CoreImageは、色補正、ぼかし、テクスチャオーバーレイ、検出のための数十の組み込みCIFilterを提供する、Appleのリアルタイム画像・ビデオ処理フレームワークです。Appleドキュメントによると、CoreImageはiOSデバイス上で高性能なピクセル処理のためにGPUを使用します。このフレームワークは、不変の画像オブジェクトとしてのCIImageと、品質を損なうことなくエフェクトを構成するフィルタチェーンをサポートしています。
重要なポイント
CoreImageは、macOS 10.4 Tigerで初めて導入され、iOS 5.0に移植された、Appleのラスター画像・ビデオ処理フレームワークです。Core GraphicsやUIKitとは異なり、CoreImageはピクセルシェーダーレベルで動作し、並列計算にGPUを使用します。これにより、ぼかし、色補正、モーフィングなどの複雑なエフェクトを、メガピクセル解像度の画像にミリ秒単位で適用できます。
CoreImageのアーキテクチャは遅延評価の概念に基づいています。CIFilterはCIContextでレンダリングされるまで処理を実行しません。開発者は複数のCIFilterのチェーンを構築し、あるフィルタの出力を別のフィルタの入力に接続し、render呼び出しのみが完全なGPUパイプラインを起動します。これにより、グラフィックスカードを通過するパス数が最小限に抑えられ、パフォーマンスが維持されます。
CoreImageは広色域(P3、sRGB、リニアsRGB)、HDR画像、16ビットおよび32ビットのピクセルフォーマットでの作業をサポートしています。Neural Engine搭載デバイスでは、CoreImageはGPUシェーダーとCore MLを組み合わせてインテリジェント処理を行うことができます。例えば、iOS 17の写真アプリで実装されている機械学習ベースの自動色補正などです。
3つの主要クラスがCoreImageの中核を形成しています。CIImage(データ)、CIFilter(操作)、CIContext(実行環境)です。各クラスはパイプラインの独自のフェーズを担当し、責任を混在させません。
CIImageは、画像を記述する軽量オブジェクトですが、ピクセルデータを直接含みません。UIImage、CGImage、Metalテクスチャ、GLテクスチャ、またはディスク上のファイルから作成できます。CIImageは不変であり、フィルタを適用すると元の画像を変更せずに新しいCIImageが作成されます。これにより、ステップ間でデータをコピーすることなく変換チェーンを構築できます。
重要な特徴として、CIImageはレンダリングまで画面解像度や色空間に縛られません。同じCIImageを、画面用のUIImageと、異なるパラメータでの印刷用のTIFFファイルにレンダリングできます。CoreImageは自動的に処理をターゲットコンテキストに適応させます。
CIFilterはエフェクトを適用するためのメインクラスです。各CIFilterは、入力パラメータ(inputImage、inputIntensity、inputRadiusなど)と1つの出力画像を持つシェーダープログラムです。Appleは200を超える組み込みCIFilterを提供しており、カテゴリ別にグループ化されています。CICategoryColorEffect(色補正)、CICategoryBlur(ぼかし)、CICategoryStylize(スタイライズ)、CICategoryGeometryAdjust(幾何変換)などです。
カスタムCIFilterを作成するには、開発者はMetalシェーダー(CIKernel)を記述します。これは各ピクセルを独立して処理するMetal Shading Languageのフラグメントシェーダーです。コンパイル後、シェーダーはCIFilterのサブクラスとして登録され、Appleの組み込みフィルタと同様にチェーン内で使用できます。
| カテゴリ | フィルタ例 | 目的 |
|---|---|---|
| ColorEffect | CIColorControls | 明るさ、コントラスト、彩度 |
| Blur | CIGaussianBlur | 調整可能な半径のガウスぼかし |
| Stylize | CIPixellate | 指定されたスケールでのピクセル化 |
| GeometryAdjust | CIAffineTransform | アフィン行列による回転、スケール、移動 |
| Composite | CISourceOverCompositing | アルファチャンネルでの画像合成 |
CIContextは、GPUリソースの割り当て、シェーダーのコンパイル、バッファリングを管理するヘビーウェイトオブジェクトです。CIContextの作成はコストのかかる操作であるため、Appleはアプリケーションのライフサイクル全体で一度作成して再利用することを推奨しています。コンテキストは特定のGPU(Metal、OpenGL)またはCPUにバインドされ、出力画像の色空間を決定します。
CIFilterライブラリは常に拡張を続けており、iOS 17ではHDR処理と機械学習のための新しいフィルタが追加されました。すべての組み込みフィルタはApple Developer Documentationに文書化されており、カテゴリや名前で検索できます。デバイスで利用可能なフィルタを見つけるには、CIFilter.filterNames(inCategory:)を使用します。
CoreImageの主な機能は、複数のCIFilterをチェーンに構成することです。あるフィルタの出力は、inputImageパラメータを介して別のフィルタの入力に供給されます。CoreImageはレンダリング段階でチェーンを最適化し、同じ色空間で動作する隣接フィルタを単一のGPUパス(カーネルフュージョン)に結合します。これにより、開発者の介入なしにパフォーマンスが向上します。
カスタムエフェクトを作成するには、開発者は[[kernel]]アノテーションを付けたMetal関数を記述します。この関数はピクセル座標を受け取り、色を返します。CoreImageはシェーダーをGPUに渡し、画像のすべてのピクセルに対して並列に実行されます。カスタムフィルタは、非線形曲線のセピア、分散ぼかし、フィルムグレインのシミュレーションなど、独自の視覚効果に特に有用です。
#include <CoreImage/CoreImage.h>
[[kernel]] float4 customFilter(sample_t s, float intensity) {
float4 result;
result.rgb = s.rgb * (1.0 - intensity) + s.r * intensity;
result.a = s.a;
return result;
}
CoreImageは中間結果のキャッシュを自動的に管理します。同じフィルタチェーンが異なる画像に適用される場合、CoreImageはコンパイル済みシェーダーを再利用できます。最大のパフォーマンスを得るには、フレームごとにCIContextを作成せず、1つのコンテキストを使用してフィルタの入力パラメータをリセットしてください。
CIDetectorは、VisionやCore MLを使用せずに画像内の意味的オブジェクトを検出するためのCoreImageサブシステムです。CIDetectorは4種類の検出をサポートしています。顔(CIDetectorTypeFace)、テキスト(CIDetectorTypeText)、QRコード(CIDetectorTypeQRCode)、長方形(CIDetectorTypeRectangle)です。検出器はNEON命令向けに最適化されたCPU上で動作し、強力なGPUを搭載していないデバイスでも安定した速度を確保します。
顔検出器CIDetectorTypeFaceは、顔の境界座標、目と口の位置を含むCIFaceFeatureの配列を返します。iOS 12以降、CIDetectorは笑顔(hasSmile)と左/右目の位置(leftEyeClosed、rightEyeClosed)も検出します。検出精度はほとんどのARおよび写真アプリケーションに十分ですが、重要なシナリオではAppleはVision.frameworkを推奨しています。
CIDetectorTypeRectangleは、画像内の長方形領域(書類、名刺、デバイス画面)を検出します。検出器は長方形の輪郭を形成する4つの点を持つCIRectangleFeatureを返します。WWDC 2024によると、長方形検出器はVisionと同じニューラルネットワークアーキテクチャを使用しますが、メモリ消費量が少なくなっています。これにより、ドキュメントスキャナーアプリなど、リアルタイムのフレームストリーム処理に適しています。
実用的な例がCoreImageの理解を深めるのに役立ちます。写真にカラーフィルタを適用する方法と、バウンディングボックスを描画する顔検出の2つの典型的なシナリオを見てみましょう。
CISepiaToneフィルタの基本的な例です。カラー画像をセピア調に変換します。フィルタはinputIntensityパラメータを0(元のまま)から1(最大効果)まで受け入れます。遅延評価に注目してください。filter.outputImageが返すCIImageにはピクセルが含まれておらず、context.createCGImageが呼び出されたときにのみレンダリングが行われます。
import CoreImage
guard let inputImage = CIImage(image: uiImage) else { return }
let filter = CIFilter(name: "CISepiaTone")
filter?.setValue(inputImage, forKey: kCIInputImageKey)
filter?.setValue(0.8, forKey: kCIInputIntensityKey)
let context = CIContext()
let outputImage = filter?.outputImage
let cgImage = context.createCGImage(outputImage!, from: inputImage.extent)
let resultImage = UIImage(cgImage: cgImage!)
次の例では、CIDetectorを使用して画像内の顔を検出し、検出された各顔の周りに長方形を描画します。CIFaceFeatureには画像座標系(原点は左下)の座標が含まれているため、UIKitで描画するにはアフィン変換による座標変換が必要です。
let detector = CIDetector(
ofType: CIDetectorTypeFace,
context: context,
options: [CIDetectorAccuracy: CIDetectorAccuracyHigh]
)
let features = detector?.features(in: inputImage) as? [CIFaceFeature]
for face in features ?? [] {
print("Face bounds: \(face.bounds)")
if face.hasSmile {
print("人物は笑っています")
}
}
最後の例は、3つのフィルタのチェーンを示しています。色補正、ビネット、テクスチャオーバーレイです。最初のフィルタのoutputImageが中間レンダリングなしで2番目のフィルタにinputImageとして渡されることに注目してください。createCGImageが呼び出されると、CoreImageは3つの操作すべてを1つのGPUパスに結合します。
let colorFilter = CIFilter(name: "CIColorControls")
colorFilter?.setValue(inputImage, forKey: kCIInputImageKey)
colorFilter?.setValues([
kCIInputBrightnessKey: 0.1,
kCIInputContrastKey: 1.2
])
let vignetteFilter = CIFilter(name: "CIVignette")
vignetteFilter?.setValue(colorFilter?.outputImage, forKey: kCIInputImageKey)
vignetteFilter?.setValue(2.0, forKey: "inputRadius")
let finalImage = vignetteFilter?.outputImage
let result = context.createCGImage(finalImage!, from: inputImage.extent)
よくある質問
CoreImageはGPU上で動作し、ピクセル操作(フィルタ、色補正)に最適化されています。一方、Core Graphicsはベクター描画と2DコンテキストのためのCPUライブラリです。CoreImageはバッチ画像処理に優れ、Core Graphicsは段階的なインターフェース描画に優れています。
はい — CoreImageはAVPlayerItemVideoOutputまたはAVCaptureOutputを介した個別のビデオフレーム処理をサポートしています。ストリーミング処理には、CIFilterと共にAVVideoCompositionを使用します。これにより、CPUとGPU間でフレームをコピーすることなくエフェクトを適用できます。
CoreImageはデフォルトでsRGB作業色空間(kCGColorSpaceSRGB)で動作します。CIContextを作成する際に、代替スペースとしてHDR用の拡張リニアsRGBやワイドギャマットディスプレイ用のDisplay P3を指定できます。
チェーン内のフィルタ数に制限はありませんが、5〜7個の連続フィルタごとに追加のGPUパスが作成されます。10個を超えるフィルタの場合は、チェーンをグループに分割し、中間結果をレンダリングしてシェーダーレジスタの制限を超えないようにすることをお勧めします。
はい — CIDetectorはiOS 5.0以降のすべてのデバイスでNEON命令を使用してCPU上で動作します。検出精度はすべてのデバイスで同じですが、Apple A12+チップではハードウェア高速化されたニューラルネットワークにより速度が向上します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。