2012-01-17 7 views

Respuesta

5

Aún no puede crear sus propios kernels/filtros en iOS. Ver http://developer.apple.com/library/mac/#documentation/graphicsimaging/Conceptual/CoreImaging/ci_intro/ci_intro.html, específicamente:

Aunque este documento se incluye en la biblioteca de referencia, tiene no se ha actualizado en detalle para iOS 5.0. Una próxima revisión será detallar las diferencias en Core Image en iOS. En particular, la diferencia de clave es que Core Image en iOS no incluye la capacidad de crear filtros de imagen personalizados.

(negrita mía)

+0

en cuenta que aunque se puede No escriba sus propios núcleos, puede ser posible combinar CIFilters existentes para obtener el efecto que desee. ¿Qué efecto estás tratando de crear? – user1118321

+0

De hecho.También puede escribir sus propias funciones de filtro de imágenes completamente usted mismo, operando directamente sobre los datos. Si usa el marco Accelerate sabiamente, también obtendrá soporte de hardware significativo para esto. –

+2

iOS 8 agrega filtros CoreImage personalizados (es decir, personalizados 'CIKernel''s). –

20

Como afirma Adam, actualmente Core Image en iOS no es compatible con núcleos personalizados como el mayor aplicación Mac hace. Esto limita lo que puede hacer con el marco para ser una especie de combinación de filtros existentes.

(Actualización: 2/13/2012)

Por esta razón, he creado un marco de código abierto para iOS llamada GPUImage, que le permite crear filtros personalizados que se aplicarán a las imágenes y de vídeo usando OpenGL ES Sombreadores de fragmentos 2.0. Describo más acerca de cómo funciona este marco en my post on the topic. Básicamente, puede suministrar sus sombreadores de fragmentos de lenguaje de sombreado de OpenGL (GLSL) personalizados para crear un filtro personalizado, y luego ejecutar ese filtro contra imágenes estáticas o video en vivo. Este marco es compatible con todos los dispositivos iOS que admiten OpenGL ES 2.0 y puede crear aplicaciones que se dirigen a iOS 4.0.

Por ejemplo, se puede configurar el filtrado de vídeo en directo utilizando código como el siguiente:

GPUImageVideoCamera *videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:AVCaptureDevicePositionBack]; 
GPUImageFilter *customFilter = [[GPUImageFilter alloc] initWithFragmentShaderFromFile:@"CustomShader"]; 
GPUImageView *filteredVideoView = [[GPUImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, viewWidth, viewHeight)]; 

// Add the view somewhere so it's visible 

[videoCamera addTarget:thresholdFilter]; 
[customFilter addTarget:filteredVideoView]; 

[videoCamera startCameraCapture]; 

Como un ejemplo de un programa de sombreado fragmento personalizado que define un filtro, el siguiente se aplica un efecto de tono sepia:

varying highp vec2 textureCoordinate; 

uniform sampler2D inputImageTexture; 

void main() 
{ 
    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); 
    lowp vec4 outputColor; 
    outputColor.r = (textureColor.r * 0.393) + (textureColor.g * 0.769) + (textureColor.b * 0.189); 
    outputColor.g = (textureColor.r * 0.349) + (textureColor.g * 0.686) + (textureColor.b * 0.168);  
    outputColor.b = (textureColor.r * 0.272) + (textureColor.g * 0.534) + (textureColor.b * 0.131); 

    gl_FragColor = outputColor; 
} 

El lenguaje utilizado para escribir núcleos de núcleo de imagen personalizados en la Mac es muy similar al de GLSL. De hecho, podrá hacer algunas cosas que no puede hacer en Core Image, ya que el lenguaje kernel de Core Image carece de algunas características que tiene GLSL (como la bifurcación).

+0

Gracias por su respuesta! Sí, si uso OpenGL, este es el mejor resultado para mí. Pero ahora tengo un poco de conocimiento sobre estas características en openGL –

+1

Brad, ¡eres genial! – openfrog

8

La respuesta original aceptada está depreciada. Desde iOS 8 puedes crear kernels personalizados para filtros.Puede encontrar más información sobre esto en:

+0

Gracias por las actualizaciones, esta es una vieja pregunta y creo que una nueva respuesta puede ayudar a otras personas a descubrir nuevos detalles si usan iOS 8 SDK. –

0

Puede crear filtros personalizados para iOS más fácil que un plug-in de la unidad de imagen para MacOS X, tanto que serían preferidos, incluso si los complementos de Image Unit fueran compatibles con iOS. El problema es que no puede "empaquetarlos" o agruparlos como recursos, como los complementos de Image Unit; tienes que exponer tu código fuente a los desarrolladores que los usan. Además, solo son útiles para los desarrolladores; no puede distribuirlos a los usuarios finales de las aplicaciones gráficas de iOS de la misma manera que lo hace con las aplicaciones de gráficos MacOS X que importan filtros Core Image de terceros. Para eso, debe incrustarlos en una extensión de edición de fotos.

Aún así, incluso el procesamiento de imágenes con un filtro Core Image personalizado para iOS es más fácil que con un plug-in de Image Unit. No hay importación, seguido de la tarea confusa de configurar .plist y archivos de descripción y lo que no.

Un filtro de imagen principal personalizado para iOS es simplemente una clase Cocoa Touch que es una subclase de CIFilter; en él, especifica los parámetros de entrada (siempre al menos la imagen), los ajustes de atributos personalizados y sus valores predeterminados, y luego cualquier combinación de filtros de imagen principal incorporados o personalizados. Si desea agregar un kernel OpenGL a la canalización de procesamiento de imágenes, simplemente agregue un método CIKernel, que carga el .cikernel que escribe en un archivo separado.

La belleza de este método en particular para el desarrollo de un núcleo de filtro personalizado de imagen de IOS es que los filtros personalizados se crean instancias y llamaron la misma manera que incorporados filtros:

CIFilter* PrewittKernel = [CIFilter filterWithName:@"PrewittKernel"]; 

CIImage *result = [CIFilter filterWithName:@"PrewittKernel" keysAndValues:kCIInputImageKey, self.inputImage, nil].outputImage; 

He aquí un ejemplo simple que utiliza OpenGL para aplicar el operador Prewitt a una imagen; En primer lugar, la Cocoa Touch Clase (subclasificación de CIFilter), a continuación, el archivo CIKernel (que contiene el código OpenGL ES 3.0):

El archivo de cabecera:

// 
// 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 

El archivo de implementación:

// 
// 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 

El 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); 
} 

Aquí hay otro filtro que genera un unsh arp mask al restar (o, más bien, diferenciar) una imagen borrosa gaussiana del original utilizando los filtros integrados de la imagen principal, sin código del kernel Core Image (OpenGL); que muestra cómo especificar y utilizar un atributo personalizado, es decir, el radio del desenfoque gaussiano:

El archivo de cabecera:

// 
// 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 

El archivo de implementación:

// 
// 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 
Cuestiones relacionadas