Couldn't open CUDA library cupti64_80.dll 如何解决?

本文解决了TensorFlow运行时找不到cupti64_80.dll的问题,详细步骤包括检查CUDA文件夹,确认cupti64_80.dll存在,调整环境变量,将该DLL复制到CUDA8.0/bin目录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tensorflow在运行时的错误:
... Couldn't open CUDA library cupti64_80.dll
... Non-OK-status: status_ status: Failed precondition: could not dlopen DSO: cupti64_80.dll; dlerror: cupti64_80.dll not found

解决方法:

先查看CUDA文件夹下有没有cupti64_80.dll,一般是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v8.0\extras\CUPTI\libx64,你看,发现一只你要的东西!

然后查看环境变量,发现那个文件所在的文件夹没有在环境变量中,但是CUDA8.0/bin却在这里。

再来打开CUDA8.0/bin:

所以,把cupit64_80.dll复制到CUDA8.0/bin就好了!

// 在调试OCR时,崩溃了这里:error_code ORT_INVALID_ARGUMENT (2) OrtErrorCode D:\wzl\project\wzl_qt_work\third_party\onnxruntime-win-x64-1.22.0\include\onnxruntime_cxx_inline.h auto outs = cls_session_->Run(Ort::RunOptions{ nullptr }, &inName, &tensor, 1, &outName, 1); namespace detail { inline void ThrowStatus(const Status& st) { std::string error_message = st.GetErrorMessage(); OrtErrorCode error_code = st.GetErrorCode(); ORT_CXX_API_THROW(std::move(error_message), error_code); } } // namespace detail 堆栈: 3 Ort::detail::ThrowStatus onnxruntime_cxx_inline.h 39 0x7ff7d0958e31 4 Ort::ThrowOnError onnxruntime_cxx_inline.h 46 0x7ff7d0958d72 5 Ort::detail::SessionImpl<OrtSession>::Run onnxruntime_cxx_inline.h 1433 0x7ff7d0958c37 6 Ort::detail::SessionImpl<OrtSession>::Run onnxruntime_cxx_inline.h 1424 0x7ff7d0958b05 7 OcrService::needRotate OcrService.cpp 219 0x7ff7d0946e7b 8 OcrService::performOcr OcrService.cpp 58 0x7ff7d0944f34 9 Test::Test Test.cpp 45 0x7ff7d093fef4 10 main main.cpp 101 0x7ff7d093278f 11 qtEntryPoint qtentrypoint_win.cpp 45 0x7ff7d097d49a 12 WinMain qtentrypoint_win.cpp 64 0x7ff7d097d34e 控制台打印信息: det output shape: 1 1 640 640 probMap min/max: 0 1 contours found: 39 // D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.cpp #include "OcrService.h" #include <stdexcept> #include <filesystem> OcrService::OcrService(QString& model_dir_str) : env_(ORT_LOGGING_LEVEL_WARNING, "OcrService") { try { session_options_.SetIntraOpNumThreads(1); session_options_.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED); const std::filesystem::path model_dir(model_dir_str.toStdWString()); const auto det_path = model_dir / "det/det.onnx"; const auto cls_path = model_dir / "cls/cls.onnx"; const auto rec_path = model_dir / "rec/rec.onnx"; // 使用智能指针管理 Session 生命周期 det_session_ = std::make_unique<Ort::Session>(env_, det_path.c_str(), session_options_); cls_session_ = std::make_unique<Ort::Session>(env_, cls_path.c_str(), session_options_); rec_session_ = std::make_unique<Ort::Session>(env_, rec_path.c_str(), session_options_); is_initialized_ = true; } catch (const Ort::Exception& e) { // 加载失败时抛出异常,方便上层捕获和处理 throw std::runtime_error("Failed to initialize OCR service: " + std::string(e.what())); } } // =============================================== // 外部统一入口 // =============================================== QVector<QString> OcrService::performOcr(const cv::Mat& image) { QVector<QString> results; if (!is_initialized_ || image.empty()) return results; // 1. 检测文本框 QList<TextBox> boxes = detectTextBoxes(image); // 2. 逐框识别 for (const TextBox& box : boxes) { // 裁剪并透视矫正 cv::Mat M, warped; std::vector<cv::Point2f> dstPts = { { 0.f, 0.f }, { float(box.pts[1].x() - box.pts[0].x()), 0.f }, { float(box.pts[1].x() - box.pts[0].x()), float(box.pts[2].y() - box.pts[1].y()) }, { 0.f, float(box.pts[2].y() - box.pts[1].y()) } }; cv::warpPerspective(image, warped, cv::getPerspectiveTransform(reinterpret_cast<const cv::Point2f*>(box.pts.data()), reinterpret_cast<const cv::Point2f*>(dstPts.data())), cv::Size(int(dstPts[1].x), int(dstPts[2].y)), cv::INTER_LINEAR, cv::BORDER_REPLICATE); // 3. 方向判断 if (needRotate(warped)) cv::rotate(warped, warped, cv::ROTATE_180); // 4. 识别 results.append(recognizeText(warped)); } return results; } // =============================================== // 1. DBNet 后处理 // =============================================== static QVector<std::array<int64_t, 4>> makeShape4(int n, int c, int h, int w) { return { { static_cast<int64_t>(n), static_cast<int64_t>(c), static_cast<int64_t>(h), static_cast<int64_t>(w) } }; } QList<TextBox> OcrService::detectTextBoxes(const cv::Mat& image, float det_thresh /* =0.1 */, float box_thresh /* =0.3 */, float unclip_ratio /* =2.0 */) { QList<TextBox> finalBoxes; // ---------- 1. 前处理:resize(640x640) + RGB + float32 ---------- const int detH = 640, detW = 640; cv::Mat rgb, resized; cv::cvtColor(image, rgb, cv::COLOR_BGR2RGB); cv::resize(rgb, resized, cv::Size(detW, detH)); resized.convertTo(resized, CV_32FC3, 1.0 / 255.0f); // 0‑1 归一化 // ---------- (新) 按 mean/std 归一化 + HWC→CHW ---------- static const float mean_vals[3] = { 0.485f, 0.456f, 0.406f }; static const float std_vals[3] = { 0.229f, 0.224f, 0.225f }; QVector<float> inputData(3 * detH * detW); for (int y = 0; y < detH; ++y) for (int x = 0; x < detW; ++x) { cv::Vec3f pix = resized.at<cv::Vec3f>(y, x); // RGB int idx = y * detW + x; inputData[0 * detH * detW + idx] = (pix[0] - mean_vals[0]) / std_vals[0]; // R inputData[1 * detH * detW + idx] = (pix[1] - mean_vals[1]) / std_vals[1]; // G inputData[2 * detH * detW + idx] = (pix[2] - mean_vals[2]) / std_vals[2]; // B } // ---------- 2. 构建 ONNX Runtime 输入 ---------- Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); auto inputTensor = Ort::Value::CreateTensor<float>( memInfo, inputData.data(), inputData.size(), makeShape4(1, 3, detH, detW)[0].data(), 4); // ---------- 3. 推理 ---------- Ort::AllocatorWithDefaultOptions allocator; const char* inName = det_session_->GetInputNameAllocated(0, allocator).get(); const char* outName = det_session_->GetOutputNameAllocated(0, allocator).get(); auto outs = det_session_->Run(Ort::RunOptions{ nullptr }, &inName, &inputTensor, 1, &outName, 1); // ---------- 4. 输出处理:阈值化→膨胀→找轮廓 ---------- Ort::Value& pred = outs[0]; auto shape = pred.GetTensorTypeAndShapeInfo().GetShape(); // 期望 [1,1,H,W] qDebug() << "det output shape:" << shape[0] << shape[1] << shape[2] << shape[3]; const int outH = static_cast<int>(shape[2]); const int outW = static_cast<int>(shape[3]); QVector<float> prob(outH * outW); std::memcpy(prob.data(), pred.GetTensorMutableData<float>(), prob.size() * sizeof(float)); cv::Mat probMap(outH, outW, CV_32F, prob.data()); #if 1 // 调试代码,如果发现 cv::threshold() 前 probMap 的最大值 maxVal = 2.97e-05,说明 模型输出几乎是全零, // 所以经过 cv::threshold(probMap, binary, det_thresh, 255, ...) 后 binary 几乎全是黑图(值为0), // cv::findContours() 找不到任何轮廓,contours 自然为空。 // det 模型输出的 probMap 全接近 0,这通常是 预处理不对或模型有问题。 double minVal, maxVal; cv::minMaxLoc(probMap, &minVal, &maxVal); qDebug() << "probMap min/max:" << minVal << maxVal; #endif cv::Mat binary; cv::threshold(probMap, binary, det_thresh, 255, cv::THRESH_BINARY); binary.convertTo(binary, CV_8U); cv::Mat dilated; cv::dilate(binary, dilated, cv::getStructuringElement(cv::MORPH_RECT, { 3, 3 }), // 小核膨胀一次 cv::Point(-1, -1), 1); std::vector<std::vector<cv::Point>> contours; cv::findContours(dilated, contours, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE); qDebug() << "contours found:" << contours.size(); // ---------- 5. 轮廓转为 TextBox ---------- for (const auto& contour : contours) { if (contour.size() < 4) continue; cv::Mat mask = cv::Mat::zeros(probMap.size(), CV_8U); cv::drawContours(mask, std::vector<std::vector<cv::Point>>{ contour }, 0, cv::Scalar(255), -1); float score = static_cast<float>(cv::mean(probMap, mask)[0]); if (score < box_thresh) continue; cv::RotatedRect rect = cv::minAreaRect(contour); // 「unclip」扩张 float area = rect.size.area(); float perimeter = 2.f * (rect.size.width + rect.size.height); float distance = area * unclip_ratio / std::max(perimeter, 1.f); cv::Mat offset; cv::Mat(contour).convertTo(offset, CV_32F); std::vector<cv::Point2f> unclipPts; cv::convexHull(offset + (offset * (distance / cv::norm(offset))), unclipPts); cv::RotatedRect unclipRect = cv::minAreaRect(unclipPts); // 坐标缩放回原图 float scaleX = static_cast<float>(image.cols) / detW; float scaleY = static_cast<float>(image.rows) / detH; cv::Point2f pts[4]; unclipRect.points(pts); TextBox box; for (int i = 0; i < 4; ++i) box.pts.append(QPointF(pts[i].x * scaleX, pts[i].y * scaleY)); box.score = score; finalBoxes.append(std::move(box)); } // ---------- 6. 从上到下排序 ---------- std::sort(finalBoxes.begin(), finalBoxes.end(), [](const TextBox& a, const TextBox& b) { return a.pts[0].y() < b.pts[0].y(); }); return finalBoxes; } // =============================================== // 2. 文字方向分类 // =============================================== bool OcrService::needRotate(const cv::Mat& roi) { const int clsH = 48, clsW = 192; cv::Mat rgb, resized; cv::cvtColor(roi, rgb, cv::COLOR_BGR2RGB); cv::resize(rgb, resized, cv::Size(clsW, clsH)); resized.convertTo(resized, CV_32FC3, 1.0 / 255); QVector<float> data(clsH * clsW * 3); std::memcpy(data.data(), resized.data, data.size() * sizeof(float)); Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); auto tensor = Ort::Value::CreateTensor<float>(memInfo, data.data(), data.size(), makeShape4(1, 3, clsH, clsW)[0].data(), 4); const char* inName = cls_session_->GetInputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); const char* outName = cls_session_->GetOutputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); auto outs = cls_session_->Run(Ort::RunOptions{ nullptr }, &inName, &tensor, 1, &outName, 1); float* outPtr = outs[0].GetTensorMutableData<float>(); // PP-OCR v5 CLS 输出 shape=[1,2],索引 1 代表 180° return outPtr[1] > outPtr[0]; } // =============================================== // 3. 识别模块 // =============================================== QString OcrService::recognizeText(const cv::Mat& roi) { // -- 0. 载入一次字典 -- if (dict_.isEmpty()) { QFile f(":/models/ocr/onnx_ocr/ppocrv5/ppocrv5_dict.txt"); if (f.open(QFile::ReadOnly | QFile::Text)) while (!f.atEnd()) dict_.append(QString::fromUtf8(f.readLine().trimmed())); } const int recH = 48, recW = 320; cv::Mat rgb, resized; cv::cvtColor(roi, rgb, cv::COLOR_BGR2RGB); cv::resize(rgb, resized, cv::Size(recW, recH)); resized.convertTo(resized, CV_32FC3, 1.0 / 255); QVector<float> data(recH * recW * 3); std::memcpy(data.data(), resized.data, data.size() * sizeof(float)); Ort::MemoryInfo memInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); auto tensor = Ort::Value::CreateTensor<float>(memInfo, data.data(), data.size(), makeShape4(1, 3, recH, recW)[0].data(), 4); const char* inName = rec_session_->GetInputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); const char* outName = rec_session_->GetOutputNameAllocated(0, Ort::AllocatorWithDefaultOptions()).get(); auto outs = rec_session_->Run(Ort::RunOptions{ nullptr }, &inName, &tensor, 1, &outName, 1); // -- 后处理 CTC 解码 (argmax) -- Ort::Value& output = outs[0]; auto shape = output.GetTensorTypeAndShapeInfo().GetShape(); // [1, T, C] int T = int(shape[1]), C = int(shape[2]); float* ptr = output.GetTensorMutableData<float>(); QString result; int lastIdx = -1; for (int t = 0; t < T; ++t) { int maxIdx = 0; float maxVal = ptr[t * C]; for (int c = 1; c < C; ++c) if (ptr[t * C + c] > maxVal) { maxVal = ptr[t * C + c]; maxIdx = c; } // CTC:去重 / 去 blank(0) if (maxIdx != lastIdx && maxIdx > 0 && maxIdx < dict_.size()) result.append(dict_[maxIdx]); lastIdx = maxIdx; } return result; } // D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.h #pragma once #include <memory> #include <opencv2/opencv.hpp> #include <onnxruntime_cxx_api.h> #include <QString> #include <QVector> // 文本框结构体,四点顺时针 struct TextBox { QVector<QPointF> pts; float score = 0.0f; }; class OcrService { public: explicit OcrService(QString& model_dir); QVector<QString> performOcr(const cv::Mat& image); private: // ==== 模块化接口 ==== QList<TextBox> detectTextBoxes(const cv::Mat& image, float det_thresh = 0.3f, float box_thresh = 0.6f, float unclip_ratio = 2.0f); bool needRotate(const cv::Mat& roi); QString recognizeText(const cv::Mat& roi); // ==== ONNX Runtime ==== Ort::Env env_; Ort::SessionOptions session_options_; std::unique_ptr<Ort::Session> det_session_; std::unique_ptr<Ort::Session> cls_session_; std::unique_ptr<Ort::Session> rec_session_; bool is_initialized_ = false; // ==== 字典缓存 ==== QStringList dict_; }; // D:\wzl\project\wzl_qt_work\src\cpp\test\Test.cpp #include "Test.h" #include "WindowManager.h" extern WindowManager* g_windowManager; Test::Test() { QTextStream qout(stdout); QTextStream qerr(stderr); // =======================【请修改这里】======================= // 设置你的 ONNX 模型所在的文件夹路径 QString model_directory = "D:/wzl/project/wzl_qt_work/assets/models/ocr/onnx_ocr/ppocrv5/"; // 设置你要测试的图片完整路径 QString image_path = "D:/mhxy.jpg"; // <--- 必须修改为一张有效图片路径! // ========================================================== std::unique_ptr<OcrService> ocr_service; // --- 步骤 1: 初始化 OCR 服务 --- // 使用 try-catch 结构来安全地处理初始化过程中可能抛出的异常 try { qout << "[INFO] Initializing OCR service from: " << model_directory << "\n"; ocr_service = std::make_unique<OcrService>(model_directory); qout << "[SUCCESS] OCR service initialized successfully." << "\n"; } catch (const std::runtime_error& e) { // 如果构造函数抛出异常 (如模型文件找不到), 在这里捕获并打印错误信息 std::cerr << "[ERROR] OCR service initialization failed: " << e.what() << "\n"; return; // 初始化失败, 程序退出 } // --- 步骤 2: 加载测试图片 --- qout << "\n[INFO] Loading image from: " << image_path << "\n"; cv::Mat image = cv::imread(image_path.toStdString()); if (image.empty()) { qerr << "[ERROR] Could not load image. Please check the path: " << image_path << "\n"; return; } qout << "[SUCCESS] Image loaded." << "\n"; // --- 步骤 3: 执行 OCR 并获取结果 --- qout << "\n[INFO] Performing OCR on the image..." << "\n"; QVector<QString> ocr_results = ocr_service->performOcr(image); // --- 步骤 4: 打印识别结果 --- qout << "\n========== OCR Results ==========" << "\n"; if (ocr_results.empty()) { qout << "No text was detected in the image." << "\n"; } else { int line_num = 1; for (const auto& line : ocr_results) { qout << "Line " << line_num++ << ": " << line << Qt::endl; } } qout << "===============================" << "\n"; } #### 这是我windows Qt 6.9 Quick CMake 项目的目录结构: "D:\wzl\project\wzl_qt_work\CMakeLists.txt" "D:\wzl\project\wzl_qt_work\src\resources.qrc" "D:\wzl\project\wzl_qt_work\src\qml\" "D:\wzl\project\wzl_qt_work\src\qml\Main.qml" "D:\wzl\project\wzl_qt_work\src\qml\WzlText.qml" "D:\wzl\project\wzl_qt_work\src\qml\SettingsWindow.qml" "D:\wzl\project\wzl_qt_work\src\cpp\" "D:\wzl\project\wzl_qt_work\src\cpp\pch.h" "D:\wzl\project\wzl_qt_work\src\cpp\CMakeLists.txt" "D:\wzl\project\wzl_qt_work\src\cpp\main.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\WindowManager.h" "D:\wzl\project\wzl_qt_work\src\cpp\WindowManager.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\BackendController.h" "D:\wzl\project\wzl_qt_work\src\cpp\BackendController.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\DataModel.h" "D:\wzl\project\wzl_qt_work\src\cpp\DataModel.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\system_info\wzl_regedit.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\documentProcessing\pdf\wzl_pdf.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\documentProcessing\wzl_file.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\ocr\wzl_ocr.cpp" "D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.h" "D:\wzl\project\wzl_qt_work\src\cpp\ocr\OcrService.cpp" "D:\wzl\project\wzl_qt_work\out\build\debug\python\ocr\ocr_test.py" "D:\wzl\project\wzl_qt_work\assets\images\" "D:\wzl\project\wzl_qt_work\assets\images\icons\main.ico" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\ppocrv5_dict.txt" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\cls\cls.onnx" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\det\det.onnx" "D:\wzl\project\wzl_qt_work\assets\models\ocr\onnx_ocr\ppocrv5\rec\rec.onnx" "D:\wzl\project\wzl_qt_work\third_party\onnxruntime-win-x64-1.22.0\include\" "D:\wzl\project\wzl_qt_work\third_party\onnxruntime-win-x64-1.22.0\lib\" "D:\vcpkg\packages\opencv4_x64-windows\include\" "D:\vcpkg\packages\opencv4_x64-windows\lib" # D:\wzl\project\wzl_qt_work\CMakeLists.txt cmake_minimum_required(VERSION 3.16) project(wzl_qt_work VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # === 启用预编译头和Qt特性 === set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON) # 启用 `AUTOMOC/AUTORCC/AUTOUIC` 自动处理Qt特性 set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) # 指定Qt安装路径(根据实际情况调整) if(MSVC) # 当使用 Visual Studio 时,使用 MSVC 版本的 Qt # 检查是否使用 Microsoft Visual Studio 的编译器 (`MSVC`) set(Qt6_DIR "E:/Qt/6.10.0/msvc2022_64/lib/cmake/Qt6") else() # 其他环境(例如在 Qt Creator 中使用 MinGW 工具链) # set(Qt6_DIR "E:/Qt/6.10.0/llvm-mingw_64/lib/cmake/Qt6") set(Qt6_DIR "E:/Qt/6.10.0/msvc2022_64/lib/cmake/Qt6") endif() # === Qt 模块 === find_package(Qt6 REQUIRED COMPONENTS Quick Core Qml Network Gui Widgets QuickControls2 QuickLayouts) qt_standard_project_setup(REQUIRES 6.8) # windows 下,用 Visual Studio 2022 打开 Qt Quick CMake 项目,编译报错: # error 指令: "Qt requires a C++17 compiler, and a suitable value for __cplusplus. On MSVC, you must pass the /Zc:__cplusplus option to the compiler." # error: "Qt requires a C++17 compiler, and a suitable value for __cplusplus. On MSVC, you must pass the /Zc:__cplusplus option to the compiler." # windows 下,用Visual Studio 2022 打开 Qt Quick CMake 项目,编译报错: # E:\Qt\6.10.0\llvm-mingw_64\include\QtCore\qcompilerdetection.h(1327): error C2338: static_assert failed: 'On MSVC you must pass the /permissive- option to the compiler.' # C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\type_traits(323): error C2139: “QString”: 未定义的类不允许作为编译器内部类型特征“__is_convertible_to”的参数 if(MSVC) add_compile_options( # 报告 C++ 标准 /Zc:__cplusplus # 启用严格标准符合模式 /permissive- # 强制源码使用 UTF-8 编码,解决中文路径问题 /utf-8 ) # 启用 ASLR,专门针对 Windows 平台和 MSVC 编译器的重要安全设置,传递给 MSVC 链接器 (link.exe) 的选项, # - **地址空间布局随机化 (ASLR - Address Space Layout Randomization)** # - 每次程序运行时,操作系统会将程序加载到**随机的内存地址** # - 防止攻击者预测关键函数/数据的内存位置 add_link_options(/DYNAMICBASE) endif() # === 预编译头 === # 将 `define_url.h` 添加到 `PRECOMPILE_HEADERS` 变量中,确保 CMake 能正确识别其为预编译依赖 # 显式添加 define_url.h 到源文件列表(确保预编译依赖正确) set(PRECOMPILE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/pch.h ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/define_url.h ) # === 添加可执行目标 === # Qt Creator 会解析 CMake 目标中的文件列表 # 所有添加到可执行目标 (`qt_add_executable`) 的文件都会显示在项目树中 qt_add_executable(appwzl_qt_work src/cpp/main.cpp # 添加 shortcut_key.h 仅用于在 IDE 中显示;这样会将文件添加到 Qt Creator 的项目树中,但不会尝试编译它(因为它不是源文件) src/cpp/shortcut_key.h # 将头文件加入可执行文件依赖 ${PRECOMPILE_HEADERS} src/cpp/BackendController.cpp src/cpp/BackendController.h src/cpp/WindowManager.cpp src/cpp/WindowManager.h src/cpp/DataModel.cpp src/cpp/DataModel.h src/cpp/wzl_dll.cpp src/cpp/test/Test.h src/cpp/test/Test.cpp src/cpp/test/company.cpp src/cpp/ocr/wzl_ocr.cpp src/cpp/ocr/OcrService.h src/cpp/ocr/OcrService.cpp src/cpp/system_info/wzl_regedit.cpp src/cpp/documentProcessing/wzl_file.cpp src/cpp/documentProcessing/pdf/wzl_pdf.cpp qt_faq.md README.md ) # === Qt 资源文件 === qt_add_resources(appwzl_qt_work "app_resources" PREFIX "/" FILES src/resources.qrc assets/images/icons/main.ico ) # === 预编译头设置 === #target_precompile_headers(appwzl_qt_work PRIVATE # "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/pch.h>" #) # 配置预编译头(更新为使用列表) target_precompile_headers(appwzl_qt_work PRIVATE ${PRECOMPILE_HEADERS}) # === 包含头文件目录 === target_include_directories(appwzl_qt_work PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/cpp ) # === 添加 QML 模块 === qt_add_qml_module(appwzl_qt_work URI "wzl_qt_work" VERSION "1.0" RESOURCE_PREFIX "/" QML_FILES src/qml/Main.qml src/qml/SettingsWindow.qml src/qml/wzl_text/WzlText.qml ) # 设置目标属性(包括 Windows 和 macOS 平台) set_target_properties(appwzl_qt_work PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" MACOSX_BUNDLE TRUE # 打开:会显示控制台;注释:隐藏控制台 WIN32_EXECUTABLE TRUE ) # === 链接 Qt 模块 === target_link_libraries(appwzl_qt_work PRIVATE Qt6::Quick Qt6::Core Qt6::Qml Qt6::Network Qt6::Gui Qt6::Widgets Qt6::QuickControls2 Qt6::QuickLayouts ) # === 新增 OpenCV 支持 === find_package(OpenCV REQUIRED) target_include_directories(appwzl_qt_work PRIVATE ${OpenCV_INCLUDE_DIRS}) target_link_libraries(appwzl_qt_work PRIVATE ${OpenCV_LIBS}) # === 新增 ONNX Runtime 支持 === set(ONNXRUNTIME_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/onnxruntime-win-x64-1.22.0") target_include_directories(appwzl_qt_work PRIVATE ${ONNXRUNTIME_DIR}/include) target_link_directories(appwzl_qt_work PRIVATE ${ONNXRUNTIME_DIR}/lib) target_link_libraries(appwzl_qt_work PRIVATE onnxruntime) # === 安装规则 === include(GNUInstallDirs) install(TARGETS appwzl_qt_work BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
06-17
import os from datetime import datetime import tensorflow as tf import keras from tensorflow.keras.optimizers import Adam # 使用TensorFlow的Keras os.environ["SM_FRAMEWORK"] = "tf.keras" # 显式设置后端 os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0' os.environ['TF_CPP_MIN_LOG_LEVEL'] = '1' os.environ['TF_GPU_ALLOCATOR'] = 'cuda_malloc_async' os.environ['TF_XLA_FLAGS'] = '--tf_xla_enable_xla_devices=false' # 导入 segmentation_models 并设置框架 import segmentation_models as sm sm.set_framework('tf.keras') # 确保使用 tf.keras 后端 import cv2 import numpy as np from matplotlib import pyplot as plt import matplotlib from keras.utils.np_utils import to_categorical from tensorflow.keras.utils import Sequence from sklearn.metrics import f1_score, precision_score, recall_score, roc_auc_score, matthews_corrcoef import pandas as pd from tqdm import tqdm import gc from keras.callbacks import EarlyStopping # 设置 matplotlib 支持中文 plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS'] plt.rcParams['axes.unicode_minus'] = False # 设置环境变量以优化 GPU 性能 os.environ["SM_FRAMEWORK"] = "tf.keras" os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0' os.environ['TF_CPP_MIN_LOG_LEVEL'] = '1' os.environ['TF_GPU_ALLOCATOR'] = 'cuda_malloc_async' os.environ['TF_XLA_FLAGS'] = '--tf_xla_enable_xla_devices=false' # 设置全精度计算 tf.keras.mixed_precision.set_global_policy('float32') # 设置 GPU 内存增长 gpus = tf.config.list_physical_devices('GPU') if gpus: for gpu in gpus: tf.config.experimental.set_memory_growth(gpu, True) else: print("警告:未检测到 GPU,将使用 CPU 运行") # 打印环境信息 print("TensorFlow 版本:", tf.__version__) print("segmentation_models 版本:", sm.__version__) print("GPU 设备:", tf.config.list_physical_devices('GPU')) print("CUDA 可用:", tf.test.is_built_with_cuda()) print("cuDNN 可用:", tf.test.is_built_with_gpu_support()) # 设置随机种子 np.random.seed(0) tf.random.set_seed(0) # 配置参数 n_classes = 2 SIZE = 1024 # 使用第一份代码的尺寸 base_directory = 'D:/pycharm/spark/data/data/data_1024_1024/' # 划分后的数据集路径 train_directory = os.path.join(base_directory, 'train_data') val_directory = os.path.join(base_directory, 'val_data') test_directory = os.path.join(base_directory, 'test_data') result_directory = 'D:/pycharm/spark/data/data/result3/' checkpoint_directory = 'D:/pycharm/spark/data/data/duststorm/' os.makedirs(result_directory, exist_ok=True) os.makedirs(checkpoint_directory, exist_ok=True) # 检查目录 for directory in [train_directory, val_directory, test_directory]: img_dir = os.path.join(directory, 'mdgm1') mask_dir = os.path.join(directory, 'mask1') if not os.path.exists(img_dir) or not os.path.exists(mask_dir): print(f"错误:目录 {img_dir} 或 {mask_dir} 不存在") exit() # 数据生成器类 class DataGenerator(Sequence): def __init__(self, image_paths, mask_paths, preprocess_input, batch_size=4, size=SIZE, n_classes=2): self.image_paths = image_paths self.mask_paths = mask_paths self.preprocess_input = preprocess_input self.batch_size = batch_size self.size = size self.n_classes = n_classes def __len__(self): return max(1, int(np.ceil(len(self.image_paths) / self.batch_size))) def __getitem__(self, idx): batch_image_paths = self.image_paths[idx * self.batch_size:(idx + 1) * self.batch_size] batch_mask_paths = self.mask_paths[idx * self.batch_size:(idx + 1) * self.batch_size] images = np.empty((len(batch_image_paths), self.size, self.size, 3), dtype=np.float32) masks = np.empty((len(batch_image_paths), self.size, self.size), dtype=np.uint8) for i, (img_path, mask_path) in enumerate(zip(batch_image_paths, batch_mask_paths)): img = cv2.imread(img_path, cv2.IMREAD_COLOR) if img is None: print(f"警告:无法加载图像 {img_path}") continue img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (self.size, self.size), interpolation=cv2.INTER_NEAREST) images[i] = img mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) if mask is None: print(f"警告:无法加载掩码 {mask_path}") continue mask = cv2.resize(mask, (self.size, self.size), interpolation=cv2.INTER_NEAREST) mask = np.where(mask > 0, 1, 0).astype(np.uint8) masks[i] = mask if not images.size or not masks.size: print(f"警告:批次 {idx} 为空,返回占位数据") return np.zeros((1, self.size, self.size, 3), dtype=np.float32), \ np.zeros((1, self.size, self.size, self.n_classes), dtype=np.float32) images = self.preprocess_input(images) masks = to_categorical(masks, num_classes=self.n_classes).astype(np.float32) return images, masks # 过滤图像文件 def is_image_file(filename): return filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')) # 加载文件路径 def load_paths(directory): img_dir = os.path.join(directory, 'mdgm1') mask_dir = os.path.join(directory, 'mask1') image_files = sorted([f for f in os.listdir(img_dir) if is_image_file(f)]) mask_files = sorted([f for f in os.listdir(mask_dir) if is_image_file(f)]) common_files = sorted(set(image_files) & set(mask_files)) image_paths = [os.path.join(img_dir, fname) for fname in common_files] mask_paths = [os.path.join(mask_dir, fname) for fname in common_files] print(f"{directory}:找到 {len(common_files)} 个匹配文件对") return image_paths, mask_paths, common_files # 加载数据集 train_image_paths, train_mask_paths, train_names = load_paths(train_directory) val_image_paths, val_mask_paths, val_names = load_paths(val_directory) test_image_paths, test_mask_paths, test_names = load_paths(test_directory) # 创建数据生成器 BACKBONE = 'inceptionv3' preprocess_input = sm.get_preprocessing(BACKBONE) train_generator = DataGenerator(train_image_paths, train_mask_paths, preprocess_input, batch_size=4) val_generator = DataGenerator(val_image_paths, val_mask_paths, preprocess_input, batch_size=4) test_generator = DataGenerator(test_image_paths, test_mask_paths, preprocess_input, batch_size=4) # 模型参数 activation = 'sigmoid' LR = 1e-5 # 使用第二份代码的学习率 optim = Adam(LR, clipnorm=1.0) metrics = [sm.metrics.IOUScore(threshold=0.5), sm.metrics.FScore(threshold=0.5)] loss = sm.losses.BinaryFocalLoss(alpha=0.25, gamma=2.0) + sm.losses.DiceLoss(class_weights=[0.2, 0.8]) # 加载权重 weights_path = 'D:/pycharm/spark/data/data/inceptionv3/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5' try: if not os.path.exists(weights_path): print(f"错误:权重文件 {weights_path} 不存在,使用 ImageNet 权重") model = sm.Unet(BACKBONE, encoder_weights='imagenet', classes=n_classes, activation=activation) else: model = sm.Unet(BACKBONE, encoder_weights=weights_path, classes=n_classes, activation=activation) except Exception as e: print(f"加载权重失败: {e},使用随机初始化") model = sm.Unet(BACKBONE, encoder_weights=None, classes=n_classes, activation=activation) # 编译模型 with tf.device('/GPU:0'): model.compile(optim, loss=loss, metrics=metrics) print(model.summary()) # 设置回调 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") checkpoint_filepath = f'{checkpoint_directory}/train_MY30_31_inceptionv3_{timestamp}.keras' callbacks = [ tf.keras.callbacks.ModelCheckpoint( filepath=checkpoint_filepath, monitor='val_iou_score', mode='max', save_best_only=True, verbose=1 ), EarlyStopping( monitor='val_iou_score', mode='max', patience=5, restore_best_weights=True, verbose=1 ), tf.keras.callbacks.ReduceLROnPlateau( monitor='val_loss', factor=0.5, patience=3, min_lr=1e-6, verbose=1 ) ] # 训练模型 try: with tf.device('/GPU:0'): history = model.fit( train_generator, epochs=50, validation_data=val_generator, callbacks=callbacks, verbose=1 ) except Exception as e: print(f"训练失败: {e}") exit() # 绘制训练和验证曲线 def plot_metrics(history, metric_name, title, ylabel): metric = history.history[metric_name] val_metric = history.history[f'val_{metric_name}'] epochs = range(1, len(metric) + 1) plt.figure(figsize=(10, 5)) plt.plot(epochs, metric, 'y', label=f'训练 {ylabel}') plt.plot(epochs, val_metric, 'r', label=f'验证 {ylabel}') plt.title(title) plt.xlabel('轮次') plt.ylabel(ylabel) plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.tight_layout() plt.show() plot_metrics(history, 'loss', '训练和验证损失 train_MY30_31_inceptionv3', '损失') plot_metrics(history, 'iou_score', '训练和验证 IoU train_MY30_31_inceptionv3', 'IoU') # 保存训练指标 with open(f'{checkpoint_directory}/train_MY30_31_inceptionv3_{timestamp}.csv', 'w', newline='') as f: writer = csv.writer(f) writer.writerow(['训练损失', '验证损失', '训练 IoU', '验证 IoU']) for row in zip(history.history['loss'], history.history['val_loss'], history.history['iou_score'], history.history['val_iou_score']): writer.writerow(row) # 测试集评估 def calculate_iou(pred_mask, gt_mask): intersection = np.logical_and(pred_mask, gt_mask).sum() union = np.logical_or(pred_mask, gt_mask).sum() return intersection / union if union != 0 else 1.0 def pixel_accuracy(y_true, y_pred): y_pred = tf.round(y_pred) correct_pixels = tf.reduce_sum(tf.cast(tf.equal(y_true, y_pred), tf.float32)) total_pixels = tf.cast(tf.size(y_true), tf.float32) return (correct_pixels / total_pixels).numpy() def pixel_accuracy_for_class(y_true, y_pred, class_id): y_pred_rounded = tf.cast(tf.round(y_pred), tf.int32) true_mask = tf.equal(y_true, class_id) pred_mask = tf.equal(y_pred_rounded, class_id) correct_pixels_class = tf.reduce_sum(tf.cast(tf.logical_and(true_mask, pred_mask), tf.float32)) total_pixels_class = tf.reduce_sum(tf.cast(true_mask, tf.float32)) return (correct_pixels_class / total_pixels_class).numpy() if total_pixels_class != 0 else 0.0 # 测试集预测和评估 metrics_dict = { '文件名': [], 'IoU 分数': [], 'AUC 分数': [], 'F1 分数': [], 'F1 微平均': [], 'F1 宏平均': [], '精确率 (宏平均)': [], '召回率 (宏平均)': [], '像素精度 (整体)': [], '像素精度 (尘暴)': [], 'MCC': [] } for i in tqdm(range(len(test_image_paths)), desc="测试集预测"): test_img = cv2.imread(test_image_paths[i], cv2.IMREAD_COLOR) if test_img is None: print(f"警告:无法加载测试图像 {test_image_paths[i]}") continue test_img = cv2.cvtColor(test_img, cv2.COLOR_BGR2RGB) test_img = cv2.resize(test_img, (SIZE, SIZE), interpolation=cv2.INTER_NEAREST) test_img_input = preprocess_input(np.expand_dims(test_img, 0)) test_mask = cv2.imread(test_mask_paths[i], cv2.IMREAD_GRAYSCALE) if test_mask is None: print(f"警告:无法加载测试掩码 {test_mask_paths[i]}") continue test_mask = cv2.resize(test_mask, (SIZE, SIZE), interpolation=cv2.INTER_NEAREST) test_mask = np.where(test_mask > 0, 1, 0).astype(np.uint8) with tf.device('/GPU:0'): test_pred = model.predict(test_img_input, verbose=0) test_prediction = np.argmax(test_pred, axis=3)[0, :, :] iou = calculate_iou(test_prediction, test_mask) auc_score = roc_auc_score(test_mask.flatten(), test_pred[0, :, :, 1].flatten()) f1 = f1_score(test_mask.flatten(), test_prediction.flatten(), average='binary', zero_division=1) f1_micro = f1_score(test_mask.flatten(), test_prediction.flatten(), average='micro', zero_division=1) f1_macro = f1_score(test_mask.flatten(), test_prediction.flatten(), average='macro', zero_division=1) precision = precision_score(test_mask.flatten(), test_prediction.flatten(), average='macro', zero_division=0) recall = recall_score(test_mask.flatten(), test_prediction.flatten(), average='macro', zero_division=0) pa = pixel_accuracy(test_mask, test_prediction) pa_dust = pixel_accuracy_for_class(test_mask, test_prediction, 1) mcc = matthews_corrcoef(test_mask.flatten(), test_prediction.flatten()) metrics_dict['文件名'].append(test_names[i]) metrics_dict['IoU 分数'].append(iou) metrics_dict['AUC 分数'].append(auc_score) metrics_dict['F1 分数'].append(f1) metrics_dict['F1 微平均'].append(f1_micro) metrics_dict['F1 宏平均'].append(f1_macro) metrics_dict['精确率 (宏平均)'].append(precision) metrics_dict['召回率 (宏平均)'].append(recall) metrics_dict['像素精度 (整体)'].append(pa) metrics_dict['像素精度 (尘暴)'].append(pa_dust) metrics_dict['MCC'].append(mcc) # 可视化 plt.figure(figsize=(15, 5)) plt.subplot(1, 3, 1) plt.title('图像') plt.imshow(test_img) plt.axis('off') plt.subplot(1, 3, 2) plt.title('图像 + 掩码') plt.imshow(test_img) plt.imshow(test_mask, cmap='jet', alpha=0.5) plt.axis('off') plt.subplot(1, 3, 3) plt.title('预测 + 掩码 + IoU') plt.imshow(test_prediction, cmap='gray') plt.imshow(test_mask, cmap='jet', alpha=0.5) plt.text(0.5, -0.1, f'IoU: {iou:.3f}', ha='center', va='center', transform=plt.gca().transAxes, fontsize=10) plt.axis('off') plt.savefig(os.path.join(result_directory, f'test_{test_names[i]}'), bbox_inches='tight') plt.close() # 保存测试指标 pd.DataFrame(metrics_dict).to_csv(f'{checkpoint_directory}/test_MY30_31_inceptionv3_metrics_{timestamp}.csv', index=False) 现在是可以运行,但是运行不是用gpu运行,是使用cpu运行
最新发布
08-15
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值