tesseract3.0.2在mac 10.10上的编译 xcode6

一. 编译tesseract的系统环境:

mac系统版本:OS X Yosemite 10.10

Xcode版本:Version 6.2 (6C131e)

iOS SDK:8.0


二. 准备工作:

1、下载源代码

1.tesseract (https://code.google.com/p/tesseract-ocr/downloads/list)

2.tesseract语言包

3.leptonica(tesseract依赖于它) (http://www.leptonica.com/download.html)

2、新建文件夹 compile_code,讲上面下载的tesseract,leptonica都解压在这里


三. 开始编译:

开发环境配置有很多种,我使用的是MacPort的方式(主要是我第一个接触的就是它,懒得去换了)

1.下载MacPort(http://www.macports.org/install.php)

2.修改/opt/local/etc/macports/sources.conf文件

官网修改方案:http://trac.macports.org/wiki/howto/PortTreeTarball

sudo vim /opt/local/etc/macports/sources.conf

找到:rsync://rsync.macports.org/release/ports/[default]

修改为:https://distfiles.macports.org/ports.tar.gz [default]

打开终端,输入下面的命令,等待更新结束

sudo port –d sync

3.按顺序安装所需要的工具:M4-> autoconf -> automake -> libtool

以M4安装为例:

sudo port install M4

4.进入文件夹compile_code,新建脚本文件build.sh

内容如下:

#!/bin/sh

GLOBAL_OUTDIR="`pwd`/build"
LOCAL_OUTDIR="./outdir"
LEPTON_LIB="`pwd`/leptonica-1.72"
TESSERACT_LIB="`pwd`/tesseract-ocr"

IOS_BASE_SDK="8.0"
IOS_DEPLOY_TGT="8.0"

# 设置编译器、连接器
export CXX=`xcrun -find c++`
export CC=`xcrun -find cc`

export LD=`xcrun -find ld`
export AR=`xcrun -find ar`
export AS=`xcrun -find as`
export NM=`xcrun -find nm`
export RANLIB=`xcrun -find ranlib`

# 设置编译器路径、模拟器路径
XCODE_DEVELOPER_PATH=/Applications/Xcode.app/Contents/Developer
XCODETOOLCHAIN_PATH=$XCODE_DEVELOPER_PATH/Toolchains/XcodeDefault.xctoolchain
SDK_IPHONEOS_PATH=$(xcrun --sdk iphoneos --show-sdk-path)
SDK_IPHONESIMULATOR_PATH=$(xcrun --sdk iphonesimulator --show-sdk-path)

export PATH="$XCODETOOLCHAIN_PATH/usr/bin:$PATH"

declare -a archs
archs=(arm7 arm7s arm64 i386 x86_64)

declare -a arch_name
arch_names=(arm-apple-darwin7 arm-apple-darwin7s arm-apple-darwin64 i386-apple-darwin x86_64-apple-darwin)

# 设置编译参数
setenv_all() {
    # Add internal libs
    export CFLAGS="$CFLAGS -I$GLOBAL_OUTDIR/include -L$GLOBAL_OUTDIR/lib -Qunused-arguments"
    export LDFLAGS="-L$SDKROOT/usr/lib/"

    export CPPFLAGS=$CFLAGS
    export CXXFLAGS=$CFLAGS
}

setenv_arm7() {
    unset DEVROOT SDKROOT CFLAGS CPP CXXCPP LDFLAGS CPPFLAGS CXXFLAGS

    export SDKROOT=$SDK_IPHONEOS_PATH
    export CFLAGS="-arch armv7 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"

    setenv_all
}

setenv_arm7s() {
    unset DEVROOT SDKROOT CFLAGS CPP CXXCPP LDFLAGS CPPFLAGS CXXFLAGS

    export SDKROOT=$SDK_IPHONEOS_PATH
    export CFLAGS="-arch armv7s -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"

    setenv_all
}

setenv_arm64() {
    unset DEVROOT SDKROOT CFLAGS CPP CXXCPP LDFLAGS CPPFLAGS CXXFLAGS

    export SDKROOT=$SDK_IPHONEOS_PATH
    export CFLAGS="-arch arm64 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"

    setenv_all
}

setenv_i386() {
    unset DEVROOT SDKROOT CFLAGS CPP CXXCPP LDFLAGS CPPFLAGS CXXFLAGS

    export SDKROOT=$SDK_IPHONESIMULATOR_PATH
    export CFLAGS="-arch i386 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT"

    setenv_all
}

setenv_x86_64() {
    unset DEVROOT SDKROOT CFLAGS CPP CXXCPP LDFLAGS CPPFLAGS CXXFLAGS

    export SDKROOT=$SDK_IPHONESIMULATOR_PATH
    export CFLAGS="-arch x86_64 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT"

    setenv_all
}

# 合并库(用于模拟器与真机同时使用)
create_outdir_lipo() {
    for file in `find $LOCAL_OUTDIR/i386 -name "lib*.a"`; do
    lib_arm7=`echo $file | sed "s/i386/arm7/g"`
    lib_arm7s=`echo $file | sed "s/i386/arm7s/g"`
    lib_arm64=`echo $file | sed "s/i386/arm64/g"`
    lib_x86_64=`echo $file | sed "s/i386/x86_64/g"`
    lib_i386=`echo $file`
    lib=`echo $file | sed "s/i386//g"`
    xcrun -sdk iphoneos lipo -arch armv7s $lib_arm7s -arch armv7 $lib_arm7 -arch arm64 $lib_arm64 -arch i386 $lib_i386 -arch x86_64 $lib_x86_64 -create -output $lib
    done
}

merge_libfiles() {
    DIR=$1
    LIBNAME=$2

    cd $DIR
    for i in `find . -name "lib*.a"`; do
    $AR -x $i
    done
    $AR -r $LIBNAME *.o
    rm -rf *.o __*
    cd -
}
# 下载源代码
#get_leptonica()
#{
#    curl -C - -O http://www.leptonica.com/source/leptonica-1.68.tar.gz
#    tar xzvf leptonica-1.68.tar.gz
#}

#get_tessreact()
#{
#    curl -C - -O http://tesseract-ocr.googlecode.com/files/tesseract-3.01.tar.gz
#    tar xzvf tesseract-3.01.tar.gz
#}

#######################
# 清理工作空间
#######################

rm -rf $GLOBAL_OUTDIR lib include

########################
## 下载需要编译的文件
########################
## 下载leptonica
#get_leptonica
## 下载tessreact
#get_tessreact

#######################
# 进入LEPTONLIB目录
#######################
cd $LEPTON_LIB
rm -rf $LOCAL_OUTDIR

for n in "${!archs[@]}"
do
    mkdir -p "$LOCAL_OUTDIR/${archs[$n]}"
    make clean 2> /dev/null
    make distclean 2> /dev/null
    eval "setenv_${archs[$n]}"
    ./configure --host="${arch_names[$n]}" --enable-shared=no --disable-programs --without-zlib --without-libpng --without-jpeg --without-giflib --without-libtiff
    make -j12
    cp -rvf src/.libs/lib*.a "$LOCAL_OUTDIR/${archs[$n]}"
done

create_outdir_lipo
mkdir -p $GLOBAL_OUTDIR/include/leptonica && find ./ -name '*.h' -exec cp {} $GLOBAL_OUTDIR/include/leptonica/  \;
mkdir -p $GLOBAL_OUTDIR/lib && cp -rvf $LOCAL_OUTDIR/lib*.a $GLOBAL_OUTDIR/lib
cd ..


#######################
# 进入TESSERACT目录
#######################
cd $TESSERACT_LIB
rm -rf $LOCAL_OUTDIR

for n in "${!archs[@]}"
do
    mkdir -p "$LOCAL_OUTDIR/${archs[$n]}"
    make clean 2> /dev/null
    make distclean 2> /dev/null
    eval "setenv_${archs[$n]}"
    bash autogen.sh
    LIBLEPT_HEADERSDIR=$GLOBAL_OUTDIR/include ./configure --host="${arch_names[$n]}" --enable-shared=no --disable-graphics
    make -j12
    for i in `find . -name "lib*.a" | grep -v $LOCAL_OUTDIR`
    do
        cp -rvf $i "$LOCAL_OUTDIR/${archs[$n]}"
    done
    merge_libfiles "$LOCAL_OUTDIR/${archs[$n]}" libtesseract_all.a
done

create_outdir_lipo

mkdir -p $GLOBAL_OUTDIR/include/tesseract && find ./ -name '*.h' -exec cp {} $GLOBAL_OUTDIR/include/tesseract/  \;
mkdir -p $GLOBAL_OUTDIR/lib && cp -rvf $LOCAL_OUTDIR/lib*.a $GLOBAL_OUTDIR/lib
make clean 2> /dev/null
make distclean 2> /dev/null
cd ..

#######################
# Copying
#######################

cp -rf $GLOBAL_OUTDIR/include .
mkdir -p lib
cp -rf $GLOBAL_OUTDIR/lib/libtesseract_all.a $GLOBAL_OUTDIR/lib/liblept.a lib/

echo "Finished!"

6.为build.sh增加可执行权限:

chmod a+x build.sh

7.终端中运行build.sh

运行结束后会在文件夹compile_code中的lib文件夹中生成两个*.a文件,include文件夹中生成头文件,这两个文件夹引入工程中即可使用该框架了。

四. iOS上的tesseract实现

/*
 *  tesseract.h(来源网上)
 */
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface Tesseract : NSObject {
    // OCR识别库
    NSString* _dataPath;
    // 需要识别的语言
    NSString* _language;
    // tesseract参数
    NSMutableDictionary* _variables;
}

+ (NSString *)version;
/**
 *  设置OCR识别参数
 *
 *  @param dataPath OCR识别库
 *  @param language 所选用的语言
 */
- (id)initWithDataPath:(NSString *)dataPath language:(NSString *)language;

- (void)setVariableValue:(NSString *)value forKey:(NSString *)key;
/**
 *  设置识别的图片
 *
 *  @param image 需要识别的图片
 */
- (void)setImage:(UIImage *)image;
/**
 *  OCR识别语言设置
 *
 *  @param language 需要识别的语言
 */
- (BOOL)setLanguage:(NSString *)language;

- (BOOL)recognize;

- (NSString *)recognizedText;

@end

/*
 *  tesseract.mm
 */

#import "Tesseract.h"
#import "baseapi.h"
#import "environ.h"
#import "pix.h"

namespace tesseract {
    class TessBaseAPI;
};

@interface Tesseract () {
    tesseract::TessBaseAPI* _tesseract;
    // 转换为二进制的图片数据
    uint32_t* _pixels;
}

@end

@implementation Tesseract

/**
 *  获取版本信息
 */
+ (NSString *)version {
    return [NSString stringWithFormat:@"%s", tesseract::TessBaseAPI::Version()];
}

/**
 *  设置参数
 *
 *  @param dataPath 黑白名单设置
 *  @param language 所选用的语言
 */
- (id)initWithDataPath:(NSString *)dataPath language:(NSString *)language {
    self = [super init];
    if (self) {
        _dataPath = dataPath;
        _language = language;
        _variables = [[NSMutableDictionary alloc] init];
        
        [self copyDataToDocumentsDirectory];
        _tesseract = new tesseract::TessBaseAPI();
        
        BOOL success = [self initEngine];
        if (!success) {
            return nil;
        }
    }
    return self;
}

/**
 *  初始化tesseract识别
 */
- (BOOL)initEngine {
    int returnCode = _tesseract->Init([_dataPath UTF8String], [_language UTF8String]);
    return (returnCode == 0) ? YES : NO;
}

/**
 *  将识别库拷贝至 Documents 文件夹
 */
- (void)copyDataToDocumentsDirectory {
    
    // 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 bundleForClass:[self class]] bundlePath];
        NSString *tessdataPath = [bundlePath stringByAppendingPathComponent:_dataPath];
        if (tessdataPath) {
            [fileManager createDirectoryAtPath:documentPath withIntermediateDirectories:YES attributes:nil error:NULL];
            [fileManager copyItemAtPath:tessdataPath toPath:dataPath error:nil];
        }
    }
    
    setenv("TESSDATA_PREFIX", [[documentPath stringByAppendingString:@"/"] UTF8String], 1);
}

/**
 *  设置OCR识别参数
 *
 *  @param value OCR识别参数属性
 *  @param key   OCR识别参数键值(参考Tesseract源代码:contrib/dump.config)
 */
- (void)setVariableValue:(NSString *)value forKey:(NSString *)key {
    /*
     * Example:
     * _tesseract->SetVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
     * _tesseract->SetVariable("language_model_penalty_non_freq_dict_word", "0");
     * _tesseract->SetVariable("language_model_penalty_non_dict_word ", "0");
     */
    
    [_variables setValue:value forKey:key];
    _tesseract->SetVariable([key UTF8String], [value UTF8String]);
}

/**
 *  重新设置OCR识别参数
 */
- (void)loadVariables {
    for (NSString* key in _variables) {
        NSString* value = [_variables objectForKey:key];
        _tesseract->SetVariable([key UTF8String], [value UTF8String]);
    }
}

/**
 *  设置识别语言
 */
- (BOOL)setLanguage:(NSString *)language {
    _language = language;
//    int returnCode = [self initEngine];
//    if (returnCode != 0) return NO;
    
    /*
     * "WARNING: On changing languages, all Tesseract parameters
     * are reset back to their default values."
     */
    [self loadVariables];
    return YES;
}

/**
 *  OCR识别
 *
 *  @return 识别是否成功
 */
- (BOOL)recognize {
    int returnCode = _tesseract->Recognize(NULL);
    return (returnCode == 0) ? YES : NO;
}

/**
 *  OCR识别
 *
 *  @return 识别出来的文本
 */
- (NSString *)recognizedText {
    char* utf8Text = _tesseract->GetUTF8Text();
    return [NSString stringWithUTF8String:utf8Text];
}

/**
 *  设置识别的图片
 *
 *  @param image 需要识别的图片
 */
- (void)setImage:(UIImage *)image
{
    free(_pixels);
    
    CGSize size = [image size];
    int width = size.width;
    int height = size.height;
    
    if (width <= 0 || height <= 0) {
        return;
    }
    
    _pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t));
    
    // 清空图片缓存数组
    memset(_pixels, 0, width * height * sizeof(uint32_t));
    
    // 申请RGA图片缓存
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    // 申请 _pixels 图片上下文
    CGContextRef context = CGBitmapContextCreate(_pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);
    
    // 向上下文填充二进制图片数据(该数据会填充到_pixels数组中)
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [image CGImage]);
    
    // 释放上下文与颜色空间
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    
    // 传递图片给 Tesseract 库
    _tesseract->SetImage((const unsigned char *) _pixels, width, height, sizeof(uint32_t), width * sizeof(uint32_t));
}

-(void)dealloc{
    // 关闭tesseract
    _tesseract->End();
}

@end


    Tesseract* tesseract = [[Tesseract alloc] initWithDataPath:@"tessdata" language:@"eng"];
    self.tesseract = tesseract;

    // tesseract参数
//    [tesseract setVariableValue:@"textord_words_default_minspace" forKey:@"0.2"];
//    [tesseract setVariableValue:@"textord_words_width_ild" forKey:@"0.4"];
    
    // 设置需要识别的图片
    UIImage *image = [UIImage imageNamed:@"Capture2.png"];
    UIImage *conImage = image;
    
    // 图像预处理
    conImage = [UIImage convertToGrayscale:conImage];
    conImage = [conImage sharpen];
    conImage = [UIImage grayImage:conImage];

    // 显示图片
    self.imageView.image = image;
    self.conImageView.image = conImage;
    [self.tesseract setImage:conImage];
    [self.tesseract recognize];
    
    NSLog(@"%@", [self.tesseract recognizedText]);
    [self.tesseract setImage:nil];


五. tesseract小结

     网上的一些资料都感觉很古老,很陈旧了,编写这部分代码什么的也弄了2天多的时间。程序现在感觉还是有些问题,但是起码可以识别一些效果比较好的英文了。有时间还会继续研究。个人认为,后续的研究应该就是图像预处理的部分了,有熟悉的大师也可以帮助一下。互勉,共同进步。

网上感觉不错的例子:https://github.com/gali8/Tesseract-OCR-iOS或者http://code4app.com/ios/Tesseract-OCR/533d7ada933bf024048b4c8b

一些简单的图像处理函数:http://pan.baidu.com/share/link?shareid=1816900461&uk=218547027(自己网上摘的)

按照网上的说法,tesseract识别的关键点在于字典训练还有图片预处理,因此后续研究方向估计就是图片预处理这部分了。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值