Come creare un semplice filtro personalizzato per iOS utilizzando Core Image Framework?
-
29-10-2019 - |
Domanda
Voglio utilizzare nella mia app an costume filtro.Ora so che devo usare Immagine centrale framework, ma non sono sicuro che sia la strada giusta.Il framework Core Image utilizza per Mac OS e dentro iOS5.0 - Non sono sicuro che possa essere utilizzato per effetti CIFilter personalizzati.Potete aiutarmi con questo problema?Ringrazia tutti!
Soluzione
obsoleto
Non puoi creare i tuoi kernel / filtri personalizzati ancora in iOS.Vedi http://developer.apple.COM / Biblioteca / MAC / # Documentazione / Graphicsimaging / Concettuale / CoreImaging / Ci_intro / ci_intro.html , in particolare:
.Sebbene questo documento sia incluso nella libreria di riferimento, ha Non è stato aggiornato in dettaglio per iOS 5.0.Una prossima revisione sarà Dettagli le differenze nell'immagine centrale su iOS.In particolare, la chiave la differenza è che immagine principale su iOS non include la capacità di Crea filtri immagine personalizzata .
(Bolding Mine)
Altri suggerimenti
Come afferma Adam, Attualmente l'immagine principale su IOS non supporta i kernel personalizzati come il più vecchio implementazione Mac lo fa. Questo limita ciò che puoi fare con il quadro per essere una specie di combinazione di filtri esistenti.
(Aggiornamento: 2/13/2012)
Per questo motivo, ho creato un quadro open source per iOS chiamato GPuimage , che ti permette Creare filtri personalizzati da applicare a immagini e video utilizzando Shader di frammenti OpenGL ES 2.0. Descrivo di più su come questo framework opera in Il mio post sull'argomento . Fondamentalmente, è possibile fornire i tuoi shader del frammento di GLSL (OpenGL Shading Language) personalizzato per creare un filtro personalizzato e quindi eseguire quel filtro contro immagini statiche o video live. Questo framework è compatibile con tutti i dispositivi IOS che supporta OpenGL ES 2.0 e possono creare applicazioni che mirano iOS 4.0.
La risposta accettata originale è ammortizzata.Da IOS 8 è possibile creare kernel personalizzati per i filtri.Puoi trovare maggiori informazioni su questo in:
Puoi creare filtri personalizzati per iOS più facilmente rispetto a un plug-in Image Unit per MacOS X, al punto che sarebbero preferiti, anche se i plug-in Image Unit fossero supportati da iOS.Il problema è che non puoi effettivamente "impacchettarli" o raggrupparli in altro modo come una risorsa come i plug-in Image Unit;devi esporre il tuo codice sorgente agli sviluppatori che li utilizzano.Inoltre, sono utili solo agli sviluppatori;non puoi distribuirli agli utenti finali delle app grafiche iOS nello stesso modo in cui puoi distribuirli per le app grafiche MacOS X che importano filtri Core Image di terze parti.Per questo, devi incorporarli in un'estensione di fotoritocco.
Tuttavia, anche l'elaborazione delle immagini con un filtro Core Image personalizzato per iOS è più semplice che con un plug-in Image Unit.Non è prevista alcuna importazione, seguita dal compito confuso di configurare .plist, file di descrizione e quant'altro.
Un filtro Core Image personalizzato per iOS è semplicemente una classe Cocoa Touch che è una sottoclasse di CIFilter;in esso, si specificano i parametri di input (sempre almeno l'immagine), le impostazioni degli attributi personalizzati e i relativi valori predefiniti, quindi qualsiasi combinazione di filtri Immagine principale incorporati o personalizzati.Se vuoi aggiungere un kernel OpenGL alla pipeline di elaborazione delle immagini, aggiungi semplicemente un metodo CIKernel, che carica il .cikernel che scrivi in un file separato.
La bellezza di questo particolare metodo per sviluppare un filtro immagine core personalizzato per iOS è che i filtri personalizzati vengono istanziati e chiamati allo stesso modo dei filtri integrati:
CIFilter* PrewittKernel = [CIFilter filterWithName:@"PrewittKernel"];
CIImage *result = [CIFilter filterWithName:@"PrewittKernel" keysAndValues:kCIInputImageKey, self.inputImage, nil].outputImage;
Ecco un semplice esempio che utilizza OpenGL per applicare l'operatore Prewitt a un'immagine;prima, la Cocoa Touch Class (sottoclasse CIFilter), quindi il file CIKernel (contenente il codice OpenGL ES 3.0):
Il file di intestazione:
//
// PrewittKernel.h
// Photo Filter
//
// Created by James Alan Bush on 5/23/15.
//
//
#import <CoreImage/CoreImage.h>
@interface PrewittKernel : CIFilter
{
CIImage *inputImage;
}
@property (retain, nonatomic) CIImage *inputImage;
@end
Il dossier di implementazione:
//
// PrewittKernel.m
// Photo Filter
//
// Created by James Alan Bush on 5/23/15.
//
//
#import <CoreImage/CoreImage.h>
@interface PrewittKernel : CIFilter
{
CIImage *inputImage;
}
@property (retain, nonatomic) CIImage *inputImage;
@end
@implementation PrewittKernel
@synthesize inputImage;
- (CIKernel *)prewittKernel
{
static CIKernel *kernelPrewitt = nil;
NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(@"PrewittKernel")];
NSStringEncoding encoding = NSUTF8StringEncoding;
NSError *error = nil;
NSString *code = [NSString stringWithContentsOfFile:[bundle pathForResource:@"PrewittKernel" ofType:@"cikernel"] encoding:encoding error:&error];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
kernelPrewitt = [CIKernel kernelWithString:code];
});
return kernelPrewitt;
}
- (CIImage *)outputImage
{
CIImage *result = self.inputImage;
return [[self prewittKernel] applyWithExtent:result.extent roiCallback:^CGRect(int index, CGRect rect) {
return CGRectMake(0, 0, CGRectGetWidth(result.extent), CGRectGetHeight(result.extent));
} arguments:@[result]];
}
@end
Il CIKernel (OpenGL ES 3.0):
/* PrewittKernel.cikernel */
kernel vec4 prewittKernel(sampler image)
{
vec2 xy = destCoord();
vec4 bottomLeftIntensity = sample(image, samplerTransform(image, xy + vec2(-1, -1)));
vec4 topRightIntensity = sample(image, samplerTransform(image, xy + vec2(+1, +1)));
vec4 topLeftIntensity = sample(image, samplerTransform(image, xy + vec2(+1, -1)));
vec4 bottomRightIntensity = sample(image, samplerTransform(image, xy + vec2(-1, +1)));
vec4 leftIntensity = sample(image, samplerTransform(image, xy + vec2(-1, 0)));
vec4 rightIntensity = sample(image, samplerTransform(image, xy + vec2(+1, 0)));
vec4 bottomIntensity = sample(image, samplerTransform(image, xy + vec2(0, -1)));
vec4 topIntensity = sample(image, samplerTransform(image, xy + vec2(0, +1)));
vec4 h = vec4(-topLeftIntensity - topIntensity - topRightIntensity + bottomLeftIntensity + bottomIntensity + bottomRightIntensity);
vec4 v = vec4(-bottomLeftIntensity - leftIntensity - topLeftIntensity + bottomRightIntensity + rightIntensity + topRightIntensity);
float h_max = max(h.r, max(h.g, h.b));
float v_max = max(v.r, max(v.g, v.b));
float mag = length(vec2(h_max, v_max)) * 1.0;
return vec4(vec3(mag), 1.0);
}
Ecco un altro filtro che genera una maschera di contrasto sottraendo (o, piuttosto, differenziando) un'immagine sfocata gaussiana dall'originale utilizzando i filtri Core Image integrati: nessun codice kernel Core Image (OpenGL);mostra come specificare e utilizzare un attributo personalizzato, ovvero il raggio della sfocatura gaussiana:
Il file di intestazione:
//
// GaussianKernel.h
// Chroma
//
// Created by James Alan Bush on 7/12/15.
// Copyright © 2015 James Alan Bush. All rights reserved.
//
#import <CoreImage/CoreImage.h>
@interface GaussianKernel : CIFilter
{
CIImage *inputImage;
NSNumber *inputRadius;
}
@property (retain, nonatomic) CIImage *inputImage;
@property (retain, nonatomic) NSNumber *inputRadius;
@end
Il dossier di implementazione:
//
// GaussianKernel.m
// Chroma
//
// Created by James Alan Bush on 7/12/15.
// Copyright © 2015 James Alan Bush. All rights reserved.
//
#import "GaussianKernel.h"
@implementation GaussianKernel
@synthesize inputImage;
@synthesize inputRadius;
+ (NSDictionary *)customAttributes
{
return @{
@"inputRadius" :
@{
kCIAttributeMin : @3.0,
kCIAttributeMax : @15.0,
kCIAttributeDefault : @7.5,
kCIAttributeType : kCIAttributeTypeScalar
}
};
}
- (void)setDefaults
{
self.inputRadius = @7.5;
}
- (CIImage *)outputImage
{
CIImage *result = self.inputImage;
CGRect rect = [[GlobalCIImage sharedSingleton].ciImage extent];
rect.origin = CGPointZero;
CGRect cropRectLeft = CGRectMake(0, 0, rect.size.width, rect.size.height);
CIVector *cropRect = [CIVector vectorWithX:rect.origin.x Y:rect.origin.y Z:rect.size.width W:rect.size.height];
result = [[CIFilter filterWithName:@"CIGaussianBlur" keysAndValues:kCIInputImageKey, result, @"inputRadius", [NSNumber numberWithFloat:inputRadius.floatValue], nil].outputImage imageByCroppingToRect:cropRectLeft];
result = [CIFilter filterWithName:@"CICrop" keysAndValues:@"inputImage", result, @"inputRectangle", cropRect, nil].outputImage;
result = [CIFilter filterWithName:@"CIDifferenceBlendMode" keysAndValues:kCIInputImageKey, result, kCIInputBackgroundImageKey, result, nil].outputImage;
return result;
}
@end