Как передать Matrix OpenCV в граф Tensorflow С++?

В Tensorflow С++ я могу загрузить файл изображения в граф, используя

tensorflow::Node* file_reader =  tensorflow::ops::ReadFile(tensorflow::ops::Const(IMAGE_FILE_NAME, b.opts()),b.opts().WithName(input_name));
tensorflow::Node* image_reader = tensorflow::ops::DecodePng(file_reader, b.opts().WithAttr("channels", 3).WithName("png_reader"));
tensorflow::Node* float_caster = tensorflow::ops::Cast(image_reader, tensorflow::DT_FLOAT, b.opts().WithName("float_caster"));
tensorflow::Node* dims_expander = tensorflow::ops::ExpandDims(float_caster, tensorflow::ops::Const(0, b.opts()), b.opts());
tensorflow::Node* resized = tensorflow::ops::ResizeBilinear(dims_expander, tensorflow::ops::Const({input_height, input_width},b.opts().WithName("size")),b.opts());

Для встроенного приложения я хотел бы вместо этого передать Matrix OpenCV в этот граф.

Как бы преобразовать Mat в тензор, который можно было бы использовать в качестве входных данных для тензорного потока:: ops:: Cast или tensorflow:: ops:: ExpandDims?

Ответ 1

Это не непосредственно из CvMat, но вы можете увидеть пример инициализации тензора из массива в памяти в примере Android TensorFlow: https://github.com/tensorflow/tensorflow/blob/0.6.0/tensorflow/examples/android/jni/tensorflow_jni.cc#L173

Вы начали бы с создания нового объекта tensorflow:: Tensor, с чем-то вроде этого (весь код не тестировался):

tensorflow::Tensor input_tensor(tensorflow::DT_FLOAT, tensorflow::TensorShape({1, height, width, depth}));

Это создает объект Tensor со значениями float с размером партии 1 и размером width x height и с каналами depth. Например, изображение шириной 128 на 64 кадра с тремя каналами будет проходить в форме {1, 64, 128, 3}. Размер партии используется только тогда, когда вам нужно передать несколько изображений за один вызов, а для простых целей вы можете оставить его как 1.

Затем вы получите базовый массив за тензором, используя следующую строку:

auto input_tensor_mapped = input_tensor.tensor<float, 4>();

Объект input_tensor_mapped является интерфейсом к данным в вашем новом тензоре, и вы можете затем скопировать свои собственные данные в него. Здесь я предполагаю, что вы установили source_data в качестве указателя на ваши исходные данные, например:

const float* source_data = some_structure.imageData;

Затем вы можете прокручивать свои данные и копировать их:

for (int y = 0; y < height; ++y) {
    const float* source_row = source_data + (y * width * depth);
    for (int x = 0; x < width; ++x) {
        const float* source_pixel = source_row + (x * depth);
        for (int c = 0; c < depth; ++c) {
           const float* source_value = source_pixel + c;
           input_tensor_mapped(0, y, x, c) = *source_value;
        }
    }
}

Есть очевидные возможности для оптимизации этого наивного подхода, и у меня нет примера кода, чтобы показать, как работать с частью OpenCV для получения исходных данных, но, надеюсь, это поможет вам начать работу.

Ответ 2

Я попытался запустить начальную модель в файле opencv Mat и следующий код работал у меня https://gist.github.com/kyrs/9adf86366e9e4f04addb. Хотя есть некоторые проблемы с интеграцией opencv и tensorflow. Код работал без каких-либо проблем для файлов .png, но не смог загрузить .jpg и .jpeg. Вы можете следить за этим для получения дополнительной информации https://github.com/tensorflow/tensorflow/issues/1924