Putting this together took a lot of trial-and-error. Here are the steps... just in case.
-
Create a static cocoa touch lib (iOS)
-
Add all of the
*.cc
and*.h
files from clstm -
Add the
clstm.proto
from clstm -
Add in the headers by adding
Eigen
andunsupported
folders into the project (these came from mybrew
installation at/usr/local/include/eigen3/
) -
Add
$(PROJECT_ROOT)
to the header search paths (so it can find those Eigen headers) -
Add
macros.h
#ifndef macros_h #define macros_h #define THROW throw #define TRY try #define CATCH catch #define NODISPLAY 1 #define CLSTM_ALL_TENSOR 1 #endif /* macros_h */
-
Set a return value for
print_usage
inclstmocr.cc
andclstmtrain.cc
return 0;
-
include
macros.h
in all of the failing files (pstring.h
,tensor.h
,utils.h
) -
In
extras.cc
you need to change:#include <png.h>
to
#include "png.h"
-
Include libpng via cocoapods, and in pngpriv.h comment out:
// #ifndef PNG_ARM_NEON_OPT // ... // #endif
And add in:
#define PNG_ARM_NEON_OPT 0
-
Set
ENABLE_BITCODE
toNO
in the project settings
Follow this guide: https://gist.github.com/jeffrafter/e00601fdbce17add0f9e0a06d4e69aec
You'll endup with a compiled protobuf library (2.6.1) which is compatible with clstm
(it is not built for 3.x):
- Copy the
google
folder frominclude
into your project. - Copy the
protoc
binary (inbin
) into your project - Copy the
libprotobuf.a
into your project under a Frameworks group. - Make sure that the lib is added to
Build Phases
. - Add
clstm.proto
to the compile sources: - Add in the
protoc
build rule:
echo ${SRCROOT}/protoc
cd ${INPUT_FILE_DIR}
${SRCROOT}/clstm/protoc --proto_path=${INPUT_FILE_DIR} ${INPUT_FILE_PATH} --cpp_out=${SRCROOT}/clstm
In order to use this from a briding header, it is easiest to create a C function that calls the C++. Add a clstmocr.cpp
and clstmocr.hpp
. This also allows us to hide the internals of protobufs, Eigen and friends from the project that includes the build lib.
//
// clstmocr.cpp
// clstm
//
// Created by Jeffrey Rafter and Tyler Davis on 1/24/17.
// Copyright © 2017 Jeffrey Rafter and Tyler Davis. All rights reserved.
//
#include "clstmocr.hpp"
#include "clstm.h"
#include "clstmhl.h"
#include <time.h>
// extern "C" will cause the C++ compiler
// (remember, this is still C++ code!) to
// compile the function in such a way that
// it can be called from C
// (and Swift).
extern "C" const char * clstm_recognize(const char * model_file_name, const char * image_file_name)
{
ocropus::Tensor2 raw;
ocropus::CLSTMOCR clstm;
clock_t start, end;
double cpu_load_time, cpu_png_time, cpu_predict_time;
// Load the model
start = clock();
clstm.load(std::string(model_file_name));
end = clock();
cpu_load_time = ((double) (end - start)) / CLOCKS_PER_SEC;
// Read the image
start = clock();
read_png(raw, image_file_name);
raw() = -raw() + ocropus::Float(1.0);
end = clock();
cpu_png_time = ((double) (end - start)) / CLOCKS_PER_SEC;
// Convert to text
start = clock();
std::string out = clstm.predict_utf8(raw());
end = clock();
cpu_predict_time = ((double) (end - start)) / CLOCKS_PER_SEC;
// If you want timing
// out = out + "(load: " + std::to_string(cpu_load_time) + ", png: " + std::to_string(cpu_png_time) + ", predict: " + std::to_string(cpu_predict_time) + ")";
char * ret = new char[out.length() + 1];
std:strcpy(ret, out.c_str());
return ret;
}
This is essentially a copy of the clstmocr
calls. We've changed all of the input calls to use const char *
so it is easier to interact with externally.
//
// clstmocr.hpp
// clstm
//
// Created by Jeffrey Rafter and Tyler Davis on 1/24/17.
// Copyright © 2017 Jeffrey Rafter and Tyler Davis. All rights reserved.
//
#ifndef clstmocr_hpp
#define clstmocr_hpp
#include <stdio.h>
extern "C" const char * clstm_recognize(const char * model_file_name, const char * image_file_name);
#endif /* clstmocr_hpp */