hyuni
1/31/2016 - 5:20 AM

vImage helpers

vImage helpers

//
//  PixelBufferUtils.h
//  IRStudio
//
//  Created by Brian Cook on 5/30/12.
//  Copyright (c) 2012 All rights reserved.
//

#import <Accelerate/Accelerate.h>
#import "BCNeonImageUtils.h"

#ifndef IRStudio_CVPixelBufferUtils_h
#define IRStudio_CVPixelBufferUtils_h

CGContextRef BCNEONCreateARGBBitmapContext(const size_t width, 
                                           const size_t height, 
                                           const size_t bytesPerRow) {
    
	CGContextRef bmContext = CGBitmapContextCreate(NULL, 
                                                   width, 
                                                   height, 
                                                   8, 
                                                   bytesPerRow, 
                                                   CGColorSpaceCreateDeviceRGB(), 
                                                   kCGBitmapByteOrderDefault | 
                                                   kCGImageAlphaPremultipliedFirst);
    
	return bmContext;
}

CGContextRef ARGBBitmapContextFromBCNEONCategory (CGImageRef inImage) {
	CGContextRef    context = NULL;
	CGColorSpaceRef colorSpace;
	void *          bitmapData;
	int             bitmapByteCount;
	int             bitmapBytesPerRow;
	
	size_t pixelsWide = CGImageGetWidth(inImage);
	size_t pixelsHigh = CGImageGetHeight(inImage);
	
	bitmapBytesPerRow   = (pixelsWide * 4);
	bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);
	
	// Use the generic RGB color space.
	colorSpace = CGColorSpaceCreateDeviceRGB();
	
	if (colorSpace == NULL) {
		fprintf(stderr, "Error allocating color space\n");
		return NULL;
	}
	
	bitmapData = malloc( bitmapByteCount );
	if (bitmapData == NULL)  {
		CGColorSpaceRelease( colorSpace );
		return NULL;
	}
	
	context = CGBitmapContextCreate (bitmapData,
									 pixelsWide,
									 pixelsHigh,
									 8,
									 bitmapBytesPerRow,
									 colorSpace,
									 kCGImageAlphaPremultipliedFirst);
    
	CGColorSpaceRelease( colorSpace );
	return context;
}

CGImageRef swapRedAndBlueChannels(CGImageRef image) {
    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    size_t bytesPerRow = width * 4;
    
    CGContextRef bmContext = BCNEONCreateARGBBitmapContext(width, height, bytesPerRow);
    CGContextDrawImage(bmContext, CGRectMake(0.0f, 0.0f, width, height), image);
    
    UInt8* imageData = CGBitmapContextGetData(bmContext);
    swapRedAndBlueChannelsARGB(imageData, width, height, bytesPerRow);
    
    CGContextRelease(bmContext);
}


void swapRedAndBlueChannelsARGB(unsigned char *baseAddress, size_t width, size_t height, size_t bytesPerRow) {
    const size_t n = sizeof(UInt8) * width * height * 4;
    void *outBuffer = malloc(n);
    vImage_Buffer src = {baseAddress, height, width, bytesPerRow};
    vImage_Buffer dest = {outBuffer, height, width, bytesPerRow};
    
    //ARGB to ABGR
    const uint8_t map[4] = {0, 3, 2, 1};
    vImagePermuteChannels_ARGB8888(&src, &dest, map, kVimageNoFlags);
}

void CalculateAutocorretionValues(CGImageRef image, CGFloat *whitePoint, CGFloat *blackPoint) {
	UInt8* imageData = malloc(200 * 200 * 4);
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	CGContextRef ctx = CGBitmapContextCreate(imageData, 200, 200, 8, 4 * 200, colorSpace, kCGImageAlphaPremultipliedFirst);
	CGColorSpaceRelease(colorSpace);
	
	CGContextDrawImage(ctx, CGRectMake(0, 0, 200, 200), image);
	
	int histogramm[256];
	bzero(histogramm, 256 * sizeof(int));
	
	for (int i = 0; i < 200 * 200 * 4; i += 4) {
		UInt8 value = (imageData[i+1] + imageData[i+2] + imageData[i+3]) / 3;
		histogramm[value]++;
	}
	
	CGContextRelease(ctx);
	free(imageData);
	
	int black = 0;
	int counter = 0;
	
	// count up to 200 (2%) values from the black side of the histogramm to find the black point
	while ((counter < 200) && (black < 256)) {
		counter += histogramm[black];
		black ++;
	}
	
	int white = 255;
	counter = 0;
	
	// count up to 200 (2%) values from the white side of the histogramm to find the white point
	while ((counter < 200) && (white > 0)) {
		counter += histogramm[white];
		white --;
	}
	
	*blackPoint = 0.0 - (black / 256.0);
	*whitePoint = 1.0 + ((255-white) / 256.0);
}

void equalizeImageBufferImageARGB(unsigned char *baseAddress, int width, int height, int bytesPerRow) {
    const size_t n = sizeof(UInt8) * width * height * 4;
    void *outBuffer = malloc(n);
    vImage_Buffer src = {baseAddress, height, width, bytesPerRow};
    vImage_Buffer dest = {outBuffer, height, width, bytesPerRow};
    vImage_Error err = vImageEqualization_ARGB8888(&src, &dest, kvImageCopyInPlace);
    
    if (err == kvImageNoError) {
        memcpy(baseAddress, outBuffer, n);
    }
    
    free(outBuffer);
}

void equalizeImageBufferBGRAtoRGBAImage(unsigned char *baseAddress, int width, int height, int bytesPerRow) {
    neon_BGRA_to_ARGB(baseAddress, width, height);
    equalizeImageBufferImageARGB(baseAddress, width, height, bytesPerRow);
}

void stretchImageContrastARGB(unsigned char *baseAddress, int width, int height, int bytesPerRow) {
    const size_t n = sizeof(UInt8) * width * height * 4;
    void *outBuffer = malloc(n);
    vImage_Buffer src = {baseAddress, height, width, bytesPerRow};
    vImage_Buffer dest = {outBuffer, height, width, bytesPerRow};
    vImage_Error err = vImageContrastStretch_ARGB8888(&src, &dest, kvImageCopyInPlace);
    
    if (err == kvImageNoError) {
        memcpy(baseAddress, outBuffer, n);
    }
    
    free(outBuffer);
}

void stretchImageBufferBGRAtoRGBAImage(unsigned char *baseAddress, int width, int height, int bytesPerRow) {
    neon_BGRA_to_ARGB(baseAddress, width, height);
    stretchImageContrastARGB(baseAddress, width, height, bytesPerRow);
}


#endif