-
Notifications
You must be signed in to change notification settings - Fork 948
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Crash in -[G8Tesseract recognizedBlocksByIteratorLevel:] --> tesseract::ResultIterator::AppendUTF8WordText #155
Comments
Can you provide the code you're using when this error occurs? What kinds of images are you trying to recognize (size, resolution, content, etc.)? It'd also be great if you could provide a sample image I can use to try to reproduce your issue. |
Following is the code. I figured out that if I call recognizedBlocksByIteratorLevel: earlier (as the code is currently configured), it works. The commented out version in the completion block is what was giving the trouble and leading to the assert. -(void)recognizeImageWithTesseract:(UIImage *)image
{
// Preprocess the image so Tesseract's recognition will be more accurate
UIImage *bwImage = [image g8_blackAndWhite];
// Create a new `G8RecognitionOperation` to perform the OCR asynchronously
G8RecognitionOperation *operation = [[G8RecognitionOperation alloc] init];
operation.tesseract.language = @"eng";
operation.tesseract.engineMode = G8OCREngineModeTesseractOnly;
operation.delegate = self;
operation.tesseract.image = bwImage; // Set the image on which to perform recognition
// Some debug info:
// First try just to get the segments from the image (no OCR):
//operation.tesseract.pageSegmentationMode = G8PageSegmentationModeAutoOnly;// Auto segmentation, NO OCR
operation.tesseract.pageSegmentationMode = G8PageSegmentationModeAutoOSD; // Auto orientation, script detection, segmentation, then OCR
DLogTM(kDebugOCR, @"Attempting to find the text segments in the image.");
BOOL result = operation.tesseract.recognize;
DLogTM(kDebugOCR, @"Attempt to find the text segments %s", result?"succeeded":"failed");
if (result)
{
NSArray *blocks = [operation.tesseract recognizedBlocksByIteratorLevel:G8PageIteratorLevelTextline];
DLogM(kDebugOCR, @"Block location Confidence Text");
for (G8RecognizedBlock *b in blocks)
{
DLogM(kDebugOCR, @"%@ %5.2f %@", NSStringFromCGRect([b boundingBoxAtImageOfSize:image.size]), b.confidence, b.text);
}
UIImage *processedImage = [operation.tesseract imageWithBlocks:blocks drawText:YES thresholded:NO];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // Create path
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"OCRImage.png"];
[UIImagePNGRepresentation(processedImage) writeToFile:filePath atomically:YES]; // Save image
}
operation.tesseract.pageSegmentationMode = G8PageSegmentationModeAuto; // Auto segmentation, followed by OCR
operation.recognitionCompleteBlock = ^(G8Tesseract *tesseract) {
// Fetch the recognized text
DLogTM(kDebugOCR, @"Tesseract OCR text recognition finished.");
NSString *recognizedText = tesseract.recognizedText;
// Some debug info:
DLogM(kDebugOCR, @"Recognized text:\n%@", recognizedText);
// NSArray *blocks = [tesseract recognizedBlocksByIteratorLevel:G8PageIteratorLevelTextline];
// DLogM(kDebugOCR, @"Block location Confidence Text");
// for (G8RecognizedBlock *b in blocks)
// {
// DLogM(kDebugOCR, @"%@ %5.2f %@", NSStringFromCGRect([b boundingBoxAtImageOfSize:image.size]), b.confidence, b.text);
// }
// UIImage *processedImage = [tesseract imageWithBlocks:blocks drawText:YES thresholded:NO];
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // Create path
// NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"OCRImage.png"];
// [UIImagePNGRepresentation(processedImage) writeToFile:filePath atomically:YES]; // Save image
[self performSelector:@selector(putOCRTextIntoField:)
onThread:[NSThread engineThread]
withObject:recognizedText
waitUntilDone:NO];
};
[self.operationQueue addOperation:operation]; // Add the recognition operation to the queue
} |
It looks like you're using You're calling Does that make sense? You should review the "Using NSOperationQueue" section of our Wiki, which provides an example for how you should be using Try adjusting your code accordingly, and if you're still having problems, provide the new version of your code and I'll try to help you debug it further. |
Sorry for the confusion, but the only reason I was trying the direct call to recognize was that when I let it happen properly via the operation queue it asserted when calling recognizedBlocksByIteratorLevel: from the completion block. So I was intentionally using it improperly only for debugging purposes, because of the assert mentioned above. I do understand that trying to do the recognition on the main thread is not a realistic option. |
Oh okay, then can you provide the original/proper code that you believe should be working but instead crashes? I won't be able to help you unless I can reproduce everything you're experiencing; it'll help if I don't have to make any assumptions about the code you're running. |
Thank you for looking at this problem. -(void)recognizeImageWithTesseract:(UIImage *)image
{
G8RecognitionOperation *operation = [[G8RecognitionOperation alloc] init];
operation.tesseract.image = [image g8_blackAndWhite]; // Preprocess the image so Tesseract's recognition will be more accurate
operation.tesseract.language = @"eng"; // Configure Tesseract
operation.tesseract.engineMode = G8OCREngineModeTesseractOnly;
operation.tesseract.pageSegmentationMode = G8PageSegmentationModeAuto; // Auto segmentation, followed by OCR
operation.delegate = self;
operation.recognitionCompleteBlock = ^(G8Tesseract *tesseract) {
// Fetch the recognized text
NSLog(@"Tesseract OCR text recognition finished.");
NSString *recognizedText = tesseract.recognizedText;
// Some debug info: --------------------------------------------------------------------------------
G8Orientation orientation = tesseract.orientation;
NSLog(@"Recognized text:\n%@", recognizedText);
NSLog(@"Orientation: %s", orientation==G8OrientationPageUp?"PageUp" : orientation==G8OrientationPageDown?"PageDown" : orientation==G8OrientationPageLeft?"PageLeft" : "PageRight");
NSLog(@"DeSkewAngle: %4.2f", tesseract.deskewAngle);
NSArray *blocks = [tesseract recognizedBlocksByIteratorLevel:G8PageIteratorLevelTextline];
NSLog(@"Block location Confidence Text");
for (G8RecognizedBlock *b in blocks)
{
NSLog(@"%@ %5.2f %@", NSStringFromCGRect([b boundingBoxAtImageOfSize:image.size]), b.confidence, b.text);
}
UIImage *processedImage = [tesseract imageWithBlocks:blocks drawText:YES thresholded:NO];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // Create path
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"OCRImage.png"];
[UIImagePNGRepresentation(processedImage) writeToFile:filePath atomically:YES]; // Save image
// --------------------------------------------------------------------------------------------------
//[self performSelector:@selector(putOCRTextIntoField:)
// onThread:[NSThread engineThread]
// withObject:recognizedText
// waitUntilDone:NO];
};
// Finally, add the recognition operation to the queue
NSLog(@"Kicking off Tesseract OCR operation to recognize the text.");
[self.operationQueue addOperation:operation];
} ***** The console:
***** and the stack:
As I mentioned above, if I have the same code execute directly on the main thread after a direct call to recognize, then I get all the right answers and no assert, so the problem seems to be influenced by the operation queue process, maybe the thread switching. |
Thanks for providing all of this info. I'm on vacation this week but I'll take a look at it early next week and try to implement a fix for you. |
Okay I've got a solution for you. First, an explanation: When you access the
This documentation is a little tricky for me to follow, but I think the gist of it is that So try modifying your code to be as follows and let me know if it works for you (note that I removed the file writing and text box part from the code you provided in your last message since it wasn't relevant, so you'll have to add that back in): -(void)recognizeImageWithTesseract:(UIImage *)image
{
// We recently updated the init for G8RecognitionOperation to be initWithLanguage, so make sure you redownload the source code or reinstall the CocoaPod so you have the latest version
G8RecognitionOperation *operation = [[G8RecognitionOperation alloc] initWithLanguage:@"eng"];
// Preprocess the image so Tesseract's recognition will be more accurate
operation.tesseract.image = [image g8_blackAndWhite];
operation.tesseract.engineMode = G8OCREngineModeTesseractOnly;
operation.tesseract.pageSegmentationMode = G8PageSegmentationModeAuto;
operation.delegate = self;
operation.recognitionCompleteBlock = ^(G8Tesseract *tesseract) {
NSLog(@"Tesseract OCR text recognition finished.");
// Access layout info BEFORE fetching recognized text
G8Orientation orientation = tesseract.orientation;
NSLog(@"Orientation: %s", orientation == G8OrientationPageUp ? "PageUp" : orientation == G8OrientationPageDown ? "PageDown" : orientation == G8OrientationPageLeft ? "PageLeft" : "PageRight");
NSLog(@"DeSkewAngle: %4.2f", tesseract.deskewAngle);
// Fetch the recognized text
NSString *recognizedText = tesseract.recognizedText;
NSLog(@"Recognized text:\n%@", recognizedText);
// Access info about recognized blocks
NSArray *blocks = [tesseract recognizedBlocksByIteratorLevel:G8PageIteratorLevelTextline];
NSLog(@"Block location Confidence Text");
for (G8RecognizedBlock *b in blocks)
{
NSLog(@"%@ %5.2f %@", NSStringFromCGRect([b boundingBoxAtImageOfSize:image.size]), b.confidence, b.text);
}
};
// Finally, add the recognition operation to the queue
NSLog(@"Kicking off Tesseract OCR operation to recognize the text.");
[self.operationQueue addOperation:operation];
} If this works for you, I propose modifying |
Your suggestion works...Thank you. |
My understanding is that Tesseract does not make the text rectangles available until you call I agree that if the user wants to use the page layout analysis values to rotate/adjust the image before performing recognition then my proposal doesn't make much sense because recognition is automatically performed when the operation is added to the queue, so the user doesn't have a chance to adjust the image. My proposal is more for the case where the user wants to know the values of the page layout analysis (just for informational purposes I guess) in the completion callback, which in the case of For your purpose, if you want to be able to adjust the image using the page layout analysis values before recognition is performed, I recommend doing it in 2 steps:
I haven't tried it myself, but my hope is that step 1 is fast relative to actually performing recognition so that this method doesn't slow down your app. I guess if it does you could always kick off step 1 asynchronously. I don't believe Tesseract does any corrections for page orientation/skew (regardless of the PSM mode set), but I could be wrong about that. My basis for this understanding are the following links: |
Hi Guys, I am using tesseract library for my iOS project. I am able to scan image in portrait mode perfectly but whenever the image orientation change, it doesn't gives me correct result. Thanks in advance. |
Hi @sauravkedia. |
Thanks Cyril. |
I kick off a recognition operation, with completion block. In the completion block I'm calling recognizedBlocksByIteratorLevel: and it asserts from tesseract::ResultIterator::AppendUTF8WordText, saying
it_->word()->best_choice != NULL:Error:Assert failed:in file resultiterator.cpp, line 594
If I don't try to get the blocks, the text recognition works fine. I've tried levels "Block", "Paragraph", and "TextLine".
The text was updated successfully, but these errors were encountered: