Конфликт Libtorch и OpenCV

Система Ubuntu 24; IDE CLion. При попытке запустить код, использующий OpenCV и Libtorch, возникают следующие ошибки:

main.cpp:34:(.text+0xa28): undefined reference to `cv::putText(cv::_InputOutputArray const&, std::string const&, cv::Point_<int>, int, double, cv::Scalar_<double>, int, int, bool)'
main.cpp:45:(.text+0xbb1): undefined reference to `cv::VideoCapture::VideoCapture(std::string const&, int)'
main.cpp:64:(.text+0xe04): undefined reference to `cv::imshow(std::string const&, cv::_InputArray const&)'

Пикантность ситуации заключается в том, что приложение, зависящее исключительно от OpenCV (и использующее вышеперечисленные функции) работает без проблем. Также без проблем запускается приложение, использующее исключительно Libtorch. Это происходит в одном и том же проекте, различается код (очевидно) и CMake lists.

Пример CMake с которым работает чисто-OpenCV приложение:

cmake_minimum_required(VERSION 3.28)
project(libtorch)

find_package (OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
set(CMAKE_CXX_STANDARD 17)

add_executable(libtorch main.cpp)
target_link_libraries(libtorch ${OpenCV_LIBS})

Пример CMake с которым работает чисто-Libtorch приложение:

cmake_minimum_required(VERSION 3.28)
project(libtorch)

find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")

add_executable(libtorch main.cpp)
target_link_libraries(libtorch "${TORCH_LIBRARIES}")
set_property(TARGET libtorch PROPERTY CXX_STANDARD 17)

Пример CMake с которым вылезают ошибки в смешанном приложении:

cmake_minimum_required(VERSION 3.28)
project(libtorch)

find_package (OpenCV REQUIRED)
find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")

add_executable(libtorch main.cpp)
target_link_libraries(libtorch ${OpenCV_LIBS})
target_link_libraries(libtorch "${TORCH_LIBRARIES}")
set_property(TARGET libtorch PROPERTY CXX_STANDARD 17)

Это происходит в одном и том же проекте. В CLion стоит флаг -DCMAKE_PREFIX_PATH=/usr/include/libtorch/share/cmake/Torch/.

OpenCV код который работает без ошибок:

#include <opencv2/opencv.hpp>
#include <iostream>

const std::string videoPath = "path";

void preprocessFrame(cv::Mat& frame) {
    cv::resize(frame, frame, cv::Size(240, 160));
}

void applyBackgroundSubtraction(cv::Mat& frame, cv::Ptr<cv::BackgroundSubtractor>& bgSubtractor, cv::Mat& fgMask) {
    bgSubtractor->apply(frame, fgMask);
}

void applyNoiseReduction(cv::Mat& fgMask) {
    cv::GaussianBlur(fgMask, fgMask, cv::Size(15, 15), 0);

    cv::erode(fgMask, fgMask, cv::Mat(), cv::Point(-1, -1), 2);
    cv::dilate(fgMask, fgMask, cv::Mat(), cv::Point(-1, -1), 2);
}

int main() {
    cv::VideoCapture cap(videoPath);
    if (!cap.isOpened()) {
        std::cerr << "Error: Could not open the video file!" << std::endl;
        return -1;
    }

    cv::Ptr<cv::BackgroundSubtractor> bgSubtractor = cv::createBackgroundSubtractorKNN(100, 2000, false);

    cv::Mat frame, fgMask;

    while (cap.read(frame)) {
        if (frame.empty()) break;

        preprocessFrame(frame);
        applyBackgroundSubtraction(frame, bgSubtractor, fgMask);
        applyNoiseReduction(fgMask);
        cv::imshow("Foreground Mask (Noise Reduced)", fgMask);
        if (cv::waitKey(30) == 27) break;
    }

    cap.release();
    cv::destroyAllWindows();

    return 0;
}

Смешанный код который возвращает ошибки:

#include <torch/script.h>
#include <opencv2/opencv.hpp>
#include <iostream>

const int INPUT_WIDTH = 320;
const int INPUT_HEIGHT = 320;
const float SCORE_THRESHOLD = 0.5;
const float NMS_THRESHOLD = 0.5;
const int PERSON_CLASS_ID = 1;
const std::string VIDEO_PATH = "path";
const std::string MODEL_PATH = "ssdlite320_mobilenet_v3_large.pt";

torch::Tensor preprocess_image(cv::Mat& image) {
    cv::Mat resized;
    resize(image, resized, cv::Size(INPUT_WIDTH, INPUT_HEIGHT));
    cvtColor(resized, resized, cv::COLOR_BGR2RGB);

    torch::Tensor tensor_image = torch::from_blob(resized.data, {1, INPUT_HEIGHT, INPUT_WIDTH, 3}, torch::kByte);
    tensor_image = tensor_image.permute({0, 3, 1, 2});
    tensor_image = tensor_image.toType(torch::kFloat);
    tensor_image = tensor_image.div(255);
    return tensor_image;
}

void draw_predictions(cv::Mat& image, const torch::Tensor& predictions) {
    auto pred_accessor = predictions.accessor<float, 2>();
    for (int i = 0; i < predictions.size(0); ++i) {
        if (pred_accessor[i][5] == PERSON_CLASS_ID && pred_accessor[i][4] > SCORE_THRESHOLD) {
            int x1 = static_cast<int>(pred_accessor[i][0] * image.cols);
            int y1 = static_cast<int>(pred_accessor[i][1] * image.rows);
            int x2 = static_cast<int>(pred_accessor[i][2] * image.cols);
            int y2 = static_cast<int>(pred_accessor[i][3] * image.rows);
            rectangle(image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0), 2);
            putText(image, "Person", cv::Point(x1, y1 - 10),
                        cv::FONT_HERSHEY_SIMPLEX, 0.9, cv::Scalar(0, 255, 0), 2);
        }
    }
}

int main() {

    torch::jit::script::Module model = torch::jit::load(MODEL_PATH);
    model.eval();

    cv::VideoCapture cap(VIDEO_PATH);
    if (!cap.isOpened()) {
        std::cerr << "Error opening video file" << std::endl;
        return -1;
    }

    cv::Mat frame;
    while (cap.read(frame)) {

        torch::Tensor input_tensor = preprocess_image(frame);

        std::vector<torch::jit::IValue> inputs;
        inputs.push_back(input_tensor);
        torch::Tensor output = model.forward(inputs).toTensor();

        torch::Tensor predictions = output.squeeze().detach();

        draw_predictions(frame, predictions);

        imshow("Person Detection", frame);

        if (cv::waitKey(1) == 27) break;

    }

    cap.release();
    cv::destroyAllWindows();
    return 0;
}

Ответы (1 шт):

Автор решения: dahoonpao

Неправильная форма тензоров для модели TorchScript: Возможно, что тензор, передаваемый в модель, имеет неправильные размеры, особенно если модель ожидает определённый формат (например, наличие батчей), в вашем коде может быть проблема с батчированием данных, ещё возможна проблема с типами данных в Torch: При загрузке данных могут быть ошибки типа данных, так как OpenCV использует uchar для изображений, а Torch ожидает float, вы делаете приведение к float, но модель может требовать других манипуляций с тензорами.

Предсказания модели могут возвращать другой формат: Вы используете predictions.accessor<float, 2>(), но нужно проверить, действительно ли вывод модели соответствует ожидаемому формату. А ещё Torch не поддерживает GPU, если не использовать CUDA (если это необходимо): Убедитесь, что модель и данные загружаются на правильное устройство (CPU или GPU).

→ Ссылка