oFで日本語テキストをタレ流しするaddon

日本語をoFでタレ流しする超地味アドオン書いてた。 ofxTrueTypeFontUC使ってます。(製作者は多分研究室の先輩)

同じクラス名のアドオンがofxaddonsにあったけどとりあえず気にしない。。

ofxTextWriter.h

#include "ofMain.h"
#include "ofxTrueTypeFontUC.h"

static const int DISAPEAR_TIME = 5;

class ofxTextWriter{
public:
    
    void setup(string fontPath, int size, float s);
    void update();
    void draw();
    
    void setString(string s, ofPoint pos, ofColor c);
    
private:
    struct stringGroup{
    
        string str;
        string drawStr;
        
        vector<int> charsizeList;
        int nChar;
        int nDrawChar;
        
        float time;
        ofPoint position;
        ofColor color;
        
    };
    
    
    ofxTrueTypeFontUC font;
    int   fontSize;
    float speed;

    
    vector<stringGroup> strings;
    
    
    vector<int> getCharsizeList(const string &input);
    int getUTF8Byte(unsigned char input);
    
};

ofxTextWriter.cpp

#include "ofxTextWriter.h"


template<typename T>
void remove(std::vector<T>& vector, unsigned int index)
{
    vector.erase(vector.begin() + index);
}


void ofxTextWriter::setup(string fontPath, int size, float s = 0.3){

    fontSize = size;
    speed    = s;
    
    font.loadFont(fontPath, fontSize);
    
}

void ofxTextWriter::update(){

    float t = ofGetElapsedTimef();
    for(int i=0;i<strings.size();i++){
        
        if(strings[i].nDrawChar < strings[i].nChar){
            
            if(t-strings[i].time > speed){
                
                strings[i].nDrawChar ++;
                int dByte = 0;
                for(int c=0;c<strings[i].nDrawChar;c++)
                    dByte += strings[i].charsizeList[c];
                strings[i].drawStr = strings[i].str.substr(0, dByte);
                
                strings[i].time = ofGetElapsedTimef();
                
            }
            
        }
        
        else{
            
            if(t - strings[i].time > DISAPEAR_TIME){
                strings[i].drawStr = strings[i].str;
                if(strings[i].color.a > 0){
                    strings[i].color.a *= cos((t -strings[i].time - DISAPEAR_TIME));
                }
                else{
                    remove(strings, i);
                }
            }
            
        }
        
    
        
    
    }
    
    
}

void ofxTextWriter::draw(){
    
    for(int i=0;i<strings.size();i++){
    
        ofSetColor(strings[i].color);
        font.drawString(strings[i].drawStr, strings[i].position.x, strings[i].position.y);
        
    }
    
    ofSetColor(255);
    ofDrawBitmapString("numStr: " +ofToString(strings.size()), 10., 10);
    ofDrawBitmapString("FPS:" + ofToString(ofGetFrameRate()), 10, 20);
    
    
}

void ofxTextWriter::setString(string s, ofPoint pos, ofColor c){

    stringGroup strGroup;
    
    strGroup.str        = s;
    strGroup.drawStr    = "";

    strGroup.charsizeList = getCharsizeList(s);
    strGroup.nChar      = strGroup.charsizeList.size();
    strGroup.nDrawChar  = 0;

    strGroup.time       = ofGetElapsedTimef();
    strGroup.position   = pos;
    strGroup.color      = c;
    
    strings.push_back(strGroup);
    
}

vector<int> ofxTextWriter::getCharsizeList(const string &input){

    vector<int> sizeList;
    
    int target = 0;
    while (target < input.size()) {
        
        int iByte = getUTF8Byte(input[target]);
        sizeList.push_back(iByte);
        target += iByte;
    
    }
    
    
    return sizeList;
    
}


int ofxTextWriter::getUTF8Byte(unsigned char input){

    int iByte;
    
    if ((input >= 0x00) && (input <= 0x7f)) {
        iByte = 1;
    } else if ((input >= 0xc2) && (input <= 0xdf)) {
        iByte = 2;
    } else if ((input >= 0xe0) && (input <= 0xef)) {
        iByte = 3;
    } else if ((input >= 0xf0) && (input <= 0xf7)) {
        iByte = 4;
    } else if ((input >= 0xf8) && (input <= 0xfb)) {
        iByte = 5;
    } else if ((input >= 0xfc) && (input <= 0xfd)) {
        iByte = 6;
    } else {
        iByte = 0;
    }
    
    return iByte;


    
}

A Neural Algorithm of Artistic Style試してみた

この論文が話題になってたので、実際に試してみました。

[1508.06576] A Neural Algorithm of Artistic Style

使用したコードはこちらです。 github.com

Torchベースですが、Torchをインストールしていれば簡単に使用することができます。 僕はqtluaのインストールができず躓いてましたが。。。anacondaをインストールしている環境だとうまくいかないっぽいので、一旦anacondaをアンインストールしてqtluaをインストールしました。

目標とするのは適当にネットから拾ってきた渋谷のこの画像。 f:id:l94q:20150902012949j:plain

実験結果はこちら。 f:id:l94q:20150902013019j:plain

500世代学習した結果ですが、学習にMacBook Pro(Mid 2014) NVIDIA GeForce GT 750M 2048 MBの環境で約3分ぐらいで完了してます。

論文をちゃんと読み込めていないのですが、中身としてはVGGを利用したシンプルな構造なのでchainer版を作ってみようかなと思います。

Variational Autoencoderでアルバムジャケットの生成

Variational Autoencoder

この論文に詳しくは記載されています。

Semi Supervised Learning with Deep Generative Models

簡単に言うと、入力の変数を潜在変数に落としてAutoencoder。

ラベルも含めた生成モデルとすることで教師データを生成することができ、半教師あり学習に応用したところ、少ない教師データでそれなりの結果がでたとのこと。

面白いのは学習したモデルに対して、任意の潜在変数を入力することでXが生成できるところ。

結果が面白いため、色んな人が紹介してくれてます。

www.slideshare.net

http://deeplearning.jp/wp-content/uploads/2014/04/dl_hacks2015-04-21-iwasawa1.pdf

アルバムジャケットの生成

VAEを使ってアルバムジャケットを学習して、潜在変数をランダムに入力することで新たなジャケットを生成する実験しています。

この方がすでにやられてることなので、新しいことでは無いです。

VAEはchainerで実装しています。

github.com

学習に使用したデータは radioheadのアルバム9枚 Atoms for peaceのアルバム1枚 の計10枚の画像。 データサイズは学習を早く進めたかったため、128*128のグレースケールに変換しています。

学習の進みはこんな感じ。

f:id:l94q:20150901074828p:plain

で、任意の潜在変数を渡して生成した例が以下の通り。

f:id:l94q:20150901074914j:plainf:id:l94q:20150901074947j:plainf:id:l94q:20150901075014j:plainf:id:l94q:20150901075415j:plainf:id:l94q:20150901075435j:plain

潜在変数の数を300にしている一方、入力データは10通りと入力が単純の割には大きい値にしてしまった感は有ります。(そのまま入力データが出力されてる?) また、学習画像が少ないので、単純に重ね合わさってる印象も強いかなと。

今回はRadioheadっぽいアルバムをつくろうと思い10枚の画像しか使いませんでしたが、入力データを増やすともっとバリエーションの多い画像になるかも。

あとカラー画像にしたほうが結果面白いと思うので、その辺も調整する。

C++でstring型の文字コードを変換する方法

C++で日本語文字を取り扱ってたら1日が終わった。。

KST32BというストロークフォントをC++から使おうとしてたら色々とハマってしまったという話です。

KST32BはJISコードの文字のストロークフォントを保持してるのだけど、C++のstring型はUTF8の文字コードを取り扱っててどうやってJISコードに変換しようという問題でした。

Windows(Visual C++)の情報は色々出てくるんだけど、Mac(というかLinux)はなかなか情報出てこなかったので苦労しました。

こちらのURLに記載されている通りiconv.hを使えばいけるとのことです。ありがとうございます。

http://bebolog.blogspot.jp/2014/11/c.html

コードはコピペだけど転載いたします。

string convert_encoding(const std::string &str, const char *fromcode, const char *tocode)
{
    char *outstr, *instr;
    iconv_t icd;
    size_t instr_len  = std::strlen(str.c_str());
    size_t outstr_len = instr_len*2;
    
    if (instr_len <= 0) return "";
    
    // allocate memory
    instr  = new char[instr_len+1];
    outstr = new char[outstr_len+1];
    strcpy(instr, str.c_str());
    icd = iconv_open(tocode, fromcode);
    if (icd == (iconv_t)-1) {
        return "Failed to open iconv (" + std::string(fromcode) + " to " + std::string(tocode) + ")";
    }
    char *src_pos = instr, *dst_pos = outstr;
    if (iconv(icd, &src_pos, &instr_len, &dst_pos, &outstr_len) == -1) {
        // return error message
        std::string errstr;
        int err = errno;
        if (err == E2BIG) {
            errstr = "There is not sufficient room at *outbuf";
        } else if (err == EILSEQ) {
            errstr = "An invalid multibyte sequence has been encountered in the input";
        } else if (err = EINVAL) {
            errstr = "An incomplete multibyte sequence has been encountered in the input";
        }
        iconv_close(icd);
        return "Failed to convert string (" + errstr + ")";
    }
    *dst_pos = '\0';
    iconv_close(icd);
    
    std::string s(outstr);
    delete[] instr;
    delete[] outstr;
    
    return s;
}

Xcodeで開発してる場合は、libiconv.dylibをフレームワークに追加した上でiconv.hをインクルードしてください。 使い方は

string conv_str = convert_encoding(str, "utf-8", "euc-jp");

みたいな感じで第2引数に元の文字コード、第3引数に変換したい文字コードを渡してあげればOKです。

実際のJISコードへの変換ですが、こんな感じでやってます。

string convertUTF8ToJIS(const string &str){
   
    string conv_str = convert_encoding(str, "utf-8", "euc-jp");
    
    vector<int> jislist;
    int c = 0;
    for(int i=0;i<conv_str.size();i++){
        
        int tmp = conv_str[i]&0x7f;
        c = c<<8;
        c += tmp;
        
    }
    
    
    stringstream ss;
    ss<<hex<<c;
    string jis = ss.str();
    
    if(jis.size() < 4){
    
        int n_zero = 4 - jis.size();
        switch (n_zero) {
            case 1:
                jis = "0" + jis;
                break;
            case 2:
                jis = "00" + jis;
                break;
            
            case 3:
                jis = "000" + jis;
                break;
                
            default:
                break;
        }
        
    }
    
    // to Upper
    transform(jis.begin(), jis.end(), jis.begin(), ::toupper);
    
    
    return jis;
    
    
}

元々KST32Bを取り扱うpythonコードがあったのでそれを参考にしています。

http://boxheadroom.com/2009/06/03/kst

これでKST32BをC++から使えるようになりました。 KST32Bのストローク解析コードも書いたけど、基本上のpythonコードのC++版です。ニッチすぎるので需要はないと思いますが、欲しければご連絡いただければと思います。

色々と雑記

色々と雑記

前回のブログ記事からだいぶ空いてしまいました。
この1年で自分の環境がかなり変わりそうなので記録をとり始めることにします。
あと、1日毎に何をしていたかをまとめるのはかなり重要だと最近痛感しています。

技術について学んだけど、後日ほとんど忘れて0からやり直し

休日に何かやった気になってるけど、実際は何も身についてない

論文を読んでもアウトプットしないから内容をちゃんと理解できていない。結局読んでないのと変わらない状態

こんな日々が続いているので自分が成長しているのを感じるためにもブログ再開します。
気負いせず適当な感じで。

内容は機械学習メインな感じですかね。

音声の類似度計算手法 ~pythonによる数値処理入門~

前回の記事につづいて、自動ラップマシーンを作っていきたいと思います。
音声の距離ですが、単純に文字としての距離と実際に発音した時に似てるという感覚は異なるかなぁと思い色々調査してみました。

音声の類似度計算にSoundexやMetaphoneなどというアルゴリズムがあるとのこと。
文字列の類似度を測る(2) 発音に着目する|Colorless Green Ideas
そんなアルゴリズムが実装されているpythonパッケージもあるとのこと。
Fuzzy 1.0 : Python Package Index

早速実装して、下記英文の中から"ryota"の発音と似た単語を表示するコードを書いてみました。

入力テキスト:

Ars Electronica Linz GmbH is an Austrian cultural, educational and scientific institute active in the field of new media art, founded in 1979. It is based at the Ars Electronica Center, which houses the Museum of the Future, in the city of Linz. Ars Electronica’s activities focus on the interlinkages between art, technology and society. It runs an annual festival, and manages a multidisciplinary media arts R&D facility known as the Futurelab. It also confers the Prix Ars Electronica awards.

結果:

at1
runs 1
and 2
art 2
focus 2

コード:

import fuzzy
import levenshtein_distance as ld
import re

def calcWordSimirality(word1, word2):
	
	nys1 = fuzzy.nysiis(word1)
	nys2 = fuzzy.nysiis(word2)

	return ld.levenshtein_distance(nys1, nys2)

def calcTextSimirality(text, word):
	
	textWithOnlyWord = re.sub(r'[^0-9a-zA-Z ]', "", text)
	textWords = textWithOnlyWord.split(" ")

	scores = {}
	for i in range(len(textWords)):
		score = calcWordSimirality(word, textWords[i])
		scores[textWords[i]] = score


	return scores


def display_distance(scores):

	for k, v in sorted(scores.items(), key=lambda x:x[1]):
		print k, v


単語間の距離ではいまいち似てるのか判断つきませんね。。
次回はテキスト間の距離を計算できるようにしてみます。Your CosmosでやっていたようにTwitterから適当に拾ってきたツイートを機械学習にかけてラップの掛け合いをできるようにすることを目標に頑張ります。

音声類似度の算出 ~pythonによる数値処理入門~

学生の時、人工知能を用いたデータマイニングの研究をしていました。
数字を眺めて、数値加工して、アルゴリズムを考えてプログラムを組んで、データを入力して出力結果を眺めるという作業をひたすらやっていました。進化計算法という手法をメインで使っていて、最近はあまり触らなくなりましたが非常に面白かったです。

数字を扱うとしたらMatlabとかRの方が扱いやすかったのかもしれませんが、c++でゴリゴリやっていました。それが今openFrameworksなどに役だっているので助かってます。

この数値処理ですが、c++でやるとなかなか難しいところがありましたので数値計算が得意なpythonでやってみようと思います。
入力は音声で、類似する音声を計算して出力するということを目標にやってみようと思います。

実はこの類似する音声の出力というのは、去年のArs Electronica2013にBrucknerのライブで真鍋さん、比嘉さん、堀井さんが似たようなことをテーマにパフォーマンスしていてすごいカッコ良かったので真似してみようと思ったわけです。
Your Cosmosという作品でした。Youtubeで検索したらリハ映像っぽいのが出てきたので貼っておこうと思います。


Performance by Daito Manabe and Satoru Higa ...

Twitter見てたら代官山UNITでこのライブをやるような感じでした。是非また行きたいところ。

とりあえず次回から実装をしていってみたいと思います。
結果できませんでしたって可能性もあるけど頑張ります。