Pregunta

He creado un objeto NSImage, e idealmente gustaría para determinar cuántos de cada color de píxeles que contiene. ¿Es esto posible?

¿Fue útil?

Solución

Sugiero crear su propio contexto de mapa de bits , envoltura en un contexto gráfico y ajuste que como el contexto actual, contando la imagen para dibujar en sí , y luego acceder a los datos de píxeles detrás el contexto de mapa de bits directamente

Esto será más código, pero le ahorrará un viaje a través de una representación TIFF y la creación de miles o millones de objetos NSColor. Si se trabaja con imágenes de cualquier tamaño apreciable, estos gastos se suman rápidamente.

Otros consejos

Este código hace que el NSImage en un CGBitmapContext:

- (void)updateImageData {

    if (!_image)
        return;

    // Dimensions - source image determines context size

    NSSize imageSize = _image.size;
    NSRect imageRect = NSMakeRect(0, 0, imageSize.width, imageSize.height);

    // Create a context to hold the image data

    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);

    CGContextRef ctx = CGBitmapContextCreate(NULL,
                                             imageSize.width,
                                             imageSize.height,
                                             8,
                                             0,
                                             colorSpace,
                                             kCGImageAlphaPremultipliedLast);

    // Wrap graphics context

    NSGraphicsContext* gctx = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:NO];

    // Make our bitmap context current and render the NSImage into it

    [NSGraphicsContext setCurrentContext:gctx];
    [_image drawInRect:imageRect];

    // Calculate the histogram

    [self computeHistogramFromBitmap:ctx];

    // Clean up

    [NSGraphicsContext setCurrentContext:nil];
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
}

Dado un contexto de mapa de bits, se puede acceder a los datos de imágenes en bruto directamente, y calcular los histogramas para cada canal de color:

- (void)computeHistogramFromBitmap:(CGContextRef)bitmap {

    // NB: Assumes RGBA 8bpp

    size_t width = CGBitmapContextGetWidth(bitmap);
    size_t height = CGBitmapContextGetHeight(bitmap);

    uint32_t* pixel = (uint32_t*)CGBitmapContextGetData(bitmap);

    for (unsigned y = 0; y < height; y++)
    {
        for (unsigned x = 0; x < width; x++)
        {
            uint32_t rgba = *pixel;

            // Extract colour components
            uint8_t red   = (rgba & 0x000000ff) >> 0;
            uint8_t green = (rgba & 0x0000ff00) >> 8;
            uint8_t blue  = (rgba & 0x00ff0000) >> 16;

            // Accumulate each colour
            _histogram[kRedChannel][red]++;
            _histogram[kGreenChannel][green]++;
            _histogram[kBlueChannel][blue]++;

            // Next pixel!
            pixel++;
        }
    }
}

@end

He publicado un proyecto completo, una aplicación de ejemplo del Cacao, que incluye lo anterior.

NSBitmapImageRep desde su NSImage. Entonces se puede obtener acceso a los píxeles.

NSImage* img = ...;
NSBitmapImageRep* raw_img = [NSBitmapImageRep imageRepWithData:[img TIFFRepresentation]];
NSColor* color = [raw_img colorAtX:0 y:0];

Esto puede ser un enfoque más racional para algunos y reducir la complejidad de caer en la gestión de memoria.

https://github.com/koher/EasyImagy

Ejemplo de código https://github.com/koher/EasyImagyCameraSample

import EasyImagy

let image = Image<RGBA<UInt8>>(nsImage: "test.png") // N.B. init with nsImage 

print(image[x, y])
image[x, y] = RGBA(red: 255, green: 0, blue: 0, alpha: 127)
image[x, y] = RGBA(0xFF00007F) // red: 255, green: 0, blue: 0, alpha: 127

// Iterates over all pixels
for pixel in image {
    // ...
}



//// Gets a pixel by subscripts Gets a pixel by  
let pixel = image[x, y]
// Sets a pixel by subscripts
image[x, y] = RGBA(0xFF0000FF)
image[x, y].alpha = 127
// Safe get for a pixel
if let pixel = image.pixelAt(x: x, y: y) {
    print(pixel.red)
    print(pixel.green)
    print(pixel.blue)
    print(pixel.alpha)

    print(pixel.gray) // (red + green + blue) / 3
    print(pixel) // formatted like "#FF0000FF"
} else {
    // `pixel` is safe: `nil` is returned when out of bounds
    print("Out of bounds")
}

Busque "histograma" en la documentación de la base de la imagen.

El uso de colorAtX con NSBitmapImageRep no siempre se traduce en el color correcto.

Me las arreglé para conseguir el color correcto con este simple código:

[yourImage lockFocus]; // yourImage is just your NSImage variable
NSColor *pixelColor = NSReadPixel(NSMakePoint(1, 1)); // Or another point
[yourImage unlockFocus];
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top