Hi to All,
Is there any library for b4i that allows image manipulation? I need to make some transformations like binarization, blur, erode and dilate. I did that using B4A by accessing OPEN CV inline code. As I use remote host to compile my iOS code, the lib is not there (and I read at some post that it is really hard to use or port as a lib to b4i).
I've tried inline code as follow using CGIImageRef and CIImage that are already in remote host. But I didn't found a way to binarize, erode and dilate using these options. Any other way to do that?
Found references to GPUImage, but it is a open project and I don´t think it is easy to use at b4i, and I don´t have skill to write a lib to b4i.
Following code (caught from internet and adapt to run as inline) as an example. If you wanna try, you need to import QuartzCore and Accelerate.
Is there any library for b4i that allows image manipulation? I need to make some transformations like binarization, blur, erode and dilate. I did that using B4A by accessing OPEN CV inline code. As I use remote host to compile my iOS code, the lib is not there (and I read at some post that it is really hard to use or port as a lib to b4i).
I've tried inline code as follow using CGIImageRef and CIImage that are already in remote host. But I didn't found a way to binarize, erode and dilate using these options. Any other way to do that?
Found references to GPUImage, but it is a open project and I don´t think it is easy to use at b4i, and I don´t have skill to write a lib to b4i.
Following code (caught from internet and adapt to run as inline) as an example. If you wanna try, you need to import QuartzCore and Accelerate.
B4X:
#import <QuartzCore/QuartzCore.h>
#import <Accelerate/Accelerate.h>
B4X:
-(UIImage *)boxblurImage:(UIImage *)image boxSize:(int)boxSize {
//Get CGImage from UIImage
CGImageRef img = image.CGImage;
//setup variables
vImage_Buffer inBuffer, outBuffer;
vImage_Error error;
void *pixelBuffer;
//create vImage_Buffer with data from CGImageRef
//These two lines get get the data from the CGImage
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
//The next three lines set up the inBuffer object based on the attributes of the CGImage
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);
//This sets the pointer to the data for the inBuffer object
inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
//create vImage_Buffer for output
//allocate a buffer for the output image and check if it exists in the next three lines
pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
if(pixelBuffer == NULL)
NSLog(@"No pixelbuffer");
//set up the output buffer object based on the same dimensions as the input image
outBuffer.data = pixelBuffer;
outBuffer.width = CGImageGetWidth(img);
outBuffer.height = CGImageGetHeight(img);
outBuffer.rowBytes = CGImageGetBytesPerRow(img);
//perform convolution - this is the call for our type of data
error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
//check for an error in the call to perform the convolution
if (error) {
NSLog(@"error from convolution %ld", error);
}
//create CGImageRef from vImage_Buffer output
//1 - CGBitmapContextCreateImage -
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
outBuffer.width,
outBuffer.height,
8,
outBuffer.rowBytes,
colorSpace,
kCGImageAlphaNoneSkipLast);
CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
//clean up
CGContextRelease(ctx);
CGColorSpaceRelease(colorSpace);
free(pixelBuffer);
CFRelease(inBitmapData);
CGColorSpaceRelease(colorSpace);
CGImageRelease(imageRef);
return returnImage;
}
- (UIImage *)applyBlurOnImage: (UIImage *)imageToBlur
withRadius: (CGFloat)blurRadius {
CIImage *originalImage = [CIImage imageWithCGImage: imageToBlur.CGImage];
CIFilter *filter = [CIFilter filterWithName: @"CIGaussianBlur"
keysAndValues: kCIInputImageKey, originalImage,
@"inputRadius", @(blurRadius), nil];
CIImage *outputImage = filter.outputImage;
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef outImage = [context createCGImage: outputImage
fromRect: [outputImage extent]];
return [UIImage imageWithCGImage: outImage];
}
- (UIImage *) convertToGreyscale:(UIImage *)i {
int kRed = 1;
int kGreen = 2;
int kBlue = 4;
int colors = kGreen | kBlue | kRed;
int m_width = i.size.width;
int m_height = i.size.height;
uint32_t *rgbImage = (uint32_t *) malloc(m_width * m_height * sizeof(uint32_t));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(rgbImage, m_width, m_height, 8, m_width * 4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextSetShouldAntialias(context, NO);
CGContextDrawImage(context, CGRectMake(0, 0, m_width, m_height), [i CGImage]);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
// now convert to grayscale
uint8_t *m_imageData = (uint8_t *) malloc(m_width * m_height);
for(int y = 0; y < m_height; y++) {
for(int x = 0; x < m_width; x++) {
uint32_t rgbPixel=rgbImage[y*m_width+x];
uint32_t sum=0,count=0;
if (colors & kRed) {sum += (rgbPixel>>24)&255; count++;}
if (colors & kGreen) {sum += (rgbPixel>>16)&255; count++;}
if (colors & kBlue) {sum += (rgbPixel>>8)&255; count++;}
m_imageData[y*m_width+x]=sum/count;
}
}
free(rgbImage);
// convert from a gray scale image back into a UIImage
uint8_t *result = (uint8_t *) calloc(m_width * m_height *sizeof(uint32_t), 1);
// process the image back to rgb
for(int i = 0; i < m_height * m_width; i++) {
result[i*4]=0;
int val=m_imageData[i];
result[i*4+1]=val;
result[i*4+2]=val;
result[i*4+3]=val;
}
// create a UIImage
colorSpace = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(result, m_width, m_height, 8, m_width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
CGImageRef image = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *resultUIImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);
free(m_imageData);
// make sure the data will be released by giving it to an autoreleased NSData
[NSData dataWithBytesNoCopy:result length:m_width * m_height];
return resultUIImage;
}