Ho una UIImage e voglio spostare la sua saturazione di circa il 10%. Ci sono metodi o funzioni standard che possono essere utilizzati per questo?Come posso modificare la saturazione di un UIImmagine?
risposta
Niente di così semplice. La soluzione più semplice è probabilmente quella di creare un CGContext in memoria con un formato pixel noto, disegnare l'immagine in quel contesto, quindi leggere/modificare i pixel nel buffer di formato noto.
Non credo che CG supporti uno spazio colore con un canale di saturazione separato, quindi dovrai convertire da RGB a HSV o HSL o eseguire i calcoli direttamente nello spazio RGB.
Un modo per fare il calcolo direttamente in RGB potrebbe essere qualcosa di simile:
average = (R + G + B)/3;
red_delta = (R - average) * 11/10;
green_delta = (G - average) * 11/10;
blue_delta = (B - average) * 11/10;
R = average + red_delta;
G = average + green_delta;
B = average + blue_delta;
// clip R,G,B to be in 0-255 range
Ciò sposterà i canali che sono lontano dalla media circa il 10% più lontano. Questo è quasi come aumentare la saturazione, anche se darà cambiamenti di tonalità per alcuni colori.
Iniziando con una vista basata su Template applicazione, creare una nuova sottoclasse di UIView in questo modo:
// header file
@interface DesatView : UIView {
UIImage *image;
float saturation;
}
@property (nonatomic, retain) UIImage *image;
@property (nonatomic) float desaturation;
@end
// implementation file
#import "DesatView.h"
@implementation DesatView
@synthesize image, desaturation;
-(void)setSaturation:(float)sat;
{
saturation = sat;
[self setNeedsDisplay];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor]; // else background is black
desaturation = 0.0; // default is no effect
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0, self.bounds.size.height); // flip image right side up
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, rect, self.image.CGImage);
CGContextSetBlendMode(context, kCGBlendModeSaturation);
CGContextClipToMask(context, self.bounds, image.CGImage); // restricts drawing to within alpha channel
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, desaturation);
CGContextFillRect(context, rect);
CGContextRestoreGState(context); // restore state to reset blend mode
}
@end
Ora, nel metodo viewDidLoad del controller della vista, mettere la visualizzazione sullo schermo e impostare è la saturazione in questo modo:
- (void)viewDidLoad {
[super viewDidLoad];
DesatView *dv = [[DesatView alloc] initWithFrame:CGRectZero];
dv.image = [UIImage imageNamed:@"someImage.png"];
dv.frame = CGRectMake(0, 0, dv.image.size.width, dv.image.size.height);
dv.center = CGPointMake(160, 240); // put it mid-screen
dv.desaturation = 0.2; // desaturate by 20%,
[self.view addSubview:dv]; // put it on screen
}
modificare la saturazione in questo modo:
dv.saturation = 0.8; // desaturate by 80%
Ob vivamente se vuoi usarlo al di fuori di un singolo metodo, dovresti fare dv un ivar del controller della vista. Spero che questo ti aiuti.
Ecco una implementazione dell'attacco di Bessey (inserire questo codice in una categoria UIImage). Non è veloce e sposta decisamente i colori, ma funziona in un certo senso.
+ (CGFloat) clamp:(CGFloat)pixel
{
if(pixel > 255) return 255;
else if(pixel < 0) return 0;
return pixel;
}
- (UIImage*) saturation:(CGFloat)s
{
CGImageRef inImage = self.CGImage;
CFDataRef ref = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
UInt8 * buf = (UInt8 *) CFDataGetBytePtr(ref);
int length = CFDataGetLength(ref);
for(int i=0; i<length; i+=4)
{
int r = buf[i];
int g = buf[i+1];
int b = buf[i+2];
CGFloat avg = (r + g + b)/3.0;
buf[i] = [UIImage clamp:(r - avg) * s + avg];
buf[i+1] = [UIImage clamp:(g - avg) * s + avg];
buf[i+2] = [UIImage clamp:(b - avg) * s + avg];
}
CGContextRef ctx = CGBitmapContextCreate(buf,
CGImageGetWidth(inImage),
CGImageGetHeight(inImage),
CGImageGetBitsPerComponent(inImage),
CGImageGetBytesPerRow(inImage),
CGImageGetColorSpace(inImage),
CGImageGetAlphaInfo(inImage));
CGImageRef img = CGBitmapContextCreateImage(ctx);
CFRelease(ref);
CGContextRelease(ctx);
return [UIImage imageWithCGImage:img];
}
Qualcuno ha qualche idea su come migliorare questo senza eseguire una conversione HSV completa? O meglio ancora, una vera implementazione per:
- (UIImage*) imageWithHueOffset:(CGFloat)h saturation:(CGFloat)s value:(CGFloat)v
C'è un filtro CoreImage per questo. CIColorControls
Basta impostare inputSaturation
a < 1.0 per desaturare o> 1,0 per aumentare la saturazione ...
es. Ecco un metodo che ho aggiunto in una categoria su UIImage
per desaturare un'immagine.
-(UIImage*) imageDesaturated {
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *ciimage = [CIImage imageWithCGImage:self.CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"];
[filter setValue:ciimage forKey:kCIInputImageKey];
[filter setValue:@0.0f forKey:kCIInputSaturationKey];
CIImage *result = [filter valueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result fromRect:[result extent]];
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return image;
}
+1. Penso che questo potenzialmente perde il 'cgImage', anche se l'inserimento di' CFAutorelease (cgImage); 'prima che il' return' dovrebbe risolvere il problema. Puoi anche usare 'kCIInputImageKey' e' kCIInputSaturationKey' invece di '@" inputImage "' e '@" inputSaturation "', e '@ 0.0f' invece di' [NSNumber numberWithFloat: 0.0f] '. – Isaac
Grazie a @Isaac, hai aggiornato con i tuoi suggerimenti. –
Mike, ti suggerisco di usare 'UIImage * image = [UIImage imageWithCGImage: cgImage scale: self.scale orientation: self.imageOrientation];' poiché garantisce che la scala e l'orientamento siano mantenuti dall'originale, il che è particolarmente importante quando si ha a che fare con dispositivi retina. – devios1
Ho appena testato metodo Mike Pollard s' e che sia corretto.
Ecco la rapida 3 versione
let ciimage = CIImage.init(cgImage: self.givenImage.cgImage)
let filter = CIFilter.init(name: "CIColorControls")
filter?.setValue(ciimage, forKey: kCIInputImageKey)
filter?.setValue(0.0, forKey: kCIInputSaturationKey)
let result = filter?.value(forKey: kCIOutputImageKey) as! CIImage
let cgimage = CIContext.init(options: nil).createCGImage(result, from: result.extent)
let image = UIImage.init(cgImage: cgimage!)
- 1. Come posso modificare tonalità, luminosità e saturazione di UIColor?
- 2. Come modificare i valori di saturazione con opencv?
- 3. Come posso modificare la priorità di un messaggio in MSMQ?
- 4. Come posso modificare la posizione di un progetto in Eclipse?
- 5. Come posso modificare la risoluzione di un raster utilizzando GDAL?
- 6. Come posso modificare la codifica di un file con vim?
- 7. Compilatore C2 saturazione CPU all'avvio
- 8. come impostare il contrasto e la saturazione usando fabric.js
- 9. MENO: tonalità, saturazione e leggerezza - come usare?
- 10. Come posso modificare la memoria casuale?
- 11. UIImmagine imageWithXAssets
- 12. Come posso modificare textColorPrimary in un tema?
- 13. Come posso modificare EditText?
- 14. Ruota UIImmagine?
- 15. Sovrapposizione di una UIImmagine con un colore?
- 16. Stiramento di un UIImmagine preservando gli angoli
- 17. JQuery cambia tonalità, saturazione, gamma di <img>?
- 18. Come posso modificare un file .jar?
- 19. Come posso modificare PYTHONPATH su un Mac?
- 20. Posso modificare un tema di Google Chrome?
- 21. Come posso modificare l'altezza di un EditText e un pulsante?
- 22. Come posso modificare la direzione di scorrimento in UICollectionView?
- 23. Posso modificare un parametro di distribuzione?
- 24. come posso modificare la dpi di un'immagine con l'estensione imagick
- 25. Come posso modificare la forma di una variabile in TensorFlow?
- 26. UIImmagine scaling/interpolazione
- 27. Posso modificare un va_list prima di passarlo?
- 28. UIImmagine: riempire lo sfondo
- 29. Come posso modificare un messaggio di commit errato con TortoiseGit?
- 30. iPhone: Sfocatura UIImmagine
Perché non basta chiamare [setNeedsDisplay auto] nella setter per desaturazione? –
Il mio cervello ha evitato di scavalcare il setter sintetizzato per qualche motivo sconosciuto ma hai ragione. Cambierò la risposta – willc2
Quindi questo diminuisce la saturazione, come si _increase_ saturazione? – Shizam