forked from apache/mxnet
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
1,319 additions
and
230 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Special thanks to https://github.com/pertusa for the Makefile | ||
CFLAGS=-std=c++11 -Wno-unknown-pragmas -Wall | ||
|
||
# Added for openblas | ||
# export OPENBLAS_ROOT=/usr/local/opt/openblas | ||
|
||
# CFLAGS+= -I${OPENBLAS_ROOT}/include | ||
# LDFLAGS=-L${OPENBLAS_ROOT}/lib -lopenblas | ||
|
||
# Added for opencv | ||
CFLAGS+= `pkg-config --cflags opencv` | ||
LDFLAGS+=`pkg-config --libs opencv` | ||
|
||
# Added for mxnet | ||
export MXNET_ROOT=`pwd`/../../../../mxnet | ||
|
||
CFLAGS+= -I$(MXNET_ROOT)/include | ||
LDFLAGS+=$(MXNET_ROOT)/lib/libmxnet.so | ||
|
||
image-classification-predict: image-classification-predict.o | ||
g++ -O3 -o image-classification-predict image-classification-predict.o $(LDFLAGS) | ||
|
||
image-classification-predict.o: image-classification-predict.cc | ||
g++ -O3 -c image-classification-predict.cc ${CFLAGS} | ||
|
||
clean: | ||
rm image-classification-predict | ||
rm -f *.d *.o | ||
|
||
lint: | ||
python ../../../dmlc-core/scripts/lint.py mxnet "cpp" ./ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Image Classification Example of C++ | ||
This is a simple predictor which shows how to use c api for image classfication. | ||
|
||
It uses opencv for image reading | ||
|
||
# How to Use | ||
|
||
## Build | ||
1. Edit image-classification-predict.cc file, change the following lines to your model paths: | ||
```bash | ||
// Models path for your model, you have to modify it | ||
BufferFile json_data("model/Inception/Inception_BN-symbol.json"); | ||
BufferFile param_data("model/Inception/Inception_BN-0039.params"); | ||
``` | ||
|
||
2. Edit synset file path if you have it: | ||
```bash | ||
// Synset path for your model, you have to modify it | ||
std::vector<std::string> synset = LoadSynset("model/Inception/synset.txt"); | ||
``` | ||
|
||
3. You may also want to change the image size and channels: | ||
```bash | ||
// Image size and channels | ||
int width = 224; | ||
int height = 224; | ||
int channels = 3; | ||
``` | ||
|
||
4. Simply just use our Makefile to build: | ||
```bash | ||
make | ||
``` | ||
|
||
## Usage | ||
* Run: | ||
```bash | ||
./image-classification-predict apple.jpg | ||
``` | ||
The only parameter is the path of the test image. | ||
|
||
## Tips | ||
* The model used in the sample can be downloaded here: | ||
http://pan.baidu.com/s/1sjXKrqX | ||
|
||
* If you donot run it in the mxnet root path, maybe you will need to copy lib folder here. | ||
|
||
# Author | ||
* **Xiao Liu** | ||
|
||
* E-mail: [email protected] | ||
|
||
* Homepage: [www.liuxiao.org](http://www.liuxiao.org/) | ||
|
||
# Thanks | ||
* pertusa (for Makefile and image reading check) | ||
|
||
* caprice-j (for reading function) | ||
|
||
* sofiawu (for sample model) | ||
|
||
* piiswrong and tqchen (for useful coding suggestions) | ||
|
||
|
237 changes: 237 additions & 0 deletions
237
example/cpp/image-classification/image-classification-predict.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
/*! | ||
* Copyright (c) 2015 by Xiao Liu, pertusa, caprice-j | ||
* \file image_classification-predict.cpp | ||
* \brief C++ predict example of mxnet | ||
*/ | ||
|
||
// | ||
// File: image-classification-predict.cpp | ||
// This is a simple predictor which shows | ||
// how to use c api for image classfication | ||
// It uses opencv for image reading | ||
// Created by liuxiao on 12/9/15. | ||
// Thanks to : pertusa, caprice-j, sofiawu, tqchen, piiswrong | ||
// Home Page: www.liuxiao.org | ||
// E-mail: [email protected] | ||
// | ||
|
||
#include <stdio.h> | ||
|
||
// Path for c_predict_api | ||
#include <mxnet/c_predict_api.h> | ||
|
||
#include <opencv2/core/core.hpp> | ||
#include <opencv2/contrib/contrib.hpp> | ||
#include <opencv2/highgui/highgui.hpp> | ||
|
||
#include <iostream> | ||
#include <fstream> | ||
#include <string> | ||
#include <vector> | ||
|
||
// Read file to buffer | ||
class BufferFile { | ||
public : | ||
std::string file_path_; | ||
int length_; | ||
char* buffer_; | ||
|
||
explicit BufferFile(std::string file_path) | ||
:file_path_(file_path) { | ||
|
||
std::ifstream ifs(file_path.c_str(), std::ios::in | std::ios::binary); | ||
if (!ifs) { | ||
std::cerr << "Can't open the file. Please check " << file_path << ". \n"; | ||
assert(false); | ||
} | ||
|
||
ifs.seekg(0, std::ios::end); | ||
length_ = ifs.tellg(); | ||
ifs.seekg(0, std::ios::beg); | ||
std::cout << file_path.c_str() << " ... "<< length_ << " bytes\n"; | ||
|
||
buffer_ = new char[sizeof(char) * length_]; | ||
ifs.read(buffer_, length_); | ||
ifs.close(); | ||
} | ||
|
||
int GetLength() { | ||
return length_; | ||
} | ||
char* GetBuffer() { | ||
return buffer_; | ||
} | ||
|
||
~BufferFile() { | ||
delete[] buffer_; | ||
buffer_ = NULL; | ||
} | ||
}; | ||
|
||
void GetMeanFile(const std::string image_file, mx_float* image_data, | ||
const int channels, const cv::Size resize_size) { | ||
// Read all kinds of file into a BGR color 3 channels image | ||
cv::Mat im_ori = cv::imread(image_file, 1); | ||
|
||
if (im_ori.empty()) { | ||
std::cerr << "Can't open the image. Please check " << image_file << ". \n"; | ||
assert(false); | ||
} | ||
|
||
cv::Mat im; | ||
|
||
resize(im_ori, im, resize_size); | ||
|
||
// Better to be read from a mean.nb file | ||
float mean = 117.0; | ||
|
||
int size = im.rows * im.cols * 3; | ||
|
||
mx_float* ptr_image_r = image_data; | ||
mx_float* ptr_image_g = image_data + size / 3; | ||
mx_float* ptr_image_b = image_data + size / 3 * 2; | ||
|
||
for (int i = 0; i < im.rows; i++) { | ||
uchar* data = im.ptr<uchar>(i); | ||
|
||
for (int j = 0; j < im.cols; j++) { | ||
mx_float b = static_cast<mx_float>(*data++) - mean; | ||
mx_float g = static_cast<mx_float>(*data++) - mean; | ||
mx_float r = static_cast<mx_float>(*data++) - mean; | ||
|
||
*ptr_image_r++ = r; | ||
*ptr_image_g++ = g; | ||
*ptr_image_b++ = b; | ||
} | ||
} | ||
} | ||
|
||
// LoadSynsets | ||
// Code from : https://github.com/pertusa/mxnet_predict_cc/blob/master/mxnet_predict.cc | ||
std::vector<std::string> LoadSynset(const char *filename) { | ||
std::ifstream fi(filename); | ||
|
||
if ( !fi.is_open() ) { | ||
std::cerr << "Error opening file " << filename << std::endl; | ||
assert(false); | ||
} | ||
|
||
std::vector<std::string> output; | ||
|
||
std::string synset, lemma; | ||
while ( fi >> synset ) { | ||
getline(fi, lemma); | ||
output.push_back(lemma); | ||
} | ||
|
||
fi.close(); | ||
|
||
return output; | ||
} | ||
|
||
void PrintOutputResult(const std::vector<float>& data, const std::vector<std::string>& synset) { | ||
if (data.size() != synset.size()) { | ||
std::cerr << "Result data and synset size does not match!" << std::endl; | ||
} | ||
|
||
float best_accuracy = 0.0; | ||
int best_idx = 0; | ||
|
||
for ( int i = 0; i < static_cast<int>(data.size()); i++ ) { | ||
printf("Accuracy[%d] = %.8f\n", i, data[i]); | ||
|
||
if ( data[i] > best_accuracy ) { | ||
best_accuracy = data[i]; | ||
best_idx = i; | ||
} | ||
} | ||
|
||
printf("Best Result: [%s] id = %d, accuracy = %.8f\n", | ||
synset[best_idx].c_str(), best_idx, best_accuracy); | ||
} | ||
|
||
int main(int argc, char* argv[]) { | ||
if (argc < 2) { | ||
std::cout << "No test image here." << std::endl | ||
<< "Usage: ./image-classification-predict apple.jpg" << std::endl; | ||
return 0; | ||
} | ||
|
||
std::string test_file; | ||
test_file = std::string(argv[1]); | ||
|
||
// Models path for your model, you have to modify it | ||
BufferFile json_data("model/Inception/Inception_BN-symbol.json"); | ||
BufferFile param_data("model/Inception/Inception_BN-0039.params"); | ||
|
||
// Parameters | ||
int dev_type = 1; // 1: cpu, 2: gpu | ||
int dev_id = 0; // arbitrary. | ||
mx_uint num_input_nodes = 1; // 1 for feedforward | ||
const char* input_key[1] = {"data"}; | ||
const char** input_keys = input_key; | ||
|
||
// Image size and channels | ||
int width = 224; | ||
int height = 224; | ||
int channels = 3; | ||
|
||
const mx_uint input_shape_indptr[2] = { 0, 4 }; | ||
// ( trained_width, trained_height, channel, num) | ||
const mx_uint input_shape_data[4] = { 1, | ||
static_cast<mx_uint>(channels), | ||
static_cast<mx_uint>(width), | ||
static_cast<mx_uint>(height) }; | ||
PredictorHandle out = 0; // alias for void * | ||
|
||
//-- Create Predictor | ||
MXPredCreate((const char*)json_data.GetBuffer(), | ||
(const char*)param_data.GetBuffer(), | ||
static_cast<size_t>(param_data.GetLength()), | ||
dev_type, | ||
dev_id, | ||
num_input_nodes, | ||
input_keys, | ||
input_shape_indptr, | ||
input_shape_data, | ||
&out); | ||
|
||
// Just a big enough memory 1000x1000x3 | ||
int image_size = width * height * channels; | ||
std::vector<mx_float> image_data = std::vector<mx_float>(image_size); | ||
|
||
//-- Read Mean Data | ||
GetMeanFile(test_file, image_data.data(), channels, cv::Size(width, height)); | ||
|
||
//-- Set Input Image | ||
MXPredSetInput(out, "data", image_data.data(), image_size); | ||
|
||
//-- Do Predict Forward | ||
MXPredForward(out); | ||
|
||
mx_uint output_index = 0; | ||
|
||
mx_uint *shape = 0; | ||
mx_uint shape_len; | ||
|
||
//-- Get Output Result | ||
MXPredGetOutputShape(out, output_index, &shape, &shape_len); | ||
|
||
size_t size = 1; | ||
for (mx_uint i = 0; i < shape_len; ++i) size *= shape[i]; | ||
|
||
std::vector<float> data(size); | ||
|
||
MXPredGetOutput(out, output_index, &(data[0]), size); | ||
|
||
// Release Predictor | ||
MXPredFree(out); | ||
|
||
// Synset path for your model, you have to modify it | ||
std::vector<std::string> synset = LoadSynset("model/Inception/synset.txt"); | ||
|
||
//-- Print Output Data | ||
PrintOutputResult(data, synset); | ||
|
||
return 0; | ||
} |
Oops, something went wrong.