Frage

Ich schreibe eine iPhone-Anwendung und muß im Wesentlichen etwas entsprechen das ‚Pipette‘ Werkzeug in Photoshop implementieren, in dem Sie einen Punkt auf dem Bild berühren und den RGB-Wert für das betreffende Pixel erfassen, um seine Farbe zu bestimmen und anzupassen . die UIImage zu erhalten ist der einfache Teil, aber gibt es eine Möglichkeit, die UIImage Daten in eine Bitmap-Darstellung zu konvertieren, in dem ich diese Information für ein bestimmtes Pixel extrahieren könnte? Eine Arbeitscodebeispiel wäre sehr geschätzt, und beachten Sie, dass ich nicht mit dem Alpha-Wert betroffen bin.

War es hilfreich?

Lösung

Ein wenig mehr Details ...

Ich gab früher an diesem Abend mit einer Konsolidierung und kleiner Ergänzung zu dem, was war auf dieser Seite gesagt worden -, der am Ende dieses Beitrags zu finden sind. Ich bin der Bearbeitung der Post an dieser Stelle jedoch zu schreiben, was ich vorschlage, ist (zumindest für meine Anforderungen, die modifizierende Pixeldaten enthalten), eine bessere Methode, da es beschreibbare Daten liefert (wobei, wie ich sie verstehe, wobei das Verfahren zur Verfügung gestellt durch vorhergehende Pfosten und an der Unterseite dieses Pfostens eine nur-Lese-Referenz zu Daten).

Methode 1: Beschreibbare Pixelinformationen

  1. I definiert Konstanten

    #define RGBA        4
    #define RGBA_8_BIT  8
    
  2. In meiner UIImage Unterklasse deklarierte ich Instanzvariablen:

    size_t bytesPerRow;
    size_t byteCount;
    size_t pixelCount;
    
    CGContextRef context;
    CGColorSpaceRef colorSpace;
    
    UInt8 *pixelByteData;
    // A pointer to an array of RGBA bytes in memory
    RPVW_RGBAPixel *pixelData;
    
  3. Die Pixel Struktur (mit Alpha in dieser Version)

    typedef struct RGBAPixel {
        byte red;
        byte green;
        byte blue;
        byte alpha;
    } RGBAPixel;
    
  4. Bitmap-Funktion (liefert vorausberechneten RGBA; divide RGB durch A unmodifizierten RGB zu erhalten):

    -(RGBAPixel*) bitmap {
        NSLog( @"Returning bitmap representation of UIImage." );
        // 8 bits each of red, green, blue, and alpha.
        [self setBytesPerRow:self.size.width * RGBA];
        [self setByteCount:bytesPerRow * self.size.height];
        [self setPixelCount:self.size.width * self.size.height];
    
        // Create RGB color space
        [self setColorSpace:CGColorSpaceCreateDeviceRGB()];
    
        if (!colorSpace)
        {
            NSLog(@"Error allocating color space.");
            return nil;
        }
    
        [self setPixelData:malloc(byteCount)];
    
        if (!pixelData)
        {
            NSLog(@"Error allocating bitmap memory. Releasing color space.");
            CGColorSpaceRelease(colorSpace);
    
            return nil;
        }
    
        // Create the bitmap context. 
        // Pre-multiplied RGBA, 8-bits per component. 
        // The source image format will be converted to the format specified here by CGBitmapContextCreate.
        [self setContext:CGBitmapContextCreate(
                                               (void*)pixelData,
                                               self.size.width,
                                               self.size.height,
                                               RGBA_8_BIT,
                                               bytesPerRow,
                                               colorSpace,
                                               kCGImageAlphaPremultipliedLast
                                               )];
    
        // Make sure we have our context
        if (!context)   {
            free(pixelData);
            NSLog(@"Context not created!");
        }
    
        // Draw the image to the bitmap context. 
        // The memory allocated for the context for rendering will then contain the raw image pixelData in the specified color space.
        CGRect rect = { { 0 , 0 }, { self.size.width, self.size.height } };
    
        CGContextDrawImage( context, rect, self.CGImage );
    
        // Now we can get a pointer to the image pixelData associated with the bitmap context.
        pixelData = (RGBAPixel*) CGBitmapContextGetData(context);
    
        return pixelData;
    }
    

Read-Only-Daten (vorherige Information) - Methode 2:


Schritt 1. erklärte ich einen Typen für Byte:

 typedef unsigned char byte;

Schritt 2. erklärte ich eine Struktur zu einem Pixel entsprechen:

 typedef struct RGBPixel{
    byte red;
    byte green;
    byte blue;  
    }   
RGBPixel;

Schritt 3. Ich subclassed UIImageView und erklärt (mit synthetisierten Eigenschaften entsprechen):

//  Reference to Quartz CGImage for receiver (self)  
CFDataRef bitmapData;   

//  Buffer holding raw pixel data copied from Quartz CGImage held in receiver (self)    
UInt8* pixelByteData;

//  A pointer to the first pixel element in an array    
RGBPixel* pixelData;

Schritt 4. Subklassen-Code, den ich in einem Verfahren namens Bitmap setzen (die Bitmap-Pixeldaten zurück):

//Get the bitmap data from the receiver's CGImage (see UIImage docs)  
[self setBitmapData: CGDataProviderCopyData(CGImageGetDataProvider([self CGImage]))];

//Create a buffer to store bitmap data (unitialized memory as long as the data)    
[self setPixelBitData:malloc(CFDataGetLength(bitmapData))];

//Copy image data into allocated buffer    
CFDataGetBytes(bitmapData,CFRangeMake(0,CFDataGetLength(bitmapData)),pixelByteData);

//Cast a pointer to the first element of pixelByteData    
//Essentially what we're doing is making a second pointer that divides the byteData's units differently - instead of dividing each unit as 1 byte we will divide each unit as 3 bytes (1 pixel).    
pixelData = (RGBPixel*) pixelByteData;

//Now you can access pixels by index: pixelData[ index ]    
NSLog(@"Pixel data one red (%i), green (%i), blue (%i).", pixelData[0].red, pixelData[0].green, pixelData[0].blue);

//You can determine the desired index by multiplying row * column.    
return pixelData;

Schritt 5. ich eine Accessormethode gemacht:

-(RGBPixel*)pixelDataForRow:(int)row column:(int)column{
    //Return a pointer to the pixel data
    return &pixelData[row * column];           
}

Andere Tipps

Hier ist meine Lösung für die Probenahme Farbe eines UIImage.

Dieser Ansatz macht die angeforderte Pixel in einen 1px großen RGBA-Puffer und gibt die resultierenden Farbwerte als UIColor Objekt. Das ist viel schneller als die meisten anderen Ansätzen habe ich gesehen, und verwendet nur sehr wenig Speicher.

Das sollte ziemlich gut für so etwas wie eine Farbauswahl arbeiten, wo Sie in der Regel nur den Wert eines bestimmten Pixels müssen in einem einem bestimmten Zeitpunkt.

UIImage + Picker.h

#import <UIKit/UIKit.h>


@interface UIImage (Picker)

- (UIColor *)colorAtPosition:(CGPoint)position;

@end

UIImage + Picker.m

#import "UIImage+Picker.h"


@implementation UIImage (Picker)

- (UIColor *)colorAtPosition:(CGPoint)position {

    CGRect sourceRect = CGRectMake(position.x, position.y, 1.f, 1.f);
    CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, sourceRect);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *buffer = malloc(4);
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;
    CGContextRef context = CGBitmapContextCreate(buffer, 1, 1, 8, 4, colorSpace, bitmapInfo);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0.f, 0.f, 1.f, 1.f), imageRef);
    CGImageRelease(imageRef);
    CGContextRelease(context);

    CGFloat r = buffer[0] / 255.f;
    CGFloat g = buffer[1] / 255.f;
    CGFloat b = buffer[2] / 255.f;
    CGFloat a = buffer[3] / 255.f;

    free(buffer);

    return [UIColor colorWithRed:r green:g blue:b alpha:a];
}

@end 

Sie können nicht die Bitmap-Daten eines UIImage direkt zugreifen zu können.

Sie müssen die CGImage Darstellung des UIImage zu bekommen. Dann werden die Daten Providers CGImage bekommen, von dem eine cfdata Darstellung der Bitmap. Achten Sie auf die cfdata freizugeben, wenn Sie fertig.

CGImageRef cgImage = [image CGImage];
CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
CFDataRef bitmapData = CGDataProviderCopyData(provider);

Sie wollen wahrscheinlich auf Bitmap-Informationen des CGImage aussehen Pixel um, Bildabmessungen zu erhalten, etc.

etwas ähnliches in meiner Anwendung zu tun, habe ich einen kleinen Off-Screen-CGImageContext und machte dann die UIImage hinein. Die erlaubte mir eine schnelle Art und Weise eine Anzahl von Pixeln auf einmal zu extrahieren. Dies bedeutet, dass Sie das Ziel Bitmap in einem Format einrichten können Sie leicht zu analysieren, zu finden, und lassen Sie Core Graphics die harte Arbeit der Umwandlung zwischen Farbmodellen oder Bitmap-Formaten zu tun.

  

Ich weiß nicht, wie zu indizieren in Bilddaten auf bestimmten X automatisch korrekt, Y cordination. Kennt jemand?

pixelPosition = (x + (y * ((Width) * BytesPerPixel)));

// Tonhöhe ist nicht ein Problem mit diesem Gerät, soweit ich weiß und kann null werden lassen ... // (oder aus der Mathematik gezogen).

Verwenden Sie ANImageBitmapRep die Pixel-Level-Zugriff gibt (Lesen / Schreiben).

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