Конфликт 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 шт):
Неправильная форма тензоров для модели TorchScript: Возможно, что тензор, передаваемый в модель, имеет неправильные размеры, особенно если модель ожидает определённый формат (например, наличие батчей), в вашем коде может быть проблема с батчированием данных, ещё возможна проблема с типами данных в Torch: При загрузке данных могут быть ошибки типа данных, так как OpenCV использует uchar для изображений, а Torch ожидает float, вы делаете приведение к float, но модель может требовать других манипуляций с тензорами.
Предсказания модели могут возвращать другой формат: Вы используете predictions.accessor<float, 2>(), но нужно проверить, действительно ли вывод модели соответствует ожидаемому формату. А ещё Torch не поддерживает GPU, если не использовать CUDA (если это необходимо): Убедитесь, что модель и данные загружаются на правильное устройство (CPU или GPU).