第一次接觸圖像解析,隨便上網(wǎng)搜羅了一些資料自己整理了一下就不要臉的寫了下來(lái),有錯(cuò)的地方還望指點(diǎn).
先說(shuō)說(shuō)大致流程吧
1.先將圖片進(jìn)行降噪
2.將降噪的圖片二值化
3.對(duì)二值化的圖片進(jìn)行劃分,分割出獨(dú)立的字符圖片
4.識(shí)別
這是一個(gè)驗(yàn)證碼
一琅催、降噪
1.我拿來(lái)處理的驗(yàn)證碼本身格式很簡(jiǎn)單,所以我對(duì)圖片進(jìn)行了灰值化處理。
圖片本身是一個(gè)個(gè)像素點(diǎn)構(gòu)成蚌堵,可以將圖片看成是一個(gè)由像素構(gòu)成的二維數(shù)組芍秆。每個(gè)像素點(diǎn)都有Red Green Blue三個(gè)顏色的值个初,通過(guò)遍歷像素點(diǎn)乖菱,令R = G = B來(lái)完成圖片的灰值化坡锡。
常見的灰值化算法(方法?窒所?):
1.g(x,y) = (r(x帆锋,y) + g(x吵取,y) + b(x,y))/3
2.g(x锯厢,y) = 0.11r(x皮官,y) + 0.59g(x脯倒,y) + 0.3*b(x,y)
3.g(x捺氢,y) = min(min(r(x藻丢,y), g(x,y)) , b(x摄乒,y))
第二種算法是來(lái)源于NTSC色彩空間中Y分量的計(jì)算公式悠反,處理大部分驗(yàn)證碼效果比較滿意。但處理紅色調(diào)為主的驗(yàn)證碼就不行了馍佑,權(quán)值太小斋否。在我的案例里我選用的就是第二種算法,因?yàn)槲业膱D像真的簡(jiǎn)單:-D拭荤。
如果圖片有噪點(diǎn)還需要對(duì)噪點(diǎn)進(jìn)行判斷茵臭,具體操作是判斷某個(gè)像素點(diǎn)與周圍8個(gè)像素點(diǎn)的色差是否大于某個(gè)闕值,如果大于就+1s,如果有超過(guò)6個(gè)像素點(diǎn)大于的話就認(rèn)定位噪點(diǎn)舅世。周圍沒(méi)有8個(gè)點(diǎn)的一律剔除旦委,那些是邊界點(diǎn)。
二雏亚、二值化
沒(méi)覺得二社证、二像一個(gè)表情?评凝?好了言歸正傳追葡,當(dāng)圖像進(jìn)行灰值化后通過(guò)計(jì)算閾值可以將圖片進(jìn)行二值化,低于閾值的g(x奕短,y)設(shè)為0宜肉,高于閾值的設(shè)為1...是255!0代表黑色翎碑,255代表白色谬返。雖然不準(zhǔn)確,但是比較好理解日杈。
三遣铝、切分
這個(gè)我沒(méi)寫下去,我通過(guò)統(tǒng)計(jì)一條X軸上所有的黑色像素點(diǎn)來(lái)獲取字與字之間間隔的閾值莉擒。當(dāng)?shù)陀谶@個(gè)閾值或等于0時(shí)就可以認(rèn)為這是字與字之間的間隔酿炸,通過(guò)這個(gè)分割字符串。好像還有別的方法切分涨冀,具體應(yīng)該看是什么類型的驗(yàn)證碼填硕。
四、識(shí)別
我集成了TesserectORC進(jìn)行匹配,所以我切分也沒(méi)搞扁眯。大致還是記錄一下吧壮莹。目前的圖片在理想情況下會(huì)根據(jù)每個(gè)字符切成一塊矩陣。這個(gè)矩陣上0是空白1是有像素姻檀。一個(gè)圖片字符就轉(zhuǎn)換為了一個(gè)矩陣命满,然后用你的肉眼去識(shí)別它,做成鍵值對(duì)绣版,通過(guò)對(duì)比這個(gè)矩陣和另一個(gè)矩陣是否一致來(lái)確定另一個(gè)矩陣是不是這個(gè)字符胶台。什么漢明距離,編輯距離我也不太懂僵娃,就當(dāng)一個(gè)索引以后拓展概作。
五、TesserectORC
oc 上識(shí)別圖像用這個(gè)應(yīng)該沒(méi)錯(cuò)默怨,免費(fèi)而且有g(shù)oogle維護(hù)讯榕。
代碼
#import "UIImage+BGImage.h"
#import <TesseractOCR/TesseractOCR.h>
@implementation UIImage (BGImage)
typedef enum {
ALPHA = 0,
BLUE = 1,
GREEN = 2,
RED = 3
} PIXELS;
- (UIImage *)convertToGrayscale {
CGSize size = [self size];
int width = size.width;
int height = size.height;
//獲取像素點(diǎn)數(shù)組
uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t));
memset(pixels, 0, width * height * sizeof(uint32_t));
//創(chuàng)建顏色通道
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//上下文規(guī)則?匙睹?我也不懂
CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
//創(chuàng)建圖片上下文
CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]);
NSMutableArray *array = [NSMutableArray array];
NSMutableArray *nub = [NSMutableArray array];
for(int x = 0; x < width; x++) {
// NSMutableString *str = [NSMutableString string];
int i = 0;
for(int y = 0; y < height; y++){
uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x];
uint32_t gray = 0.11 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.3* rgbaPixel[BLUE];
// uint32_t gray = MIN(MIN(rgbaPixel[RED], rgbaPixel[GREEN]), rgbaPixel[BLUE]);
// uint32_t gray = rgbaPixel[GREEN];
if (gray > 138) {
gray = 255;
}else {
gray = 0;
i++;
//保存黑點(diǎn)的XY值
NSValue *value = [NSValue valueWithCGPoint:CGPointMake(x, y)];
[array addObject:value];
}
rgbaPixel[RED] = gray;
rgbaPixel[GREEN] = gray;
rgbaPixel[BLUE] = gray;
}
[nub addObject:[NSNumber numberWithInt:i]];
}
// NSLog(@"%@",nub);
//// NSLog(@"%@",array);
// //i代表y值
// for (int i = 0; i < nub.count; i++) {
// NSNumber *num = nub[i];
// if (num.intValue == 0) {
//
// }
// }
CGImageRef image = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
free(pixels);
UIImage *resultUIImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);
G8Tesseract *rect = [[G8Tesseract alloc]init];
rect.language = @"eng";
rect.engineMode = G8OCREngineModeTesseractCubeCombined;
rect.pageSegmentationMode = G8PageSegmentationModeAuto;
rect.maximumRecognitionTime = 60.0;
rect.image = resultUIImage;
NSString *newStr = rect.recognizedText;
NSLog(@"hhhhh::%@",newStr);
return resultUIImage;
}
@end
差不多就是這樣愚屁。能幫到需要的人一點(diǎn)點(diǎn)就好了。蟹蟹看完