Используйте TF_Tensor для создания множества изображений cv :: cuda :: GpuMat - PullRequest
0 голосов
/ 06 октября 2019

Я использую Tensorflow (TF) и его C API для написания пользовательского конвейера TF. Я загружаю изображения с помощью OpenCV, меняю их размер и нормализую (на процессоре с помощью cv :: Mat) и загружаю их в TF_Tensor (на графическом процессоре). Все это работает на удивление хорошо, и конвейер работает достаточно быстро.

Недавно я решил, что хочу еще большего ускорения и загрузки изображений непосредственно в память графического процессора, используя cv :: cuda:: GpuMat. Таким образом, нет ненужного копирования между процессором и графическим процессором. Снова, я заставил это работать - но только при загрузке единственного изображения за один раз. Мой вопрос: как мне загрузить целую серию изображений?

Пример кода для загрузки одного изображения:

void runGPUStuff(Session& session, Status& status)
{
    int rows = 359, cols = 240, newDim = 224;
    /* Dimensions {batchSize, with, height, numOfColors */
    std::vector<std::int64_t> dimensions{1, newDim, newDim, 1};
    TF_Tensor* tensorPtr = TF_AllocateTensor(
        TF_FLOAT,
        dimensions.data(),
        dimensions.size(),
        newDim * newDim * sizeof(float));
    auto gpuDataPtr = TF_TensorData(tensorPtr);
    /* I set the new GpuMat with the Tensor's pointer */
    GpuMat newGpuMat(rows, cols, CV_32FC1, gpuDataPtr);
    GpuMat oldGpuMat;

    oldGpuMat.upload(cv::imread(imagePath, cv::IMREAD_UNCHANGED));
    cv::cuda::resize(
        oldGpuMat, newGpuMat, cv::Size(224, 224), 0, 0, cv::INTER_CUBIC);
    cv::cuda::normalize(newGpuMat, newGpuMat, 1, 0, cv::NORM_MINMAX, CV_32FC1);

    Tensor inputTensor;
    inputTensor.setTensorPtr(tensorPtr);
    Tensor outputTensor;
    runSession(inputTensor, outputTensor, session, status);
}

Я пытаюсь заставить эту работу работать с двумя (и более поздними) изображениями,Вот моя попытка, которая не компилируется:

void runGPUStuff(Session& session, Status& status)
{
    int rows = 359, cols = 240, newDim = 224;
    /* Changing the batch size to two */
    std::vector<std::int64_t> dimensions{2, newDim, newDim, 1};
    TF_Tensor* tensorPtr = TF_AllocateTensor(
        TF_FLOAT,
        dimensions.data(),
        dimensions.size(),
        newDim * newDim * sizeof(float));
    auto gpuDataPtr = TF_TensorData(tensorPtr);
    GpuMat newGpuMat1(rows, cols, CV_32FC1, gpuDataPtr);
    /* The following line complains that "expression must be
    a pointer to a complete object type" */
    GpuMat newGpuMat2(rows, cols, CV_32FC1, gpuDataPtr + (newDim*newDim*sizeof(float)));
    GpuMat oldGpuMat;

    oldGpuMat.upload(cv::imread(imagePath, cv::IMREAD_UNCHANGED));
    cv::cuda::resize(
        oldGpuMat, newGpuMat1, cv::Size(224, 224), 0, 0, cv::INTER_CUBIC);
    cv::cuda::normalize(newGpuMat1, newGpuMat1, 1, 0, cv::NORM_MINMAX, CV_32FC1);

    Tensor inputTensor;
    inputTensor.setTensorPtr(tensorPtr);
    Tensor outputTensor;
    runSession(inputTensor, outputTensor, session, status);
}

Я думаю, что я действительно спрашиваю - как работает арифметика указателей на GPU? Если я выделяю TF_Tensor размером двух изображений, почему я не могу создать экземпляр второго GpuMat с указателем, который указывает на середину TF_Tensor?

...