Hatena::ブログ(Diary)

Over&Out その後 このページをアンテナに追加 RSSフィード

2012-12-17

Core Image の全エフェクトを試せるサンプルコードを公開しました

Core Image のフィルタ(画像にエフェクトをかけたり、色を調整したりするもの)を一通り試せるサンプルプロジェクトをgithubに上げました。


というか、これ、1年以上前にアップしてこちらの記事に書いたのですが、ほとんど認知されることがなかったので、改めて紹介させていただきます。


こんな感じでフィルターを試せます。

(フィルタのパラメータはランダムに生成されるので、かける度に変わる場合もあります)


f:id:shu223:20111117111856p:image:left:w240

f:id:shu223:20111117111857p:image:left:w240



プロジェクト一式、こちらからダウンロードできます。

https://github.com/shu223/FilterDemo


注意点として、選んでも何も起こらないフィルターがたくさんあります

詳細は後述しますが、こちら、Apple の PocketCoreImage というサンプルコードを数行いじっただけのものなので、あんまり多種多様なフィルタに対応したつくりになってはいないのです。。

そういうフィルタはリストから除いてもよかったのですが、「どんなフィルタがあるのか?」を一覧できる意味もあるので、残してあります。


PocketCoreImageからの改変点

CIFilterは、下記のように、NSString型の名前を引数に渡してインスタンスを生成します。

CIFilter *newFilter = [CIFilter filterWithName:name];

で、ここに渡せる名前をずらずらっと列挙するために、awakeFromNibで次のようなコードで全ビルトインフィルタの名前を取得しています。

NSArray *filterNames;
filterNames = [CIFilter filterNamesInCategory:kCICategoryBuiltIn];
_availableFilters = [NSArray arrayWithArray:filterNames];


それと、PocketCoreImageでは、フィルタをかける箇所で、次のようにKVCを利用して元画像をフィルタに渡しています。

[filter setValue:_filteredImage forKey:@"inputImage"];

ここで、inputImageというアクセサを持たないフィルタもあるので、

if (![filter respondsToSelector:NSSelectorFromString(@"inputImage")]) {
    continue;
}

とチェックを入れて例外を回避しています。

(詳細はこちらの記事をご参照ください)


その他、コードの解説

もともと PocketCoreImage にあった部分なのですが、多種多様なパラメータを持つ不特定多数のフィルタに対してランダム値を設定する部分はこうなっているよ、というのを紹介させていただきます。


まず、CIFilterのattributesメソッドでパラメータ一覧を取得します。

(このあとここでは設定しないパラメータを取り除く処理が入りますが割愛)

NSDictionary *filterAttributes = [filter attributes];

NSNumber型のパラメータだけを取り出し、

for (NSString *key in editableAttributes) {
    
    NSDictionary *attributeDictionary = [editableAttributes objectForKey:key];

    if ([[attributeDictionary objectForKey:kCIAttributeClass] isEqualToString:@"NSNumber"]) {

        // 後述    
    }   
}

BOOL/Decimal/Integerそれぞれの型に応じて、ランダム値を設定しています。

(下記は、上記コードのif文の中身)

        if ([attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeBoolean)
        {
            NSInteger randomValue = (rand() % 2); 
            
            NSLog(@"Setting %i for key %@ of type BOOL", randomValue, key);
            [filter setValue:[NSNumber numberWithInteger:randomValue] forKey:key];
        }
        else if([attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeScalar ||
                [attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeDistance ||
                [attributeDictionary objectForKey:kCIAttributeType] == kCIAttributeTypeAngle)
        {
            // Get the min and max values
            float maximumValue = [[attributeDictionary valueForKey:kCIAttributeSliderMax] floatValue];
            float minimumValue = [[attributeDictionary valueForKey:kCIAttributeSliderMin] floatValue];
            
            float randomValue = randFloat(minimumValue, maximumValue);

            NSLog(@"Setting %f for key %@ of type Decimal", randomValue, key);
            [filter setValue:[NSNumber numberWithFloat:randomValue] forKey:key];
        }
        else
        {
            // Get the min and max values
            NSInteger maximumValue = [[attributeDictionary valueForKey:kCIAttributeMax] integerValue];
            NSInteger minimumValue = [[attributeDictionary valueForKey:kCIAttributeMin] integerValue];
            
            NSInteger randomValue = (rand() % (maximumValue - minimumValue)) + minimumValue;
            
            NSLog(@"Setting %i for key %@ of type Integer", randomValue, key);
            [filter setValue:[NSNumber numberWithInteger:randomValue] forKey:key];
        }

Core Image の参考書籍

iOS Core Frameworksテクニカルガイド

iOS Core Frameworksテクニカルガイド
Shawn Welch
インプレスジャパン
売り上げランキング: 242494


2012年9月と比較的最近出版されたものですが、原著の出版は2011年9月。したがって iOS5 時代のものです。『Core Image』の章があるのですが、広く浅く、という感じです。


iOS5プログラミングブック

iOS5プログラミングブック
加藤 寛人 吉田 悠一 藤川 宏之 西方 夏子 関川 雄介 高丘 知央
インプレスジャパン
売り上げランキング: 88968


Core Imageの章あり。この本は全体的に説明が詳しく、あまり他の書籍やブログにないところまで踏み込んだ情報も多いので、個人的にはこちらの方がおすすめです。


おまけ:CIFilterのフィルタ名一覧(iOS 6 版)

前回記事(2011年11月)時点では 48 個だったものが、なんと 94 個に増えていました。


CIAdditionCompositing

CIAffineClamp

CIAffineTile

CIAffineTransform

CIBarsSwipeTransition

CIBlendWithMask

CIBloom

CIBumpDistortion

CIBumpDistortionLinear

CICheckerboardGenerator

CICircleSplashDistortion

CICircularScreen

CIColorBlendMode

CIColorBurnBlendMode

CIColorControls

CIColorCube

CIColorDodgeBlendMode

CIColorInvert

CIColorMap

CIColorMatrix

CIColorMonochrome

CIColorPosterize

CIConstantColorGenerator

CICopyMachineTransition

CICrop

CIDarkenBlendMode

CIDifferenceBlendMode

CIDisintegrateWithMaskTransition

CIDissolveTransition

CIDotScreen

CIEightfoldReflectedTile

CIExclusionBlendMode

CIExposureAdjust

CIFalseColor

CIFlashTransition

CIFourfoldReflectedTile

CIFourfoldRotatedTile

CIFourfoldTranslatedTile

CIGammaAdjust

CIGaussianBlur

CIGaussianGradient

CIGlideReflectedTile

CIGloom

CIHardLightBlendMode

CIHatchedScreen

CIHighlightShadowAdjust

CIHoleDistortion

CIHueAdjust

CIHueBlendMode

CILanczosScaleTransform

CILightenBlendMode

CILightTunnel

CILinearGradient

CILineScreen

CILuminosityBlendMode

CIMaskToAlpha

CIMaximumComponent

CIMaximumCompositing

CIMinimumComponent

CIMinimumCompositing

CIModTransition

CIMultiplyBlendMode

CIMultiplyCompositing

CIOverlayBlendMode

CIPinchDistortion

CIPixellate

CIRadialGradient

CIRandomGenerator

CISaturationBlendMode

CIScreenBlendMode

CISepiaTone

CISharpenLuminance

CISixfoldReflectedTile

CISixfoldRotatedTile

CISmoothLinearGradient

CISoftLightBlendMode

CISourceAtopCompositing

CISourceInCompositing

CISourceOutCompositing

CISourceOverCompositing

CIStarShineGenerator

CIStraightenFilter

CIStripesGenerator

CISwipeTransition

CITemperatureAndTint

CIToneCurve

CITriangleKaleidoscope

CITwelvefoldReflectedTile

CITwirlDistortion

CIUnsharpMask

CIVibrance

CIVignette

CIVortexDistortion

CIWhitePointAdjust



2012-05-25

Assets Library を利用した高速フォトビューア

1年以上前にこちらの記事で Assets Library の読み込みを高速化する試行錯誤について書かせていただきましたが、そのときに作った『i走馬灯』という高速フォトビューアアプリを作り直して再リリースしました。


f:id:shu223:20120525083606p:image

i走馬灯 〜超高速フォトビューア

※無料です



再リリースの経緯

もともと iPhone 4 のカメラの解像度でも高速表示は厳しかったのですが、iPhone4S になってさらにカメラの解像度が上がり、もはや「走馬灯」といえるスピードは出せなくなっていました。(iPhone 4Sの処理速度でも)


描画をOpenGLで行うことも検討してみましたが、

ALAsset *aseet = (ALAsset *)[self.assets objectAtIndex:currentAssetIndex];
ALAssetRepresentation *representation = [asset defaultRepresentation];
UIImage *img = [UIImage imageWithCGImage:[representation fullResolutionImage]
                                   scale:[representation scale]
                             orientation:[representation orientation]];

結局この ALAssetRepresentation から fullScreenImage なり fullResolutionImage なりで CGImageRef を取り出しているところが時間かかってるっぽくて、描画を高速化してもここがボトルネックになるんではと思い断念しました。


で、

ALAsset *asset = (ALAsset *)[self.assets objectAtIndex:currentAssetIndex_];
UIImage *img = [UIImage imageWithCGImage:[asset thumbnail]];

このように『ALAsset から直接 thumbnail メソッドで CGImageRef を取り出す』方式だと非常に高速で、それを6個、12個、24個と増やしても相変わらずチョッパヤだったので、もうサムネイル表示だけでいこうってことで、「サムネイルを高速表示するアプリ」として作り直した次第です。


f:id:shu223:20120525090111p:image:w480


ちょっといい感じの写真が iPhone に入ってなくてスクリーンショットを用意しなかったのですが、上記6分割、12分割の他にも、24分割モードがあります。


無料なのでぜひお試しいただけると幸いです!



2012-05-12

逆ジオコーディングで取得した CLPlacemark の住所情報の内容

先日CLGeocoder を用いた逆ジオコーディングの記事を書きましたが、その結果得られる CLPlacemark 型の addressDictionary プロパティに入っている住所情報について、どのキーがどういう情報なのか、国ごとにどういう違いがあるのか、毎回調べるのが面倒なのでここに書いておきます。


近所で位置情報を取得し逆ジオコーディングし、addressDictionaryの内容をログ出力するとこんな感じでした。(エンコードおかしいですが気にしないでください・・・)

City = "\U938c\U5009\U5e02";
Country = "\U65e5\U672c";
CountryCode = JP;
FormattedAddressLines =     (
                             "\U3012248-0007 \U795e\U5948\U5ddd \U938c\U5009\U5e02 \U5927\U753a 2\U4e01\U76ee6\U756a13\U53f7"
                             );
Name = "\U5927\U753a 2\U4e01\U76ee6\U756a13\U53f7";
State = "\U795e\U5948\U5ddd";
Street = "\U5927\U753a 2\U4e01\U76ee6\U756a13\U53f7";
SubLocality = "\U5927\U753a";
SubThoroughfare = "6\U756a13\U53f7";
Thoroughfare = "\U5927\U753a 2\U4e01\U76ee";
ZIP = "\U3012248-0007";

ここからわかることは、

  • FormattedAddressLines には、"ZIP", "State", "City", "Street"の順に入っている
  • 日本でいうと、"State"は都道府県、"City"は市区町村にあたり、"Street"には「小町 2丁目3番1号」といったような町名地番が入る
  • "Street" は、"Thoroughfare" と "SubThoroughfare" を繋げたもので、"SubLocality" は町名(市区町村以降の地名。"Thoroughfare" にも含まれる)


ただどの国でもこれらの項目が得られるかというとそうではなく、たとえばチュニジアの緯度経度で逆ジオコーディングすると、

Country = "\U30c1\U30e5\U30cb\U30b8\U30a2";
CountryCode = TN;
FormattedAddressLines =     (
"RN 3E",
"\U30c1\U30e5\U30cb\U30b8\U30a2"
);
Name = "RN 3E";
State = "\U30b7\U30c7\U30a3\U30d6\U30b8\U30c3\U30c9";
Street = "RN 3E";
Thoroughfare = "RN 3E";

addressDictionaryにはこういう感じの結果が返ってきました。


"City" や "SubThoroughfare" 、"SubLocality" といった項目がはいっていません。データがないのか、もともと住所の構造がシンプルなのかわかりませんが、日本と同様に市区町村にあたる項目があるという前提で処理を書くとおかしなことになりそうです。



そもそもこういうのは世界共通で規格みたいなものがあるのかもしれないので、こういう場当たり的な調べ方は的外れなのかもしれません。悪しからず・・・



2012-05-06

iOS 5.0 より追加された CLGeocoder を使用して逆ジオコーディング

Appleのドキュメントによると

iOS 5.0では、MKReverseGeocoderとMKReverseGeocoderDelegateは非推奨になっているの で、新たにアプリケーションを開発する場合はCLGeocoderを使ってください。

とのことなので、逆ジオコーディングを CLGeocoder を使用してやってみたのでその手順をこちらにメモしておきます。

(上記Appleのドキュメントのコードは少しずつ変数名が間違ってたり、独自定義のクラスが引数の型に指定されていたりして、そのままでは使いづらい・・・)


で、手順といってもヘッダのインポートやオブジェクトの生成とかを除けば、

  • reverseGeocodeLocation:completionHandler: を呼ぶ

これしかありません・・・


僕の場合は下記のようにクラスメソッドを定義しました。

+ (void)reverseGeocodeLocation:(CLLocation *)location
{
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:location completionHandler:
     ^(NSArray* placemarks, NSError* error) {
         if ([placemarks count] > 0) {
             
             CLPlacemark *placemark = (CLPlacemark *)[placemarks lastObject];

             // 取得したplacemarkを格納したNSNotificationを発行
         }
     }];
}

Blocksで非同期に処理されるので、CLPlacemarkオブジェクトを取得したらNSNotificationを発行して必要なオブジェクトに通知するようにしました。


なお、reverseGeocodeLocation:completionHandler: で得られる値が NSArray 型になっていますが、CLGeocoderのクラスリファレンスによると

Contains an array of CLPlacemark objects. For most geocoding requests, this array should contain only one entry. However, forward-geocoding requests may return multiple placemark objects in situations where the specified address could not be resolved to a single location.

とあり、逆ジオコーディングのときは基本的に1つしかオブジェクトが入ってこないと思ってよさそうです。(正ジオコーディングのときはアドレス→緯度経度なので、1つとは限らないため、NSArrayになっている)



2012-04-01

クロスディゾルブで画面遷移

UIView に用意されている画面遷移用エフェクトとして、カールアップ/ダウンやフリップ(クルッとまわる)以外にも、iOS4.0以降ではクロスディゾルブ(アルファで入れ替わる)も利用できます。


2つの UIView (下記サンプルでは fromView, toView)を用意して、 transitionFromView:toView:duration:options:completion: メソッドの options 引数に UIViewAnimationOptionTransitionCrossDissolve を渡してやるだけ。

[UIView transitionFromView:fromView
                    toView:toView
                  duration:1.0
                   options:options
                completion:^(BOOL finished) {
                    // animation completed
                }];

アクのない一般的なエフェクトなので比較的使い勝手がいいと思うのですが、UIViewAnimationOptionTransitionCrossDissolve で検索してみたら意外にも日本語で触れられているページがヒットしなかったのでご紹介しました。


(参考:Appleのサンプルコード)

https://developer.apple.com/library/ios/#samplecode/ViewTransitions/Introduction/Intro.html



2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 04 | 05 | 06 |