CoreImage to framework Apple do przetwarzania obrazów i wideo w czasie rzeczywistym, oferujący dziesiątki wbudowanych CIFilter do korekcji kolorów, rozmycia, nakładania tekstur i wykrywania. Według Apple Documentation, CoreImage wykorzystuje GPU do wydajnego przetwarzania pikseli na urządzeniach iOS. Framework obsługuje CIImage jako niezmienny obiekt obrazu oraz łańcuchy filtrów do komponowania efektów bez utraty jakości.
Najważniejsze
CoreImage to framework Apple do przetwarzania obrazów rastrowych i wideo, po raz pierwszy wprowadzony w macOS 10.4 Tiger i przeniesiony na iOS 5.0. W przeciwieństwie do Core Graphics czy UIKit, CoreImage działa na poziomie shaderów pikselowych, wykorzystując GPU do obliczeń równoległych. Pozwala to na stosowanie złożonych efektów — rozmycia, korekcji kolorów, morphingu — do obrazów o rozdzielczości megapikselowej w milisekundach.
Architektura CoreImage opiera się na koncepcji leniwych obliczeń (lazy evaluation): CIFilter nie wykonuje przetwarzania aż do momentu renderowania w CIContext. Programista buduje łańcuch z kilku CIFilter, łącząc wyjście jednego filtru z wejściem drugiego, a dopiero wywołanie render uruchamia pełny potok GPU. Minimalizuje to liczbę przebiegów przez kartę graficzną i zachowuje wydajność.
CoreImage obsługuje szeroką gamę kolorów (P3, sRGB, liniowy sRGB), obrazy HDR oraz pracę z 16-bitowymi i 32-bitowymi formatami pikseli. Na urządzeniach z Neural Engine CoreImage może łączyć shadery GPU z Core ML do inteligentnego przetwarzania — na przykład automatycznej korekcji kolorów opartej na uczeniu maszynowym, zaimplementowanej w aplikacji Zdjęcia w iOS 17.
Trzy główne klasy stanowią rdzeń CoreImage: CIImage (dane), CIFilter (operacja) i CIContext (środowisko wykonawcze). Każda klasa odpowiada za swoją fazę potoku i nie miesza odpowiedzialności.
CIImage to lekki obiekt, który opisuje obraz, ale nie zawiera bezpośrednio danych pikselowych. Może być utworzony z UIImage, CGImage, tekstury Metal, tekstury GL lub pliku na dysku. CIImage jest niezmienny — każde zastosowanie filtru tworzy nowy CIImage bez modyfikacji oryginału. Pozwala to na budowanie łańcuchów transformacji bez kopiowania danych między krokami.
Ważna cecha: CIImage nie jest powiązany z rozdzielczością ekranu ani przestrzenią kolorów aż do momentu renderowania. Ten sam CIImage można wyrenderować do UIImage dla ekranu i do pliku TIFF do druku z różnymi parametrami — CoreImage automatycznie dostosowuje przetwarzanie do docelowego kontekstu.
CIFilter to główna klasa do stosowania efektów. Każdy CIFilter stanowi program shaderowy z parametrami wejściowymi (inputImage, inputIntensity, inputRadius itd.) i jednym obrazem wyjściowym. Apple dostarcza ponad 200 wbudowanych CIFilter, pogrupowanych w kategorie: CICategoryColorEffect (korekcja kolorów), CICategoryBlur (rozmycie), CICategoryStylize (stylizacja), CICategoryGeometryAdjust (transformacje geometryczne).
Aby utworzyć niestandardowy CIFilter, programista pisze shader Metal (CIKernel) — shader fragmentów w języku Metal Shading Language, który przetwarza każdy piksel niezależnie. Po skompilowaniu shader jest rejestrowany jako podklasa CIFilter i może być używany w łańcuchach na równi z wbudowanymi filtrami Apple.
| Kategoria | Przykład filtru | Przeznaczenie |
|---|---|---|
| ColorEffect | CIColorControls | Jasność, kontrast, nasycenie |
| Blur | CIGaussianBlur | Rozmycie Gaussa z regulowanym promieniem |
| Stylize | CIPixellate | Pikselizacja obrazu z zadaną skalą |
| GeometryAdjust | CIAffineTransform | Obrót, skala, przesunięcie poprzez macierz affine |
| Composite | CISourceOverCompositing | Nakładanie obrazów z kanałem alfa |
CIContext to ciężki obiekt, który zarządza alokacją zasobów GPU, kompilacją shaderów i buforowaniem. Utworzenie CIContext to kosztowna operacja, dlatego Apple zaleca tworzenie go raz na cały cykl życia aplikacji i wielokrotne używanie. Kontekst jest powiązany z konkretnym GPU (Metal, OpenGL) lub CPU i określa przestrzeń kolorów obrazu wyjściowego.
Biblioteka CIFilter stale się rozszerza: iOS 17 dodał nowe filtry do przetwarzania HDR i uczenia maszynowego. Wszystkie wbudowane filtry są udokumentowane w Apple Developer Documentation, można je przeszukiwać według kategorii lub nazw. Do wykrywania dostępnych filtrów na urządzeniu użyj CIFilter.filterNames(inCategory:).
Główna możliwość CoreImage — kompozycja wielu CIFilter w łańcuch. Wyjście jednego filtru jest podawane na wejście następnego poprzez parametr inputImage. CoreImage optymalizuje łańcuch na etapie renderowania: sąsiednie filtry działające w tej samej przestrzeni kolorów są łączone w jeden przebieg GPU (kernel fusion). Daje to wzrost wydajności bez ingerencji programisty.
Aby stworzyć własny efekt, programista pisze funkcję Metal z adnotacją [[kernel]]. Funkcja przyjmuje współrzędne piksela i zwraca kolor. CoreImage przekazuje shader na GPU, gdzie jest wykonywany równolegle dla wszystkich pikseli obrazu. Niestandardowe filtry są szczególnie przydatne do unikalnych efektów wizualnych: sepii z nieliniową krzywą, rozmycia dyspersyjnego lub imitacji ziarna filmowego.
#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 automatycznie zarządza pamięcią podręczną wyników pośrednich. Jeśli ten sam łańcuch filtrów jest stosowany do różnych obrazów, CoreImage może ponownie wykorzystać skompilowane shadery. Aby uzyskać maksymalną wydajność, unikaj tworzenia CIContext dla każdej klatki — używaj jednego kontekstu i ponownie ustawiaj parametry wejściowe filtru.
CIDetector — podsystem CoreImage do wykrywania obiektów semantycznych na obrazie bez użycia Vision lub Core ML. CIDetector obsługuje cztery typy detekcji: twarzy (CIDetectorTypeFace), tekstu (CIDetectorTypeText), kodów QR (CIDetectorTypeQRCode) i prostokątów (CIDetectorTypeRectangle). Detektor działa na CPU z optymalizacją dla instrukcji NEON, co zapewnia stabilną prędkość na urządzeniach bez wydajnego GPU.
Detektor twarzy CIDetectorTypeFace zwraca tablicę CIFaceFeature ze współrzędnymi granic twarzy, położeniem oczu i ust. Od iOS 12 CIDetector określa również uśmiech (hasSmile) oraz położenie lewego/prawego oka (leftEyeClosed, rightEyeClosed). Dokładność detekcji jest wystarczająca dla większości aplikacji AR i foto, ale do krytycznych scenariuszy Apple zaleca Vision.framework.
CIDetectorTypeRectangle znajduje prostokątne obszary na obrazie — dokumenty, wizytówki, ekrany urządzeń. Detektor zwraca CIRectangleFeature z czterema punktami tworzącymi kontur prostokąta. Według WWDC 2024, detektor prostokątów wykorzystuje tę samą architekturę sieci neuronowej co Vision, ale z mniejszym zużyciem pamięci. Czyni to go preferowanym do przetwarzania strumienia klatek w czasie rzeczywistym, na przykład w aplikacjach skanera dokumentów.
Praktyczne przykłady pomogą utrwalić zrozumienie CoreImage. Rozważmy dwa typowe scenariusze: zastosowanie filtru kolorów do zdjęcia oraz detekcję twarzy z rysowaniem ramki.
Podstawowy przykład filtru CISepiaTone, który przekształca kolorowy obraz w tony sepii. Filtr przyjmuje parametr inputIntensity od 0 (oryginał) do 1 (maksymalny efekt). Zwróć uwagę na leniwą ocenę: CIImage zwracany przez filter.outputImage nie zawiera pikseli — renderowanie następuje dopiero przy wywołaniu 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!)
Poniższy przykład używa CIDetector do wyszukiwania twarzy na obrazie i rysowania prostokąta wokół każdej znalezionej twarzy. CIFaceFeature zawiera współrzędne w systemie obrazu (początek w lewym dolnym rogu), dlatego przy rysowaniu na UIKit wymagana jest transformacja współrzędnych przez affine transform.
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("Osoba się uśmiecha")
}
}
Ostatni przykład demonstruje łańcuch z trzech filtrów: korekcja kolorów, winietowanie i nakładanie tekstury. Zwróć uwagę, że outputImage pierwszego filtru jest przekazywany jako inputImage drugiego — bez pośredniego renderowania. Przy wywołaniu createCGImage CoreImage łączy wszystkie trzy operacje w jeden przebieg 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)
Często zadawane pytania
CoreImage działa na GPU i jest zoptymalizowany do operacji pikselowych (filtry, korekcja kolorów), podczas gdy Core Graphics to biblioteka CPU do rysowania wektorowego i kontekstów 2D. CoreImage jest szybszy do masowego przetwarzania obrazów, Core Graphics dokładniejszy do stopniowego rysowania interfejsu.
Tak — CoreImage obsługuje przetwarzanie poszczególnych klatek wideo przez AVPlayerItemVideoOutput lub AVCaptureOutput. Do przetwarzania strumieniowego użyj AVVideoComposition with CIFilter, co pozwala stosować efekty bez kopiowania klatek między CPU a GPU.
CoreImage domyślnie działa w roboczej przestrzeni kolorów sRGB (kCGColorSpaceSRGB). Przy tworzeniu CIContext można określić alternatywną przestrzeń — extended linear sRGB dla HDR lub Display P3 dla wyświetlaczy z szeroką gamą.
Nie ma ograniczenia liczby filtrów w łańcuchu, ale każde 5–7 kolejnych filtrów tworzy dodatkowy przebieg GPU. Dla więcej niż 10 filtrów zaleca się podzielenie łańcucha na grupy i renderowanie wyników pośrednich, aby uniknąć przekroczenia limitu rejestrów shadera.
Tak — CIDetector działa na CPU z wykorzystaniem instrukcji NEON na wszystkich urządzeniach z iOS 5.0 i nowszym. Dokładność detekcji jest taka sama na wszystkich urządzeniach, ale prędkość jest wyższa na układach Apple A12+ ze względu na sprzętowe przyspieszenie sieci neuronowych.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również