Related
When I user dispatch_apply to add some data to nscountset,I get a crash in simulator but iphone. And get a message "-[__NSArrayI isEqual:]: message sent to deallocated instance 0x60000024c5a0" ,I can not find how it happen.
CGSize thumbSize = CGSizeMake(200,200);
NSCountedSet *cls2 = [NSCountedSet setWithCapacity:thumbSize.width * thumbSize.height];
dispatch_apply(thumbSize.width, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
int x = (int)index;
for (int y = 0; y < thumbSize.height; y++) {
if(y<x){
continue;
}
int offset = 4*(x*y);
int red = data[offset];
int green = data[offset+1];
int blue = data[offset+2];
int alpha = data[offset+3];
NSArray *clr2 = #[#(red),#(green),#(blue),#(alpha)];
[cls2 addObject:clr2];
}
});
crash in [cls2 addobject:clr2];The log is "-[__NSArrayI isEqual:]: message sent to deallocated instance 0x60000024c5a0".
And There are all Code In My function,I want get the mostColor in a Image.
CGSize thumbSize = CGSizeMake(200, 200);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, thumbSize.width, thumbSize.height, 8, thumbSize.width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGRect drawRect = CGRectMake(0, 0, thumbSize.width, thumbSize.height);
CGContextDrawImage(context, drawRect, self.CGImage);
CGColorSpaceRelease(colorSpace);
unsigned char *data = CGBitmapContextGetData(context);
if (data == NULL)
{
return nil;
}
NSCountedSet *cls2 = [NSCountedSet setWithCapacity:thumbSize.width * thumbSize.height];
dispatch_apply(thumbSize.width, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
int x = (int) index;
for (int y = 0; y < thumbSize.height; y++)
{
if (y < x)
{
continue;
}
int offset = 4 * (x * y);
int red = data[offset];
int green = data[offset + 1];
int blue = data[offset + 2];
int alpha = data[offset + 3];
NSArray *clr3 = #[#(red), #(green), #(blue), #(alpha)];
[cls2 addObject:clr3];
}
});
CGContextRelease(context);
NSEnumerator *enumerator = [cls2 objectEnumerator];
NSArray *curColor = nil;
NSArray *maxColor = nil;
NSUInteger maxCount = 0;
while ((curColor = [enumerator nextObject]) != nil)
{
NSUInteger tmpCount = [cls2 countForObject:curColor];
if (tmpCount < maxCount) {
continue;
}
maxCount = tmpCount;
maxColor = curColor;
}
NSLog(#"colors: RGB A %f %d %d %d",[maxColor[0] floatValue],[maxColor[1] intValue],[maxColor[2] intValue],[maxColor[3] intValue]);
return [UIColor colorWithRed:([maxColor[0] intValue]/255.0f) green:([maxColor[1] intValue]/255.0f) blue:([maxColor[2] intValue]/255.0f) alpha:([maxColor[3] intValue]/255.0f)];
NSCountedSet is not thread safe - reference. Attempting to mutate one from concurrent threads is going to give unpredictable results - as you have found.
Either use a simple for loop without a dispatch_apply, dispatched on a background thread if required, to process your data, or protect your NSCountedSet update by dispatching it on a serial dispatch queue.
Earlier i used SDWebimage third party to display images, now i removed that 3rd party due some other reason. is there any other way to Display GIF image from URL in Imageview without using third party...
Well you can do it simply by following next steps:
Add the following functions
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>
UIImage *GIFFromData(NSData *data) {
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)(data), NULL);
UIImage *image = nil;
if (GIFSourceContainsAnimatedGIF(source)) {
image = GIFFromImageSource(source);
} else {
image = [UIImage imageWithData:data];
}
if (source) {
CFRelease(source);
}
return image;
}
BOOL GIFSourceContainsAnimatedGIF(CGImageSourceRef source) {
return (source && UTTypeConformsTo(CGImageSourceGetType(source), kUTTypeGIF) && CGImageSourceGetCount(source) > 1);
}
UIImage *GIFFromImageSource(CGImageSourceRef source) {
CFRetain(source);
NSUInteger numberOfFrames = CGImageSourceGetCount(source);
NSMutableArray<UIImage *> *images = [NSMutableArray arrayWithCapacity:numberOfFrames];
NSTimeInterval duration = 0.0;
for (NSUInteger i = 0; i < numberOfFrames; ++i) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (image) {
UIImage *frameImage = [UIImage imageWithCGImage:image scale:1.0 orientation:UIImageOrientationUp];
[images addObject:frameImage];
CFRelease(image);
} else {
continue;
}
duration += GIFSourceGetFrameDelay(source, i);
}
CFRelease(source);
return [UIImage animatedImageWithImages:images duration:duration];
}
NSTimeInterval GIFSourceGetFrameDelay(CGImageSourceRef source, NSUInteger index) {
NSTimeInterval frameDelay = 0;
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(source, index, NULL);
if (!imageProperties) {
return frameDelay;
}
CFDictionaryRef gifProperties = nil;
if (CFDictionaryGetValueIfPresent(imageProperties, kCGImagePropertyGIFDictionary, (const void **)&gifProperties)) {
const void *durationValue = nil;
if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFUnclampedDelayTime, &durationValue)) {
frameDelay = [(__bridge NSNumber *)durationValue doubleValue];
if (frameDelay <= 0) {
if (CFDictionaryGetValueIfPresent(gifProperties, kCGImagePropertyGIFDelayTime, &durationValue)) {
frameDelay = [(__bridge NSNumber *)durationValue doubleValue];
}
}
}
}
CFRelease(imageProperties);
return frameDelay;
}
Download your GIF with NSURLSession
Display it
UIImage *image = GIFFromData(data);
UIImageView *view = [[UIImageView alloc] initWithImage:image];
Hope this helps :)
UIImageView* animatedImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
animatedImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"image1.gif"],
[UIImage imageNamed:#"image2.gif"],
[UIImage imageNamed:#"image3.gif"],
[UIImage imageNamed:#"image4.gif"], nil];
animatedImageView.animationDuration = 1.0f;
animatedImageView.animationRepeatCount = 0;
[animatedImageView startAnimating];
[self.view addSubview: animatedImageView];
Add animated Gif image in Iphone UIImageView
I have to generate PDf from UITableView having multiple sections and rows.
I have generated the pdf as well but the problem is while creating PDF it is cutting the data of some rows and showing on other page.
So Please suggest any dynamic logic that will help in creating PDf having data on the page without going to other Page .
Also Please find code below which I have used to create PDF.
CGRect priorBounds = self.tableView.bounds;
CGSize fittedSize = [self.tableView sizeThatFits:CGSizeMake(priorBounds.size.width, self.tableView.contentSize.height)];
self.tableView.bounds = CGRectMake(0, 0, 612, fittedSize.height);
CGRect pdfPageBounds = CGRectMake(0, 0, 612, 792); // Change this as your need
NSMutableData *pdfData = [[NSMutableData alloc] init];
UIGraphicsBeginPDFContextToData(pdfData, pdfPageBounds, nil); {
for (CGFloat pageOriginY = 0; pageOriginY < fittedSize.height; pageOriginY += pdfPageBounds.size.height) {
UIGraphicsBeginPDFPageWithInfo(pdfPageBounds, nil);
CGContextSaveGState(UIGraphicsGetCurrentContext()); {
CGContextTranslateCTM(UIGraphicsGetCurrentContext(), 0, -pageOriginY);
[self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
} CGContextRestoreGState(UIGraphicsGetCurrentContext());
}
} UIGraphicsEndPDFContext();
self.tableView.bounds = priorBounds; // Reset the tableView
// Use the pdfData to
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
//Get the docs directory
NSString *filePathPDF = [documentsPath stringByAppendingPathComponent:#"image.pdf"]; //Add the file name
[pdfData writeToFile:filePathPDF atomically:YES];
Any help will be appreciated.
After doing a lot R&D on this, finally I got the solution.
I know this to too late to post answer of above question, but I am posting my solution so it may help someone in future.
The trick which I used to avoid this issue is, Run the loop each section wise and took picture of each dynamic cell.
Then I started combining images of cells by below function,
- (UIImage*)imageByCombiningImage:(UIImage*)firstImage withImage:(UIImage*)secondImage {
UIImage *image1 = firstImage;
UIImage *image2 = secondImage;
CGSize size = CGSizeMake(image1.size.width, image1.size.height + image2.size.height);
UIGraphicsBeginImageContext(size);
[image1 drawInRect:CGRectMake(0,0,size.width, image1.size.height)];
[image2 drawInRect:CGRectMake(0,image1.size.height,size.width, image2.size.height)];
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//set finalImage to IBOulet UIImageView
return finalImage;
}
and to generate combined image, I used below logic. In that I checked the height of combine image, if it is greater than screen size or not.
Below is my whole logic of code,
CGRect priorBounds = self.tableView.bounds;
CGSize fittedSize = [self.tableView sizeThatFits:CGSizeMake(priorBounds.size.width, self.tableView.contentSize.height)];
self.tableView.bounds = CGRectMake(0, 0, fittedSize.width, fittedSize.height);
pdfViews = [[NSMutableArray alloc] init];
NSMutableData *pdfData = [[NSMutableData alloc] init];
float sections = [self.tableView numberOfSections];
for (int C = 0; C < sections; C++)
{
int rows = 0;
rows = [self.tableView numberOfRowsInSection:C];
for (int I = 0; I < rows; I++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:I inSection:C];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UIGraphicsBeginImageContextWithOptions(cell.bounds.size, cell.opaque, 0.0);
[cell.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *cellImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[pdfViews addObject:cellImage];
}
}
NSArray *pageArray = pdfViews;
UIImage *pdfFinalImage = [[UIImage alloc] init];
UIImage *addOnImage = [[UIImage alloc] init];
NSMutableArray *finalA = [[NSMutableArray alloc] init];
int checkHeight;
checkHeight = 1024;
for (int Z = 0; Z < [pdfViews count]; Z++)
{
if (Z == 0)
{
pdfFinalImage = [pageArray objectAtIndex:Z];
}else if (Z+1 == [pdfViews count])
{
addOnImage = [pageArray objectAtIndex:Z];
if (pdfFinalImage.size.height+addOnImage.size.height > checkHeight)
{
[finalA addObject:pdfFinalImage];
pdfFinalImage = [pageArray objectAtIndex:Z];
[finalA addObject:pdfFinalImage];
}else
{
pdfFinalImage = [self imageByCombiningImage:pdfFinalImage withImage:addOnImage];
[finalA addObject:pdfFinalImage];
}
}else
{
UIImage *heightCheckImage = [pageArray objectAtIndex:Z];
if (pdfFinalImage.size.height+heightCheckImage.size.height > checkHeight)
{
[finalA addObject:pdfFinalImage];
pdfFinalImage = [pageArray objectAtIndex:Z];
}else
{
addOnImage = [pageArray objectAtIndex:Z];
pdfFinalImage = [self imageByCombiningImage:pdfFinalImage withImage:addOnImage];
}
}
}
UIGraphicsBeginPDFContextToData(pdfData, CGRectMake(0, 0, 768, 1024), nil);
for (int IC = 0; IC < [finalA count]; IC++)
{
UIGraphicsBeginPDFPage();
UIImage *mainImage = [finalA objectAtIndex:IC];
NSData *jpegData = UIImageJPEGRepresentation(mainImage, 0.5);
CGDataProviderRef dp = CGDataProviderCreateWithCFData((__bridge CFDataRef)jpegData);
CGImageRef cgImage = CGImageCreateWithJPEGDataProvider(dp, NULL, true, kCGRenderingIntentDefault);
[[UIImage imageWithCGImage:cgImage] drawInRect:CGRectMake(0, 0, mainImage.size.width, mainImage.size.height)];
}
UIGraphicsEndPDFContext();
self.tableView.bounds = priorBounds;
[pdfData writeToFile:tmpPdfPath atomically:YES];
I've done the following to allocate buffers for OpenAL in Swift:
init() {
self.buffers = NSMutableArray(capacity: 2);
self.sources = NSMutableArray(capacity: 2);
var sources: [ALuint] = [ALuint](count: 2, repeatedValue: 0);
var buffers: [ALuint] = [ALuint](count: 2, repeatedValue: 0);
alGenSources(2, UnsafeMutablePointer<ALuint>(sources));
alGenBuffers(2, UnsafeMutablePointer<ALuint>(buffers));
for i in 0...2 {
self.sources.addObject(NSNumber(unsignedInt: sources[i]));
self.buffers.addObject(NSNumber(unsignedInt: buffers[i]));
}
}
And it works perfectly fine. I cannot figure out how to delete it though. I tried:
deinit {
for i in 0...2 {
var source = self.sources.objectAtIndex(i).unsignedIntValue;
var buffer = self.buffers.objectAtIndex(i).unsignedIntValue;
//Error below.. I can't get address of "source" or "buffer".
alDeleteSources(1, UnsafePointer<ALuint>(ALuint(source)));
}
self.sources = nil; //cannot nil an NSMutableArray either..
self.buffers = nil;
}
So how can I get the address of the source and buffer variables to pass it to the UnsafePointer<ALuint>?
I'm trying to translate my Objective-C code below to the Swift code above:
-(void) init
{
if (!_sources)
{
unsigned int sources[2];
unsigned int buffers[2];
alGenSources(2, &sources[0]);
alGenBuffers(2, &buffers[0]);
_sources = [[NSMutableArray alloc] initWithCapacity: 2];
_buffers = [[NSMutableArray alloc] initWithCapacity: 2];
for (int i = 0; i < 2; ++i)
{
[_sources addObject: [NSNumber numberWithUnsignedInt: sources[i]]];
[_buffers addObject: [NSNumber numberWithUnsignedInt: buffers[i]]];
}
}
}
-(void) dealloc
{
for (int i = 0; i < [_sources count]; ++i)
{
unsigned int source = [[_sources objectAtIndex: i] unsignedIntValue];
unsigned int buffer = [[_buffers objectAtIndex: i] unsignedIntValue];
alDeleteSources(1, &source);
alDeleteBuffers(1, &buffer);
}
_sources = nil;
_buffers = nil;
}
I think you can simply use Array like:
class FuBar {
var sources = [ALuint](count: 2, repeatedValue: 0);
var buffers = [ALuint](count: 2, repeatedValue: 0);
init() {
alGenSources(2, &sources)
alGenBuffers(2, &buffers)
}
deinit {
alDeleteSources(2, &sources)
alDeleteBuffers(2, &buffers)
}
}
You don't have to use UnsafeMutablePointer explicitly, because in-out(&) expression of Array for UnsafeMutablePointer<T> is automatically converted to the pointer of the first element of the buffer of the array. see the docs.
When I use an image taken with the camera on the iPhone and send it to tesseract the accuracy is horrible it is all garbage text, but when I choose the same image from the photo library I get great accuracy.
How can I improve tesseracts accuracy from a picture take with the camera? Here is what I am doing to the image before sending
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
CGFloat newWidth = 1200;
CGSize newSize = CGSizeMake(newWidth, newWidth);
image = [image resizedImage:newSize interpolationQuality:kCGInterpolationHigh];
Tesseract* tesseract = [[Tesseract alloc]initWithLanguage:#"eng"];
[tesseract setVariableValue:#"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ##&*()-_:." forKey:#"tessedit_char_whitelist"];
[tesseract setVariableValue:#"`~!%^*[]{}<>?|" forKey:#"tessedit_char_blacklist"];
[tesseract setImage:image];
[tesseract recognize];
NSLog(#"%#", [tesseract recognizedText]);
[picker dismissViewControllerAnimated:YES completion:NULL];
}
If anyone has found some "magical" way to get tesseract to scan with great accuracy I will reward a bounty!
Main things to consider:
Tesseract needs to be trained for the font and language being recognized.
It looks like you are supplying appropriate parameters here - are they the same that you use when you supply a predefined image?
Tesseract doesn't orientate, or 'clean up' images
When you pass an image to the library, it should already be cleaned up and in portrait. Is the
image in photo reel taken from the camera too, or is it a sample image you've saved there somehow?
One check to make is the resize function:
CGFloat newWidth = 1200;
CGSize newSize = CGSizeMake(newWidth, newWidth);
The original image will be distorted by this, since you are resizing a non-square image into a square image. This will definitely squash the text and make life difficult for Tesseract. At the very least, you want to preserve the aspect ratio of the captured image.
My code work fine, but it´s more complex
- (IBAction)captureTapped:(id)sender
{
NSMutableArray *results = [NSMutableArray array];
NSString *fullWord = #"";
OCRImplementation *ocr = [[OCRImplementation alloc] init];
for(int j = 0; j < [self.images count]; j++){
UIImage *imageToTesseract = [self.images objectAtIndex:j];
//UIImage *imageToTesseract = self.imgfinal.image;
NSMutableArray *sortedKeys = [NSMutableArray array];
#try {
sortedKeys = [ocr processImageDetectText:imageToTesseract threadhold:198];
}
#catch (NSException *exception) {
sortedKeys = [NSMutableArray array];
}
NSString *finalWord = #"";
if([sortedKeys count] > 0){
for(int i=0; i<[sortedKeys count]; i++){
UIImage *image = [sortedKeys objectAtIndex:i];
finalWord = [self confidencesOCRTesseract:image];
if(finalWord.length > 1){
finalWord = [NSString stringWithFormat:#"%c",[finalWord characterAtIndex:0]];
}
fullWord = [fullWord stringByAppendingString:finalWord];
}
}
fullWord = [fullWord stringByReplacingOccurrencesOfString:#"\n" withString:#""];
[results addObject:fullWord];
NSLog(#"-- RESULT -- %#",fullWord);
}
NSString *resultWord = #"";
if([results count] > 0){
resultWord = [self calculateStatics:results];
}
//Your text Result
NSLog(#"%#",resultWord);
}
- (NSString*)calculateStatics:(NSMutableArray*)results{
NSMutableArray *first = [NSMutableArray array];
NSMutableArray *second = [NSMutableArray array];
NSMutableArray *third = [NSMutableArray array];
NSMutableArray *fourth = [NSMutableArray array];
NSMutableArray *fifth = [NSMutableArray array];
NSMutableArray *six = [NSMutableArray array];
NSMutableArray *seven = [NSMutableArray array];
for(int i = 0; i<[results count]; i++){
NSString *result = [results objectAtIndex:i];
if(result && ![result isEqualToString:#""]){
if(result.length >= 1 && [result characterAtIndex:0]){
[first addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:0]]];
}else{
[first addObject:#" "];
}
if(result.length >= 2 &&[result characterAtIndex:1]){
[second addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:1]]];
}else{
[second addObject:#" "];
}
if(result.length >= 3 &&[result characterAtIndex:2]){
[third addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:2]]];
}else{
[third addObject:#" "];
}
if(result.length >= 4 &&[result characterAtIndex:3]){
[fourth addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:3]]];
}else{
[fourth addObject:#" "];
}
if(result.length >= 5 &&[result characterAtIndex:4]){
[fifth addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:4]]];
}else{
[fifth addObject:#" "];
}
if(result.length >= 6 &&[result characterAtIndex:5]){
[six addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:5]]];
}else{
[six addObject:#" "];
}
if(result.length >= 7 &&[result characterAtIndex:6]){
[seven addObject:[NSString stringWithFormat:#"%c", [result characterAtIndex:6]]];
}else{
[seven addObject:#" "];
}
}else{
[first addObject:#" "];
[second addObject:#" "];
[third addObject:#" "];
[fourth addObject:#" "];
[fifth addObject:#" "];
[six addObject:#" "];
[seven addObject:#" "];
}
}
NSString *word = #"";
NSCountedSet *frequencies = [NSCountedSet setWithArray:first];
if([frequencies count] == 1){
word = [word stringByAppendingString:[[frequencies allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies count]; i++){
NSString *possibleWord = [[frequencies allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies2 = [NSCountedSet setWithArray:second];
if([frequencies2 count] == 1){
word = [word stringByAppendingString:[[frequencies2 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies2 count]; i++){
NSString *possibleWord = [[frequencies2 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies2 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies3 = [NSCountedSet setWithArray:third];
if([frequencies3 count] == 1){
word = [word stringByAppendingString:[[frequencies3 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies3 count]; i++){
NSString *possibleWord = [[frequencies3 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies3 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies4 = [NSCountedSet setWithArray:fourth];
if([frequencies4 count] == 1){
word = [word stringByAppendingString:[[frequencies4 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies4 count]; i++){
NSString *possibleWord = [[frequencies4 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies4 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies5 = [NSCountedSet setWithArray:fifth];
if([frequencies5 count] == 1){
word = [word stringByAppendingString:[[frequencies5 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies5 count]; i++){
NSString *possibleWord = [[frequencies5 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies5 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies6 = [NSCountedSet setWithArray:six];
if([frequencies6 count] == 1){
word = [word stringByAppendingString:[[frequencies6 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies6 count]; i++){
NSString *possibleWord = [[frequencies6 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies6 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
NSCountedSet *frequencies7 = [NSCountedSet setWithArray:seven];
if([frequencies7 count] == 1){
word = [word stringByAppendingString:[[frequencies7 allObjects] objectAtIndex:0]];
}else{
NSUInteger count = 0;
NSString *repeatedWord = #"";
for(int i=0; i<[frequencies7 count]; i++){
NSString *possibleWord = [[frequencies7 allObjects] objectAtIndex:i];
NSUInteger wordCount = [frequencies7 countForObject:possibleWord];
if(count < wordCount){
count = wordCount;
repeatedWord = possibleWord;
}
}
word = [word stringByAppendingString:repeatedWord];
}
return word;
}
OCRImplementation class
OCRImplementation.h
#ifndef __TesseractSample__OCRImplementation__
#define __TesseractSample__OCRImplementation__
#endif /* defined(__TesseractSample__OCRImplementation__) */
#interface OCRImplementation : NSObject{
}
- (UIImage*)processImage:(id)sender;
- (NSString*)confidencesOCRTesseract:(UIImage*)picture;
#end
OCRImplementation.mm
#include "OCRImplementation.h"
#import <OpenCV/opencv2/imgproc/imgproc.hpp>
#import <OpenCV/opencv2/highgui/highgui.hpp>
#import "UIImage+OpenCV.h"
#import "Tesseract.h"
#import "baseapi.h"
#import "environ.h"
#import "pix.h"
#include <sstream>
#include <iostream>
#include <vector>
#include "OpenCV/opencv2/core/core.hpp"
#include "OpenCV/opencv2/features2d/features2d.hpp"
#include "OpenCV/opencv2/calib3d/calib3d.hpp"
#implementation OCRImplementation
- (NSMutableArray*)processImageDetectText:(id)sender threadhold:(int)threadhold{
UIImage *img1 = sender;
cv::Mat src = [img1 CVMat];
cv::Mat src_gray;
cv::Mat threshold_output;
cv::vector<cv::vector<cv::Point> > contours;
cv::vector<cv::Vec4i> hierarchy;
int thresh = 100;
cv::RNG rng(12345);
/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, cv::Size(3,3) );
/// Detect edges using Threshold
cv::threshold( src_gray, threshold_output, thresh, 255, cv::THRESH_BINARY );
/// Find contours
cv::findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
/// Approximate contours to polygons + get bounding rects and circles
cv::vector<cv::vector<cv::Point> > contours_poly( contours.size() );
cv::vector<cv::Rect> boundRect( contours.size() );
cv::vector<cv::Point2f>center( contours.size() );
cv::vector<float>radius( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
approxPolyDP( cv::Mat(contours[i]), contours_poly[i], 3, true );
boundRect[i] = boundingRect( cv::Mat(contours_poly[i]) );
minEnclosingCircle( (cv::Mat)contours_poly[i], center[i], radius[i] );
}
/// Draw polygonal contour + bonding rects + circles
cv::Mat drawing = cv::Mat::zeros( threshold_output.size(), CV_8UC3 );
NSMutableDictionary *dictionaryImages = [NSMutableDictionary dictionary];
NSMutableArray *areaArray = [NSMutableArray array];
float lastArea = 0.0;
for( int i = 0; i< contours.size(); i++ )
{
cv::Scalar color = cv::Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
if(boundRect[i].height > 50){
double area = cv::contourArea(contours[i]);
if((boundRect[i].width < boundRect[i].height) && area > (lastArea / 2)){
lastArea = area;
[areaArray addObject:[NSString stringWithFormat:#"%f",area]];
rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
cv::Rect extendedRect = cv::Rect(boundRect[i].x - 5, boundRect[i].y - 5, boundRect[i].width + 10, boundRect[i].height + 10);
cv::Mat source = src;
cv::Mat target(extendedRect.size(), source.type());
if(0 <= extendedRect.x && 0 <= extendedRect.width && extendedRect.x + extendedRect.width <= source.cols && 0 <= extendedRect.y && 0 <= extendedRect.height && extendedRect.y + extendedRect.height <= source.rows){
source(extendedRect).copyTo(target);
//converting the original image into grayscale
cv::cvtColor(target, target, CV_BGR2GRAY);
cv::multiply(target, cv::Scalar(2,2,2), target);
cv::add(target, cv::Scalar(2,2,2), target);
/// Detect edges using Threshold
cv::threshold( target, threshold_output, threadhold, 255, cv::THRESH_BINARY );
cv::dilate(threshold_output, threshold_output, NULL);
UIImage *imgFinal = [OCRImplementation imageWithCVMat:threshold_output];
[dictionaryImages setObject:imgFinal forKey:[NSString stringWithFormat:#"%f", area]];
}else{
NSLog(#"Error al leer la imagen. NO ROI");
}
}
}
}
NSMutableDictionary *finalImages = [NSMutableDictionary dictionary];
NSMutableArray *sortedKeys = [NSMutableArray arrayWithArray:[areaArray sortedArrayUsingFunction:intSort context:NULL]];
for( int k = 0; k< contours.size(); k++ )
{
if(boundRect[k].height > 50){
for(int i = 0; i < [sortedKeys count]; i++){
double area = cv::contourArea(contours[k]);
if(area == [[sortedKeys objectAtIndex:i] floatValue]){
[finalImages setObject:[dictionaryImages objectForKey:[sortedKeys objectAtIndex:i]] forKey:[NSString stringWithFormat:#"%d",boundRect[k].x]];
}
}
}
}
NSMutableArray *array = [NSMutableArray array];
NSArray *keys = [finalImages allKeys];
NSArray *sortedKeys2 = [keys sortedArrayUsingFunction:intSortDesc context:NULL];
for(int i=0; i<[sortedKeys2 count]; i++){
[array addObject:[finalImages objectForKey:[sortedKeys2 objectAtIndex:i]]];
}
return array;
}
+ (UIImage *)imageWithCVMat:(const cv::Mat&)cvMat
{
NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize() * cvMat.total()];
CGColorSpaceRef colorSpace;
if (cvMat.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);
CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width
cvMat.rows, // Height
8, // Bits per component
8 * cvMat.elemSize(), // Bits per pixel
cvMat.step[0], // Bytes per row
colorSpace, // Colorspace
kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags
provider, // CGDataProviderRef
NULL, // Decode
false, // Should interpolate
kCGRenderingIntentDefault); // Intent
UIImage *image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return image;
}
- (NSString*)confidencesOCRTesseract:(UIImage*)picture{
tesseract::TessBaseAPI* tess;
uint32_t* _pixels;
NSString* _dataPath = #"tessdata";
NSString* _language = #"eng";
// Useful paths
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath = ([documentPaths count] > 0) ? [documentPaths objectAtIndex:0] : nil;
NSString *dataPath = [documentPath stringByAppendingPathComponent:_dataPath];
// Copy data in Doc Directory
if (![fileManager fileExistsAtPath:dataPath]) {
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *tessdataPath = [bundlePath stringByAppendingPathComponent:_dataPath];
if (tessdataPath) {
[fileManager copyItemAtPath:tessdataPath toPath:dataPath error:nil];
}
}
setenv("TESSDATA_PREFIX", [[documentPath stringByAppendingString:#"/"] UTF8String], 1);
tess = new tesseract::TessBaseAPI();
tess->Init([_dataPath UTF8String], [_language UTF8String]);
tess->SetVariable("save_blob_choices", "T");
tess->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
//SET IMAGE
CGSize size = [picture size];
int width = size.width;
int height = size.height;
_pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t));
// Clear the pixels so any transparency is preserved
memset(_pixels, 0, width * height * sizeof(uint32_t));
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// Create a context with RGBA _pixels
CGContextRef context = CGBitmapContextCreate(_pixels, width, height, 8, width * sizeof(uint32_t), colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
// Paint the bitmap to our context which will fill in the _pixels array
CGContextDrawImage(context, CGRectMake(0, 0, width, height), [picture CGImage]);
// We're done with the context and color space
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
tess->SetImage((const unsigned char *) _pixels, width, height, sizeof(uint32_t), width * sizeof(uint32_t));
//END SET IMAGE
tess->Recognize(NULL);
tesseract::ResultIterator* ri = tess->GetIterator();
tesseract::ChoiceIterator* ci;
// For every identified symbol (there should be only one...)
NSString *finalWord = #"";
if(ri != 0) {
do {
const char* symbol = ri->GetUTF8Text(tesseract::RIL_SYMBOL);
if(symbol != 0) {
float conf = ri->Confidence(tesseract::RIL_SYMBOL);
if(conf > 80.0f){
finalWord = [finalWord stringByAppendingString:[NSString stringWithUTF8String:symbol]];
}else{
const tesseract::ResultIterator itr = *ri;
ci = new tesseract::ChoiceIterator(itr);
// For every chosen candidate...
do {
const char* choice = ci->GetUTF8Text();
NSString *choiceStr = [NSString stringWithUTF8String:choice];
if(choice && ![choiceStr isEqualToString:#""]){
finalWord = [finalWord stringByAppendingString:choiceStr];
break;
}else{
finalWord = [finalWord stringByAppendingString:[NSString stringWithUTF8String:symbol]];
}
} while(ci->Next());
delete ci;
}
}
delete[] symbol;
} while((ri->Next(tesseract::RIL_SYMBOL)));
}
return finalWord;
}
NSInteger intSort(id num1, id num2, void *context) {
NSString *n1 = (NSString *) num1;
NSString *n2 = (NSString *) num2;
n1 = [[n1 componentsSeparatedByString:#"."] objectAtIndex:0];
n2 = [[n2 componentsSeparatedByString:#"."] objectAtIndex:0];
if ([n1 floatValue] > [n2 floatValue]) {
return NSOrderedAscending;
}
else if ([n1 floatValue] < [n2 floatValue]) {
return NSOrderedDescending;
}
return NSOrderedSame;
}
NSInteger intSortDesc(id num1, id num2, void *context) {
NSString *n1 = (NSString *) num1;
NSString *n2 = (NSString *) num2;
n1 = [[n1 componentsSeparatedByString:#"."] objectAtIndex:0];
n2 = [[n2 componentsSeparatedByString:#"."] objectAtIndex:0];
if ([n1 floatValue] < [n2 floatValue]) {
return NSOrderedAscending;
}
else if ([n1 floatValue] > [n2 floatValue]) {
return NSOrderedDescending;
}
return NSOrderedSame;
}
#end