Frage

Ich bin derzeit versucht, den Alpha-Wert eines Pixels in einem UIImageView zu erhalten. Ich habe die CGImage aus [UIImageView Bild] erhalten, und ein Byte-Array RGBA daraus erstellt. Alpha ist Premultiplied.

CGImageRef image = uiImage.CGImage;
NSUInteger width = CGImageGetWidth(image);
NSUInteger height = CGImageGetHeight(image);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
rawData = malloc(height * width * 4);
bytesPerPixel = 4;
bytesPerRow = bytesPerPixel * width;

NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(
    rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace,
    kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big
);
CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
CGContextRelease(context);

I den Array-Index für den gegebenen alpha-Kanal, die Koordinaten vom UIImageView verwenden.

dann berechnen,
int byteIndex = (bytesPerRow * uiViewPoint.y) + uiViewPoint.x * bytesPerPixel;
unsigned char alpha = rawData[byteIndex + 3];

Allerdings bekomme ich nicht die Werte, die ich erwarte. Für einen völlig schwarzen transparenten Bereich des Bildes I erhalten Werte ungleich Null für den alpha-Kanal. Muss ich die Koordinaten zwischen UIKit und Core Graphics übersetzen - das heißt: die y-Achse invertiert? Oder habe ich premultiplied Alpha-Werte falsch verstanden?

Update:

@Nikolai Ruhe Vorschlag war der Schlüssel dazu. Ich habe nicht in der Tat müssen übersetzen zwischen UIKit koordiniert und Core Graphics-Koordinaten. Doch nach dem Mischmodus einstellt meine Alpha-Werte waren das, was ich erwartet habe:

CGContextSetBlendMode(context, kCGBlendModeCopy);
War es hilfreich?

Lösung

Ja, haben CGContexts ihre y-Achse zeigt nach oben, während in UIKit es nach unten zeigt. Sehen Sie die Dokumentation .

Bearbeiten nach Codelese:

Sie wollen auch vor dem Ziehen um das Bild zu ersetzen, den Mischmodus einstellen, da Sie das Bild des Alpha-Wert wollen, nicht derjenige, der im Kontext des Puffers war vor:

CGContextSetBlendMode(context, kCGBlendModeCopy);

Bearbeiten nach Denken:

Sie könnten die Lookup viel effizienter durch den kleinstmöglichen CGBitmapContext Gebäude (1x1 Pixel vielleicht 8x8 haben einen Versuch?) Und den Kontext auf die gewünschte Position zu übersetzen vor dem Zeichnen:

CGContextTranslateCTM(context, xOffset, yOffset);

Andere Tipps

Wenn alles, was Sie wollen, ist der Alpha-Wert von einem einzigen Punkt, alles, was Sie brauchen, ist ein Alpha-only Single-Point-Puffer. Ich glaube, das sollte genügen:

// assume im is a UIImage, point is the CGPoint to test
CGImageRef cgim = im.CGImage;
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel, 
                                         1, 1, 8, 1, NULL,
                                         kCGImageAlphaOnly);
CGContextDrawImage(context, CGRectMake(-point.x, 
                                   -point.y, 
                                   CGImageGetWidth(cgim), 
                                   CGImageGetHeight(cgim)), 
               cgim);
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;

Wenn die UIImage nicht jedes Mal neu erstellt werden muss, ist dies sehr effizient.

EDIT 8. Dezember 2011:

Ein Kommentator weist darauf hin, dass unter bestimmten Umständen das Bild umgedreht werden kann. Ich habe darüber nachgedacht, und ich bin ein wenig traurig, dass ich nicht den Code geschrieben habe direkt die UIImage verwenden, wie dies (ich glaube, der Grund dafür ist, dass zum Zeitpunkt ich nicht über UIGraphicsPushContext verstand):

// assume im is a UIImage, point is the CGPoint to test
unsigned char pixel[1] = {0};
CGContextRef context = CGBitmapContextCreate(pixel, 
                                             1, 1, 8, 1, NULL,
                                             kCGImageAlphaOnly);
UIGraphicsPushContext(context);
[im drawAtPoint:CGPointMake(-point.x, -point.y)];
UIGraphicsPopContext();
CGContextRelease(context);
CGFloat alpha = pixel[0]/255.0;
BOOL transparent = alpha < 0.01;

Ich denke, das würde das Flipping Problem gelöst hat.

Ich fand diese Frage / Antwort, während der Erforschung, wie Kollisionserkennung zwischen Sprites der Bilddaten, anstatt ein rechteckigen Begrenzungsrahmen mit dem Alpha-Wert zu tun. Der Kontext ist eine iPhone App ... Ich versuche, die oben vorgeschlagen 1 Pixel Unentschieden zu tun, und ich habe immer noch Probleme, die diese, den Weg zur Arbeit, aber ich fand einen einfacheren Weg, um eine CGContextRef der Erstellung von Daten aus dem Bild mit sich selbst und der Hilfsfunktionen hier:

CGContextRef context = CGBitmapContextCreate(
                 rawData, 
                 CGImageGetWidth(cgiRef), 
                 CGImageGetHeight(cgiRef), 
                 CGImageGetBitsPerComponent(cgiRef), 
                 CGImageGetBytesPerRow(cgiRef), 
                 CGImageGetColorSpace(cgiRef),
                 kCGImageAlphaPremultipliedLast     
    );

Dies umgeht die ganze hässliche Hardcoding in der Probe oben. Der letzte Wert kann durch den Aufruf CGImageGetBitmapInfo (), aber in meinem Fall abgerufen wird, einen Wert aus dem Bild zurück, die einen Fehler in der Funktion ContextCreate verursacht. Nur bestimmte Kombinationen gültig sind wie hier dokumentiert: http://developer.apple.com/qa /qa2001/qa1037.html

Hope Dies ist hilfreich!

  

Muss ich die Koordinaten zwischen UIKit und Core Graphics übersetzen - das heißt: die y-Achse invertiert

Es ist möglich. In CGImage ist die Pixeldaten in Englisch Leserichtung: von links nach rechts, von oben nach unten. So ist das erste Pixel in der Anordnung ist die obere linke; das zweite Pixel ist einer von links in der oberen Reihe; etc.

Angenommen, Sie haben richtig haben, sollten Sie auch sicherstellen, dass Sie innerhalb eines Pixels an der richtigen Komponente suchen. Vielleicht erwar Sie RGBA aber fordern ARGB, oder umgekehrt. Oder vielleicht haben Sie die Byte-Reihenfolge falsch (ich weiß nicht, was das iPhone endianness ist).

  

Oder habe ich premultiplied Alpha-Werte falsch verstanden?

Es klingt nicht wie es.

Für diejenigen, die es nicht wissen: Premultiplied bedeutet, dass die Farbkomponenten durch die alpha Premultiplied sind; die Alpha-Komponente ist das gleiche, ob die Farbkomponenten, indem sie es sind vormultipliziert oder nicht. Sie können dies umkehren (unpremultiply) durch Zahlungen der alpha die Farbkomponenten aufgeteilt wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top