Getting Pixel Data From CIImage

  • Hey,
    I am trying as hard as I can to get pixel data from a CIImage, but am
    failing, pretty miserably. I am using
    render:toBitmap:rowBytes:bounds:format:colorSpace: from CIContext and
    it seems to work, but doesn't really. I get data in my int*
    pointer, but it never changes! What am I doing wrong? I posted my
    code. The part in need of assistance is near the bottom of
    (void)captureOutput. I would greatly appreciate your help.

    Thank You,
    Bridger Maxwell

    - (void)captureOutput:(QTCaptureOutput *)captureOutput
    didOutputVideoFrame:(CVImageBufferRef)videoFrame
    withSampleBuffer:(QTSampleBuffer *)sampleBuffer
    fromConnection:(QTCaptureConnection *)connection

    {

    CIImage* image = [CIImage imageWithCVImageBuffer:videoFrame];

    [monoChromeFilter setValue:image forKey:@"inputImage"];  //First we
    monochrome it (only black and white

    //[smoothingFilter setValue:[monoChromeFilter
    valueForKey:@"outputImage"] forKey:@"inputImage"];

    if (needsNewBackground) { //If the flag has been raised we will
    capture a new background

    [backgroundFilter setValue:[monoChromeFilter
    valueForKey:@"outputImage"] forKey:@"inputBackgroundImage"];

    if (videoDeviceInput) {

    needsNewBackground = NO;

    }

    }

    [backgroundFilter setValue:[monoChromeFilter
    valueForKey:@"outputImage"] forKey:@"inputImage"]; //Now we subtract
    the background from the monochrome image

    [colorCorrectionFilter setValue:[backgroundFilter
    valueForKey:@"outputImage"] forKey:@"inputImage"];

    CIImage* finalImage = [colorCorrectionFilter valueForKey:@"outputImage"];

    size_t rowBytes = [self optimalRowBytesForWidth:[finalImage
    extent].size.width bytesPerPixel:4];

    int* imageData;

    [[[NSGraphicsContext currentContext] CIContext] render:finalImage

      toBitmap:imageData rowBytes:rowBytes

    bounds:[finalImage extent]

    format:kCIFormatARGB8

    colorSpace:CGColorSpaceCreateWithName(kCGColorSpaceGenericGray)];

    blobDetector->computeBlobs(imageData);

    NSLog(@"On Frame %i there are %i blobs. Sample byte 5:
    %i",frameCount++,blobDetector->getBlobNb(),imageData[19]);

    [outputView setImage:finalImage];

    [outputView setNeedsDisplay:YES];

    //CIContext* theContext = [outputView ciContext];

    }

    - (void) drawBlobsOnCIImage:(CIImage *)image {

    for (int n=0 ; n< blobDetector->getBlobNb() ; n++)

    {

    *blob = blobDetector->getBlob(n);

    if (blob->isOk())

    {

    NSRect rectangle = NSMakeRect(blob->xMin, blob->yMin, blob->xMax -
    blob->xMin , blob->yMax - blob->yMin);

    }

    }

    }

    - (size_t)optimalRowBytesForWidth: (size_t)width bytesPerPixel:
    (size_t)bytesPerPixel

    {

        size_t rowBytes = width * bytesPerPixel;

        //Widen rowBytes out to a integer multiple of 16 bytes

        rowBytes = (rowBytes + 15) & ~15;

        //Make sure we are not an even power of 2 wide.

        //Will loop a few times for rowBytes <= 16.

        while( 0 == (rowBytes & (rowBytes - 1) ) )

            rowBytes += 16;

        return rowBytes;

    }
  • Hi,

    If you are using Leopard (10.5), you could do something like this:

    CIImage* imageBlurred = .....
    NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc] initWithCIImage:
    imageBlurred] autorelease];

    // Getting pixels data
    // this returns a pointer to the pixel data
    [bitmap bitmapData]

    regards
    Nikolai Hellwig

    Am 13.05.2008 um 03:06 schrieb Bridger Maxwell:

    > Hey,
    > I am trying as hard as I can to get pixel data from a CIImage, but am
    > failing, pretty miserably. I am using
    > render:toBitmap:rowBytes:bounds:format:colorSpace: from CIContext and
    > it seems to work, but doesn't really. I get data in my int*
    > pointer, but it never changes! What am I doing wrong? I posted my
    > code. The part in need of assistance is near the bottom of
    > (void)captureOutput. I would greatly appreciate your help.
    >
    >
    > Thank You,
    > Bridger Maxwell
    >
    >
    >
    > - (void)captureOutput:(QTCaptureOutput *)captureOutput
    > didOutputVideoFrame:(CVImageBufferRef)videoFrame
    > withSampleBuffer:(QTSampleBuffer *)sampleBuffer
    > fromConnection:(QTCaptureConnection *)connection
    >
    > {
    >
    > CIImage* image = [CIImage imageWithCVImageBuffer:videoFrame];
    >
    >
    >
    > [monoChromeFilter setValue:image forKey:@"inputImage"];  //First we
    > monochrome it (only black and white
    >
    > //[smoothingFilter setValue:[monoChromeFilter
    > valueForKey:@"outputImage"] forKey:@"inputImage"];
    >
    >
    >
    > if (needsNewBackground) { //If the flag has been raised we will
    > capture a new background
    >
    > [backgroundFilter setValue:[monoChromeFilter
    > valueForKey:@"outputImage"] forKey:@"inputBackgroundImage"];
    >
    > if (videoDeviceInput) {
    >
    > needsNewBackground = NO;
    >
    > }
    >
    > }
    >
    >
    >
    > [backgroundFilter setValue:[monoChromeFilter
    > valueForKey:@"outputImage"] forKey:@"inputImage"]; //Now we subtract
    > the background from the monochrome image
    >
    > [colorCorrectionFilter setValue:[backgroundFilter
    > valueForKey:@"outputImage"] forKey:@"inputImage"];
    >
    > CIImage* finalImage = [colorCorrectionFilter
    > valueForKey:@"outputImage"];
    >
    > size_t rowBytes = [self optimalRowBytesForWidth:[finalImage
    > extent].size.width bytesPerPixel:4];
    >
    > int* imageData;
    >
    > [[[NSGraphicsContext currentContext] CIContext] render:finalImage
    >
    > toBitmap:imageData rowBytes:rowBytes
    >
    > bounds:[finalImage extent]
    >
    > format:kCIFormatARGB8
    >
    > colorSpace:CGColorSpaceCreateWithName(kCGColorSpaceGenericGray)];
    >
    >
    >
    > blobDetector->computeBlobs(imageData);
    >
    > NSLog(@"On Frame %i there are %i blobs. Sample byte 5:
    > %i",frameCount++,blobDetector->getBlobNb(),imageData[19]);
    >
    >
    >
    > [outputView setImage:finalImage];
    >
    > [outputView setNeedsDisplay:YES];
    >
    > //CIContext* theContext = [outputView ciContext];
    >
    > }
    >
    >
    >
    >
    > - (void) drawBlobsOnCIImage:(CIImage *)image {
    >
    > for (int n=0 ; n< blobDetector->getBlobNb() ; n++)
    >
    > {
    >
    > *blob = blobDetector->getBlob(n);
    >
    > if (blob->isOk())
    >
    > {
    >
    > NSRect rectangle = NSMakeRect(blob->xMin, blob->yMin, blob->xMax -
    > blob->xMin , blob->yMax - blob->yMin);
    >
    > }
    >
    > }
    >
    >
    >
    > }
    >
    >
    >
    >
    > - (size_t)optimalRowBytesForWidth: (size_t)width bytesPerPixel:
    > (size_t)bytesPerPixel
    >
    > {
    >
    > size_t rowBytes = width * bytesPerPixel;
    >
    >
    >
    > //Widen rowBytes out to a integer multiple of 16 bytes
    >
    > rowBytes = (rowBytes + 15) & ~15;
    >
    >
    >
    > //Make sure we are not an even power of 2 wide.
    >
    > //Will loop a few times for rowBytes <= 16.
    >
    > while( 0 == (rowBytes & (rowBytes - 1) ) )
    >
    > rowBytes += 16;
    >
    >
    >
    > return rowBytes;
    >
    > }
  • You can also create a CGBitmapContext (with CGBitmapContextCreate) and
    create a CIContext from that (with +[CIContext
    contextWithCGContext:options:]) and draw to the CIContext.  It will
    draw the pixels into the bitmap.  This will work for Tiger and Leopard.

    On May 13, 2008, at 1:51 AM, Nikolai Hellwig wrote:

    > If you are using Leopard (10.5), you could do something like this:
    >
    > CIImage* imageBlurred = .....
    > NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc]
    > initWithCIImage: imageBlurred] autorelease];
    >
    > // Getting pixels data
    > // this returns a pointer to the pixel data
    > [bitmap bitmapData]