頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


面積平均法で画像を縮小してみる

面積平均法って方法で画像の縮小をしてみたってお話だよ。

最近やっている日本語OCR関連なんだけど、画像を縮小したくなったんだ。
処理の手順としてはカメラから画像を取得するでしょ。その画像内から文字らしき部分、それも一文字分の画像エリアを得るでしょ。処理の都合この一文字分の画像は正方形なんだけど、これを縮小したいんだ。

画像の縮小といってもUIImageやUIImageViewなんかは登場しなくて、輝度データが配列に入ってる状態。
一文字分カットした画像のサイズは任意(正方形)、縮小後のサイズは16x16pxとするね。

アルゴリズムを調べるとこういうのがあったんだよ。
陶見の窓 画像リサイズ「面積平均法」
へえ。面積平均法だってさ、初めて聞いたよ。リンク先の解説が図解入りで理解しやすいのでここでは詳細は書かなくてもいいね。
ところがいざObjective-Cで実装しようとしたら案外面倒でさ。イライラしてチョコを無駄に消費しちゃったよ。こういうのをサクっとコード化できるようになりたいよね。

つたないコードで恥ずかしいけどコードを以下に書いとくよ。恥ずかしいと言えばこの前近所の歯医者さんに子供を連れて行ったら知り合いの美人ママさんが助手?歯科技工士?かなにか知らないけどそこで働いていたんだよ。連れて行く前は、今回は息子だけど今度は自分が診てもらおうかな、と思っていたんだけど、知り合いに口の中を見せるのって恥ずかしいよね。そりゃキレイな口内ならいいけどさ、虫歯の治療痕がいっぱいだし正直裸よりも見られるのが恥ずかしい気分だよ。あれ、なんの話だっけ?そうそうコードね。

//float squArray[length*length];//ここに輝度のデータが入ってる
{
    //まず横方向から縮小する(length→16px)
    float red1Array[length*16];//横方向を縮小した結果を入れる
    float numeratorArray[16];//numerator=分子
    float denominatorArray[16];//denominator=分母
    unsigned int ite1, ite2;
    float aa1,aa2 , cc;//高速化のための定数
    float rate = 16.f/length;
    float theBr;
    for (j=0;j < length;j++) {
        //リセット
        for (i=0;i < 16;i++) {
            numeratorArray[i] = 0.f;
            denominatorArray[i]=0.f;
        }
        
        for (i=0;i < length;i++) {
            theBr = squArray[j*length+i];
            aa1 = rate*i;
            aa2 = rate*(i+1);
            ite1 = floor(aa1);
            ite2 = floor(aa2);
            if (ite1 == ite2) {
                numeratorArray[ite1]+= theBr*rate;
                denominatorArray[ite1]+= rate;
            } else {
                cc = ite2-aa1;
                numeratorArray[ite1]+= theBr * cc;
                denominatorArray[ite1]+= cc;
                if (ite2 != 16) {
                    cc = aa2-ite2;
                    numeratorArray[ite2]+= theBr * cc;
                    denominatorArray[ite2]+= cc;
                }
            }
        }
        //平均値を出す
        for (i=0;i < 16;i++) {
            red1Array[j*16+i] = numeratorArray[i]/denominatorArray[i];
        }
    }
    
    
    //次は縦方向の縮小
    for (j=0;j < 16;j++) {
        
        //リセット
        for (i=0;i < 16;i++) {
            numeratorArray[i] = 0.f;
            denominatorArray[i]=0.f;
        }
        
        for (i=0;i < length;i++) {
            theBr = red1Array[i*16+j];
            aa1 = rate*i;
            aa2 = rate*(i+1);
            ite1 = floor(aa1);
            ite2 = floor(aa2);
            if (ite1 == ite2) {
                numeratorArray[ite1]+= theBr*rate;
                denominatorArray[ite1]+= rate;
            } else {
                cc = ite2-aa1;
                numeratorArray[ite1]+= theBr * cc;
                denominatorArray[ite1]+= cc;
                if (ite2 != 16) {
                    cc = aa2-ite2;
                    numeratorArray[ite2]+= theBr * cc;
                    denominatorArray[ite2]+= cc;
                }
            }
        }
        //平均値を出す
        for (i=0;i < 16;i++) {
            characterArray[i*16+j] = numeratorArray[i]/denominatorArray[i];
        }
    }
}
あまりObjective-Cに見えないねえ。実のところ今回の日本語OCRアプリだと画像データを直接扱ったりするからどうしてもこんな感じになっちゃうんだ。
画像の数値データをNSArrayに入れようとしてもNSNumberかまさないとだめだし、そういうのすると処理に時間がかかるからねえ。

面積平均法で縮小

↑上から、カメラで撮影した画像、一文字を切り出した画像、横方向を縮小した画像、縦方向を縮小した画像だよ。
上のリンク先にあるように縦方向、横方向と別々にやっても可なので、まずは大きい正方形の画像の横方向を縮小して縦長の画像にして、次に縦方向を縮小して正方形にって具合で二段階でやってみたんだ。

その結果なんだけど、46x46→16x16ピクセルに縮小するのにiPhone 4S実機で0.7msec程度かかってたよ。
うーん、もうちょっと速くならないかな、と思っていっぺんに処理するのもやってみたんだよ。一度にやるんだからもっと速くなるんじゃないかな、と思って修正したんだけどさ、、、
約0.7msecだったのが0.65msecくらいかな。少しは速くなったみたいだけど、なにかと計算が複雑になるからか劇的には変わらなかったよ、、、vDSP使ってみてもこの程度の個数じゃ影響なかったね。

とりあえず一度にやる方のコードは下のような感じ、、、と思ったけどやっぱりめんどくさいからやめとこう。それよりも歯医者どうしたもんかねえ。

<< 8月の節電結果  TopPage  自作クラスに別ファイルでカテゴリ >>

コメント


管理者にだけ表示を許可する
 

トラックバック

トラックバックURL
http://ringsbell.blog117.fc2.com/tb.php/645-ef895de8




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad