這段時間項目的需求,需要在注冊的時候進行身份證識別萍悴。就簡單的搞了一下岩齿。
身份證識別
項目的需求是通過攝像頭的采集獲取到身份證上面的一些數(shù)據(jù)太颤,比如身份證號碼、姓名等信息盹沈。
而不是簡單的知曉身份證號碼后來一波正則判斷龄章。
實現(xiàn)方案
- 首先通過手機攝像頭獲取到手機的身份證的圖片,務(wù)必要背景簡單乞封,色調(diào)單一瓦堵,主要是在后面處理圖像的時候?qū)ψR別率的提升有幫助。
- 通過openCV對原始圖片處理歌亲,把圖片變成灰度圖->二值化->腐蝕、膨脹->輪廓檢測->剪裁等處理澜驮,使得圖片成為我們想要的樣式陷揪。
- 然后裁剪出合適的區(qū)域,如只要身份證的號碼的區(qū)域就只需要裁剪出身份證號碼即可杂穷。
- 通過OCR對圖片進行識別悍缠,讓圖片中顯示的文字轉(zhuǎn)換成文字。
- 識別好號碼后耐量,進行一波身份證號碼識別的預處理飞蚓,網(wǎng)上有很多的正則表達式,可以搜索下廊蜒。我的代碼中也會有體現(xiàn)的趴拧。
- 通過身份證號碼就可以得知出生年月以及性別(18位身份證:第17位代表的是性別溅漾,奇數(shù)為男性,偶數(shù)為女性)
openCV相關(guān)
- opencv的相關(guān)代碼是用C++寫的著榴,所以在引用這個opencv的頭文件的那個類添履,需要把.m文件修改為.mm文件。
- 相關(guān)的類引用了opencv脑又,需要把引用的頭文件放在最前面暮胧,建議使用pch來引用,可以避免造成不必要的麻煩问麸。
下面弄個簡單的代碼演示下:
-
原始圖片:女神 新垣結(jié)衣
- 處理后的圖片
opencv demo下載里面沒有opencv的framework,另行[下載](鏈接: https://pan.baidu.com/s/1o8LjSgi) 密碼: 7ubn严卖。
OCR相關(guān)
利用谷歌的tesseractOCR和tessdata的庫(其中有英文的庫和中文的庫)來識別處理完成后的圖片席舍。
- 注意 : 其中tessdata拖入到工程中需要拖入一個真實的文件夾(藍色文件),而不是一個在工程中虛擬的文件夾妄田。
引入的依賴庫
處理圖片
#pragma mark - 處理圖片得到身份證號碼圖片
//掃描身份證圖片俺亮,并進行預處理,定位號碼區(qū)域圖片并返回
- (UIImage *)opencvScanCardWithNumber:(UIImage *)image {
//將UIImage轉(zhuǎn)換成Mat
cv::Mat resultImage;
UIImageToMat(image, resultImage);
//轉(zhuǎn)為灰度圖
cvtColor(resultImage, resultImage, cv::COLOR_BGR2GRAY);
//利用閾值二值化
cv::threshold(resultImage, resultImage, 100, 255, CV_THRESH_BINARY);
//腐蝕疟呐,填充(腐蝕是讓黑色點變大)
cv::Mat erodeElement = getStructuringElement(cv::MORPH_RECT, cv::Size(27,27));
cv::erode(resultImage, resultImage, erodeElement);
//輪廊檢測
std::vector<std::vector<cv::Point>> contours;//定義一個容器來存儲所有檢測到的輪廊
cv::findContours(resultImage, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));
//cv::drawContours(resultImage, contours, -1, cv::Scalar(255),4);
//取出身份證號碼區(qū)域
std::vector<cv::Rect> rects;
cv::Rect numberRect = cv::Rect(0,0,0,0);
std::vector<std::vector<cv::Point>>::const_iterator itContours = contours.begin();
for ( ; itContours != contours.end(); ++itContours) {
cv::Rect rect = cv::boundingRect(*itContours);
rects.push_back(rect);
//算法原理
if (rect.width > numberRect.width && rect.width > rect.height * 5) {
numberRect = rect;
}
}
//身份證號碼定位失敗
if (numberRect.width == 0 || numberRect.height == 0) {
return nil;
}
//定位成功成功脚曾,去原圖截取身份證號碼區(qū)域,并轉(zhuǎn)換成灰度圖启具、進行二值化處理
cv::Mat matImage;
UIImageToMat(image, matImage);
resultImage = matImage(numberRect);
cvtColor(resultImage, resultImage, cv::COLOR_BGR2GRAY);
cv::threshold(resultImage, resultImage, 80, 255, CV_THRESH_BINARY);
//將Mat轉(zhuǎn)換成UIImage
UIImage *numberImage = MatToUIImage(resultImage);
return numberImage;
}
識別已經(jīng)處理過的圖片
#pragma mark - 識別文字或者數(shù)字
//利用TesseractOCR識別文字
- (void)tesseractRecognizeImage:(UIImage *)image compleate:(CompleateBlock)compleate {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"chi_sim"];
// tesseract.image = [image g8_blackAndWhite];
if (image == nil) {
NSLog(@"圖片沒有處理成功");
return;
}
tesseract.image = image;
// Start the recognition
BOOL done = [tesseract recognize];
//執(zhí)行回調(diào)
compleate(tesseract.recognizedText);
});
}
獲取攝像頭的權(quán)限后本讥,開啟攝像頭,在其代理中實現(xiàn)
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;
得到號碼后鲁冯,可以對性別進行判斷
#pragma mark - 判斷性別
- (NSString *)judgeGenderWithIdNumber:(NSString *)idNumber {
NSInteger genderNumber = [[idNumber substringWithRange:NSMakeRange(16, 1)] integerValue];
if (genderNumber % 2 == 0) {
return [NSString stringWithFormat:@"性別:%@", @"女"];
} else {
return [NSString stringWithFormat:@"性別:%@", @"男"];
}
}
相關(guān)的[依賴文件]鏈接: https://pan.baidu.com/s/1gfkSXWn 密碼: kan7拷沸。直接拖入到工程中就可以了(opencv、tesseractOCR以及tessdata)薯演。