iOS 集成OCR

来源:互联网 发布:sql基本语句 编辑:程序博客网 时间:2024/06/06 01:59
项目里要加一个OCR识别身份证图片,当时没理解,就在网上找了个利用Video扫描识别身份证的。识别率挺高,识别效果挺好的,地址是 https://github.com/iosWellLin/OCR。这个demo 真心不错,识别速度快,识别汉字几乎没有乱码,但是和我们的需求不符合,我们要的是识别图片。我就想,如果把这个改造一下,既让它扫描 也让它拍照,拍照后还能截取我在屏幕上画的指定区域的截图,所以我就开搞。使用AVCaptureVideoDataOutput扫描屏幕,使用上面那个Demo的静态库获得扫描的身份证信息,然后使用AVCaptureStillImageOutput获取屏幕截图,利用下面的方法 获取指定区域

- (CGRect) calcRect:(CGSize)imageSize{      NSString* gravity = self.previewLayer.videoGravity;      CGRect cropRect = 区域的Rect;      CGSize screenSize = self.previewLayer.bounds.size;             CGFloat screenRatio = screenSize.height / screenSize.width ;      CGFloat imageRatio = imageSize.height /imageSize.width;             CGRect presentImageRect = self.previewLayer.bounds;      CGFloat scale = 1.0;                    if([AVLayerVideoGravityResizeAspect isEqual: gravity]){                     CGFloat presentImageWidth = imageSize.width;          CGFloat presentImageHeigth = imageSize.height;          if(screenRatio > imageRatio){              presentImageWidth = screenSize.width;              presentImageHeigth = presentImageWidth * imageRatio;                         }else{              presentImageHeigth = screenSize.height;              presentImageWidth = presentImageHeigth / imageRatio;          }                     presentImageRect.size = CGSizeMake(presentImageWidth, presentImageHeigth);          presentImageRect.origin = CGPointMake((screenSize.width-presentImageWidth)/2.0, (screenSize.height-presentImageHeigth)/2.0);             }else if([AVLayerVideoGravityResizeAspectFill isEqual:gravity]){                     CGFloat presentImageWidth = imageSize.width;          CGFloat presentImageHeigth = imageSize.height;          if(screenRatio > imageRatio){              presentImageHeigth = screenSize.height;              presentImageWidth = presentImageHeigth / imageRatio;          }else{              presentImageWidth = screenSize.width;              presentImageHeigth = presentImageWidth * imageRatio;          }                     presentImageRect.size = CGSizeMake(presentImageWidth, presentImageHeigth);          presentImageRect.origin = CGPointMake((screenSize.width-presentImageWidth)/2.0, (screenSize.height-presentImageHeigth)/2.0);                 }else{          NSAssert(0, @"dont support:%@",gravity);      }             scale = CGRectGetWidth(presentImageRect) / imageSize.width;             CGRect rect = cropRect;      rect.origin = CGPointMake(CGRectGetMinX(cropRect)-CGRectGetMinX(presentImageRect), CGRectGetMinY(cropRect)-CGRectGetMinY(presentImageRect));             rect.origin.x /= scale;      rect.origin.y /= scale;      rect.size.width /= scale;      rect.size.height  /= scale;             return rect;  }     #define SUBSET_SIZE 360    - (UIImage*) cropImageInRect:(UIImage*)image{         CGSize size = [image size];      CGRect cropRect = [self calcRect:size];         float scale = fminf(1.0f, fmaxf(SUBSET_SIZE / cropRect.size.width, SUBSET_SIZE / cropRect.size.height));      CGPoint offset = CGPointMake(-cropRect.origin.x, -cropRect.origin.y);             size_t subsetWidth = cropRect.size.width * scale;      size_t subsetHeight = cropRect.size.height * scale;                    CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceGray();             CGContextRef ctx =      CGBitmapContextCreate(nil,                            subsetWidth,                            subsetHeight,                            8,                            0,                            grayColorSpace,                            kCGImageAlphaNone|kCGBitmapByteOrderDefault);      CGColorSpaceRelease(grayColorSpace);      CGContextSetInterpolationQuality(ctx, kCGInterpolationNone);      CGContextSetAllowsAntialiasing(ctx, false);         // adjust the coordinate system      CGContextTranslateCTM(ctx, 0.0, subsetHeight);      CGContextScaleCTM(ctx, 1.0, -1.0);                    UIGraphicsPushContext(ctx);      CGRect rect = CGRectMake(offset.x * scale, offset.y * scale, scale * size.width, scale * size.height);         [image drawInRect:rect];             UIGraphicsPopContext();             CGContextFlush(ctx);                    CGImageRef subsetImageRef = CGBitmapContextCreateImage(ctx);             UIImage* subsetImage = [UIImage imageWithCGImage:subsetImageRef];         CGImageRelease(subsetImageRef);             CGContextRelease(ctx);                return subsetImage;  }
至于怎么在屏幕中画区域,参考扫描二维码绘制遮盖层即layer

这样一做,用户主动去拍照,当点击我设置的拍照的时候,利用AVCaptureStillImageOutput获取屏幕截图,利用上面的方法获取指定区域的图片,再通过静态库提供的类获取身份证信息,当获取不到时就认为获取失败,只展示拍照图片。

这样看上去挺完美的,况且识别率挺高的。

但是有一个特别重要的问题,就是这个OCR识别身份证的静态库,没有源码,不知道内部实现,看大小也不像是现在开源的一些OCR识别库。所以这里的安全性问题就交到了一个没有安全性可言的人或...身上。当然不公开源码也无可厚非,因为毕竟这是人家或人家公司的核心技术。如果你注重客户的隐私,那么这个就不能使用。如果没有这方面的问题,这个Demo还是不错的。因为这些我们否定了这个。查找开源的OCR库,最后我们使用的Tesseart-OCR,这是谷歌在维护的一个开源库,总体来说识别还是不错的,重要的是图片的预处理。因为我的C++实在不怎么样 集成 太费劲 ,所以我在github上找了一个为iOS封装的FrameWork,地址:https://github.com/gali8/Tesseract-OCR-iOS/releases 
你可以用他的工程生成FrameWork 也可以直接把文件导出来,直接使用。
使用起来也挺简单的,最重要的是图像与处理,Tesseract-OCR只是提供了简单的儿纸和灰度处理,比如滤镜、锐度...都需要自己去处理,我打算使用openCV进行处理,现在还在学习openCV的阶段,就不丢人了

0 0
原创粉丝点击