I'm writing a custom operation for Tensorflow that is supposed to load a video. For this, I need to include OpenCV.
For now, the operation simply tries to open a VideoCapture and returns an empty tensor.
Here's the C++ code:
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/shape_inference.h"
#include "tensorflow/core/framework/op_kernel.h"
#include <iostream>
using namespace tensorflow;
using namespace cv;
using namespace std;
using shape_inference::ShapeHandle;
using shape_inference::DimensionHandle;
REGISTER_OP("LoadVideo")
.Input("filename: string")
.Output("frame: float32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
TensorShape outputTensorShape({224, 224, 3});
ShapeHandle outputShapeHandle;
c->MakeShapeFromTensorShape(outputTensorShape, &outputShapeHandle);
c->set_output(0, outputShapeHandle);
return Status::OK();
});
class LoadVideoOp : public OpKernel {
public:
explicit LoadVideoOp(OpKernelConstruction* context) : OpKernel(context) {}
void Compute(OpKernelContext* context) override {
// Grab the input tensor
const Tensor& input_tensor = context->input(0);
auto input = input_tensor.flat<string>();
string filename = input(0);
VideoCapture cap = VideoCapture("data/0eRkpTGq5pA.mp4");
Tensor* output_tensor = NULL;
OP_REQUIRES_OK(context, context->allocate_output(0, {224, 224, 3}, &output_tensor));
}
};
REGISTER_KERNEL_BUILDER(Name("LoadVideo").Device(DEVICE_CPU), LoadVideoOp);
Then, I use the following command to compile the code:
g++ -std=c++11 -shared -fPIC \
-I /home/master/anaconda3/envs/tf/lib/python3.6/site-packages/tensorflow/include \
-I ~/anaconda3/envs/tf/include/opencv2/ -I ~/anaconda3/envs/tf/include/opencv/ -O2 \
-L ~/anaconda3/envs/tf/lib \
load_video.cc -o load_video.so \
-lopencv_core -lopencv_videoio -lopencv_highgui \
-lopencv_imgproc -lopencv_video -lopencv_objdetect
When I load the compiled code into a Python script (using tf.load_op_library) and try to run the op I get the following error:
tensorflow.python.framework.errors_impl.NotFoundError: lib/ops/load_video.so: undefined symbol: _ZN2cv12VideoCaptureC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
It looks like the compiled C++ code cannot access the appropriate OpenCV object. I don't know much about C++ compilation and linking, so the problem probably is that I'm compiling the custom op in a wrong way.
Could you please help me compile the op in such way, that it can be successfully loaded and run by tensorflow?
EDIT 1:
This is the Python script I use to load the custom op:
import tensorflow as tf
load_video_module = tf.load_op_library('lib/ops/load_video.so')
with tf.Session():
x = load_video_module.load_video("data/0eRkpTGq5pA.mp4").eval()
print(x)
The error happens on the line 2 (i.e. when trying to load the compiled C++ code).
Solution:
I managed to successfully compile and run the custom tensorflow op after rebuilding OpenCV. The compilation command is:
g++ -std=c++11 -ggdb -shared -I`python -c 'import tensorflow as tf; print(tf.sysconfig.get_include())'` `pkg-config --cflags opencv` -o load_video.so load_video.cc `pkg-config --libs opencv` -fPIC