把网站做成静态页面,舆情分析系统,学校建设网站的结论,dede免费模板近期有个工作需求是进行 YOLOv8 模型的 C 部署#xff0c;部署环境如下 系统#xff1a;WindowsIDE#xff1a;VS2015语言#xff1a;COpenCV 4.5.0OnnxRuntime 1.15.1 0. 预训练模型保存为 .onnx 格式
假设已经有使用 ultralytics 库训练并保存为 .pt 格式的 YOLOv8 模型…近期有个工作需求是进行 YOLOv8 模型的 C 部署部署环境如下 系统WindowsIDEVS2015语言COpenCV 4.5.0OnnxRuntime 1.15.1 0. 预训练模型保存为 .onnx 格式
假设已经有使用 ultralytics 库训练并保存为 .pt 格式的 YOLOv8 模型将其转换为 .onnx 格式是简单的import os
import sys
base_path os.path.abspath(os.path.join(os.path.dirname(__file__),))
sys.path.append(base_path)from ultralytics import YOLO# Load a YOLOv8 model
model YOLO(f{base_path}/model/output/best.pt)# Export the model
model.export(formatonnx, opset9, simplifyTrue, dynamicFalse, imgsz640)注意导出时设置了 opset9这个版本可以和 OnnxRuntime 1.15.1 匹配 除了 .onnx 模型文件以外还需要准备数据集的 .yaml 文件和用于测试的图片
1. 依赖下载
1.1 OpenCV
在 window 上用 Cmake 从源码编译 OpenCV 很麻烦直接下载 release 库下载地址OpenCV-4.5.0 下载后得到 opencv-4.5.0-vc14_vc15.exe双击解压。把 C:\Users…\opencv\build\x64\vc14\bin 添加到环境变量。其中 vc14 对应 vs2015提取的文件中以下是我们之后需要的 头文件C:\Users…\opencv\build\include\opencv2动态库C:\Users…\opencv\build\x64\vc14\bin\opencv_world450.dll静态库C:\Users…\opencv\build\x64\vc14\lib\opencv_world450.lib opencv_world450d.lib opencv_world450.lib 用于 vs release 模式opencv_world450d.lib 用于 vs debug 模式
1.2 OnnxRuntime
下载地址ONNX Runtime v1.15.1下载 onnxruntime-win-x64-1.15.1.zip下载后直接解压。提取的文件中以下是我们之后需要的 头文件C:\Users…\onnxruntime-win-x64-1.15.1\include动态库C:\Users…\onnxruntime-win-x64-1.15.1\lib 下的所有 .dll 文件静态库C:\Users…\onnxruntime-win-x64-1.15.1\lib 下的所有 .lib 文件
1.3 Cpp 源码
下载地址YOLOv8 OnnxRuntime C。这是 ultralytics 提供的官方案例注意其依赖 由于 vs2015 无法设置 C17 标准后续会修改源码去掉其中使用的 filesystem 库由于仅部署 CPU 版本无需 Cuda 和 cuDNN。另外这个 readme 还提到了 Cmake 编译我们不需要做这步直接用它的源码就行了
2. VS2015 工程配置
2.1 创建项目
首先新建 Win32 控制台项目选择空项目。我这里项目路径为 YOLOv8-Test项目名为 Test。打开工程根目录新建 bin、lib、include 三个目录 在 bin 中粘贴 1.2 和 1.3 节提到的所有动态库文件 在 lib 中粘贴 1.2 和 1.3 节提到的所有静态库文件 在 include 中粘贴 1.2 和 1.3 节提到的所有头文件目录 其中 onnxruntime-win-x64 就是 C:\Users…\onnxruntime-win-x64-1.15.1\include 文件夹 把源码粘贴到根目录并添加到项目中
2.2 配置项目属性
在解决方案名 Test 处右键点最下面属性打开项目属性页。首先配置 Release 属性平台选择 x64 VC目录 - 包含目录编辑增加以下路径 VC目录 - 库目录编辑增加以下路径 C/C - 常规 - 附加包含目录编辑增加以下路径。并关闭 SDL 检查 链接器 - 附加库目录编辑增加以下路径 链接器 - 输入 - 附加依赖项编辑增加以下文件名主要这里是Release版本所以用 opencv_world450.lib 类似地配置 Debug 属性区别仅在于最后一步链接附加依赖项写入 opencv_world450d.lib 由于 1.3 节没有对源码进行 Cmake 安装还需要将 onnxruntime.dll 复制粘贴到编译运行后 .exe 文件的生成目录下如 C:…\YOLOv8-Test\Test\x64\Release以免出现链接错误 如果不想在每次编译都粘贴可以直接把它粘贴到 C:\Windows\System32 和 C:\Windows\SysWOW64
3. 修改源码 由于 vs2015 无法使用 C17 特征修改 main.cpp 去掉其中对 filesystem 库的依赖如下 #include iostream
#include iomanip
#include inference.h
#include fstream
#include random
#include vector
#include string
#include dirent.h
#include sys/stat.h
#include opencv2/opencv.hppvoid Detector(YOLO_V8* p) {std::string current_path .;std::string imgs_path current_path /images;DIR* dir;struct dirent* ent;if ((dir opendir(imgs_path.c_str())) ! NULL) {while ((ent readdir(dir)) ! NULL) {std::string file_name ent-d_name;if (file_name.find(.jpg) ! std::string::npos || file_name.find(.png) ! std::string::npos || file_name.find(.jpeg) ! std::string::npos) {std::string img_path imgs_path / file_name;cv::Mat img cv::imread(img_path);std::vectorDL_RESULT res;p-RunSession(img, res);for (auto re : res) {cv::RNG rng(cv::getTickCount());cv::Scalar color(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));cv::rectangle(img, re.box, color, 3);float confidence floor(100 * re.confidence) / 100;std::cout std::fixed std::setprecision(2);std::string label p-classes[re.classId] std::to_string(confidence).substr(0, std::to_string(confidence).size() - 4);cv::rectangle(img,cv::Point(re.box.x, re.box.y - 25),cv::Point(re.box.x label.length() * 15, re.box.y),color,cv::FILLED);cv::putText(img,label,cv::Point(re.box.x, re.box.y - 5),cv::FONT_HERSHEY_SIMPLEX,0.75,cv::Scalar(0, 0, 0),2);std::replace(label.begin(), label.end(), \r, );std::cout Target Type: label std::endl;std::cout Loc (x,y,w,h): ( re.box.x , re.box.y , re.box.width , re.box.height ) std::endl;}cv::Mat resized_img; double scale_factor 5.0; // 放大倍数 cv::resize(img, resized_img, cv::Size(), scale_factor, scale_factor, cv::INTER_LINEAR); cv::imshow(Result of Detection, resized_img); std::cout Press any key to exit std::endl;//cv::imshow(Result of Detection, img);cv::waitKey(0);cv::destroyAllWindows();}}closedir(dir);}
}void Classifier(YOLO_V8* p) {std::string current_path .;std::string imgs_path current_path;std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distributionint dis(0, 255);DIR* dir;struct dirent* ent;if ((dir opendir(imgs_path.c_str())) ! NULL) {while ((ent readdir(dir)) ! NULL) {std::string file_name ent-d_name;if (file_name.find(.jpg) ! std::string::npos || file_name.find(.png) ! std::string::npos) {std::string img_path imgs_path / file_name;cv::Mat img cv::imread(img_path);std::vectorDL_RESULT res;char* ret p-RunSession(img, res);float positionY 50;for (int i 0; i res.size(); i) {int r dis(gen);int g dis(gen);int b dis(gen);cv::putText(img, std::to_string(i) :, cv::Point(10, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2);cv::putText(img, std::to_string(res.at(i).confidence), cv::Point(70, positionY), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(b, g, r), 2);positionY 50;}cv::imshow(TEST_CLS, img);cv::waitKey(0);cv::destroyAllWindows();}}closedir(dir);}
}int ReadPlaneYaml(YOLO_V8* p) {// Open the YAML filestd::ifstream file(./cfg/plane.yaml);if (!file.is_open()) {std::cerr Failed to open file std::endl;return 1;}// Read the file line by linestd::string line;std::vectorstd::string lines;while (std::getline(file, line)) {lines.push_back(line);}// Find the start and end of the names sectionstd::size_t start 0;std::size_t end 0;for (std::size_t i 0; i lines.size(); i) {if (lines[i].find(names:) ! std::string::npos) {start i 1;} else if (start 0 lines[i].find(:) std::string::npos) {end i;break;}}// Extract the namesstd::vectorstd::string names;for (std::size_t i start; i end; i) {std::stringstream ss(lines[i]);std::string name;std::getline(ss, name, :); // Extract the number before the delimiterstd::getline(ss, name); // Extract the string after the delimiternames.push_back(name);}p-classes names;return 0;
}void DetectTest() {YOLO_V8* yoloDetector new YOLO_V8;ReadPlaneYaml(yoloDetector);DL_INIT_PARAM params;params.rectConfidenceThreshold 0.1;params.iouThreshold 0.5;params.modelPath ./model/best.onnx;params.imgSize { 640, 640 };
#ifdef USE_CUDAparams.cudaEnable true;// GPU FP32 inferenceparams.modelType YOLO_DETECT_V8;// GPU FP16 inference//Note: change fp16 onnx model//params.modelType YOLO_DETECT_V8_HALF;#else// CPU inferenceparams.modelType YOLO_DETECT_V8;params.cudaEnable false;#endifyoloDetector-CreateSession(params);Detector(yoloDetector);
}// void ClsTest() {
// YOLO_V8* yoloDetector new YOLO_V8;
// std::string model_path cls.onnx;
// ReadPlaneYaml(yoloDetector);
// DL_INIT_PARAM params{ model_path, YOLO_CLS, {224, 224} };
// yoloDetector-CreateSession(params);
// Classifier(yoloDetector);
// }int main() {DetectTest();//ClsTest();
} 以上代码使用了 dirent.h 中封装的 windows 文件读写方法如果 vs 报错找不到这个头文件则自己创建该文件放置于 vs 安装路径我这是 D:\Programmer\Microsoft Visual Studio 14.0\VC\include /** Dirent interface for Microsoft Visual Studio** Copyright (C) 1998-2019 Toni Ronkko* This file is part of dirent. Dirent may be freely distributed* under the MIT license. For all details and documentation, see* https://github.com/tronkko/dirent*/
#ifndef DIRENT_H
#define DIRENT_H/* Hide warnings about unreferenced local functions */
#if defined(__clang__)
# pragma clang diagnostic ignored -Wunused-function
#elif defined(_MSC_VER)
# pragma warning(disable:4505)
#elif defined(__GNUC__)
# pragma GCC diagnostic ignored -Wunused-function
#endif/** Include windows.h without Windows Sockets 1.1 to prevent conflicts with* Windows Sockets 2.0.*/
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include windows.h#include stdio.h
#include stdarg.h
#include wchar.h
#include string.h
#include stdlib.h
#include malloc.h
#include sys/types.h
#include sys/stat.h
#include errno.h/* Indicates that d_type field is available in dirent structure */
#define _DIRENT_HAVE_D_TYPE/* Indicates that d_namlen field is available in dirent structure */
#define _DIRENT_HAVE_D_NAMLEN/* Entries missing from MSVC 6.0 */
#if !defined(FILE_ATTRIBUTE_DEVICE)
# define FILE_ATTRIBUTE_DEVICE 0x40
#endif/* File type and permission flags for stat(), general mask */
#if !defined(S_IFMT)
# define S_IFMT _S_IFMT
#endif/* Directory bit */
#if !defined(S_IFDIR)
# define S_IFDIR _S_IFDIR
#endif/* Character device bit */
#if !defined(S_IFCHR)
# define S_IFCHR _S_IFCHR
#endif/* Pipe bit */
#if !defined(S_IFFIFO)
# define S_IFFIFO _S_IFFIFO
#endif/* Regular file bit */
#if !defined(S_IFREG)
# define S_IFREG _S_IFREG
#endif/* Read permission */
#if !defined(S_IREAD)
# define S_IREAD _S_IREAD
#endif/* Write permission */
#if !defined(S_IWRITE)
# define S_IWRITE _S_IWRITE
#endif/* Execute permission */
#if !defined(S_IEXEC)
# define S_IEXEC _S_IEXEC
#endif/* Pipe */
#if !defined(S_IFIFO)
# define S_IFIFO _S_IFIFO
#endif/* Block device */
#if !defined(S_IFBLK)
# define S_IFBLK 0
#endif/* Link */
#if !defined(S_IFLNK)
# define S_IFLNK 0
#endif/* Socket */
#if !defined(S_IFSOCK)
# define S_IFSOCK 0
#endif/* Read user permission */
#if !defined(S_IRUSR)
# define S_IRUSR S_IREAD
#endif/* Write user permission */
#if !defined(S_IWUSR)
# define S_IWUSR S_IWRITE
#endif/* Execute user permission */
#if !defined(S_IXUSR)
# define S_IXUSR 0
#endif/* Read group permission */
#if !defined(S_IRGRP)
# define S_IRGRP 0
#endif/* Write group permission */
#if !defined(S_IWGRP)
# define S_IWGRP 0
#endif/* Execute group permission */
#if !defined(S_IXGRP)
# define S_IXGRP 0
#endif/* Read others permission */
#if !defined(S_IROTH)
# define S_IROTH 0
#endif/* Write others permission */
#if !defined(S_IWOTH)
# define S_IWOTH 0
#endif/* Execute others permission */
#if !defined(S_IXOTH)
# define S_IXOTH 0
#endif/* Maximum length of file name */
#if !defined(PATH_MAX)
# define PATH_MAX MAX_PATH
#endif
#if !defined(FILENAME_MAX)
# define FILENAME_MAX MAX_PATH
#endif
#if !defined(NAME_MAX)
# define NAME_MAX FILENAME_MAX
#endif/* File type flags for d_type */
#define DT_UNKNOWN 0
#define DT_REG S_IFREG
#define DT_DIR S_IFDIR
#define DT_FIFO S_IFIFO
#define DT_SOCK S_IFSOCK
#define DT_CHR S_IFCHR
#define DT_BLK S_IFBLK
#define DT_LNK S_IFLNK/* Macros for converting between st_mode and d_type */
#define IFTODT(mode) ((mode) S_IFMT)
#define DTTOIF(type) (type)/** File type macros. Note that block devices, sockets and links cannot be* distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are* only defined for compatibility. These macros should always return false* on Windows.*/
#if !defined(S_ISFIFO)
# define S_ISFIFO(mode) (((mode) S_IFMT) S_IFIFO)
#endif
#if !defined(S_ISDIR)
# define S_ISDIR(mode) (((mode) S_IFMT) S_IFDIR)
#endif
#if !defined(S_ISREG)
# define S_ISREG(mode) (((mode) S_IFMT) S_IFREG)
#endif
#if !defined(S_ISLNK)
# define S_ISLNK(mode) (((mode) S_IFMT) S_IFLNK)
#endif
#if !defined(S_ISSOCK)
# define S_ISSOCK(mode) (((mode) S_IFMT) S_IFSOCK)
#endif
#if !defined(S_ISCHR)
# define S_ISCHR(mode) (((mode) S_IFMT) S_IFCHR)
#endif
#if !defined(S_ISBLK)
# define S_ISBLK(mode) (((mode) S_IFMT) S_IFBLK)
#endif/* Return the exact length of the file name without zero terminator */
#define _D_EXACT_NAMLEN(p) ((p)-d_namlen)/* Return the maximum size of a file name */
#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)1)#ifdef __cplusplus
extern C {
#endif/* Wide-character version */
struct _wdirent {/* Always zero */long d_ino;/* File position within stream */long d_off;/* Structure size */unsigned short d_reclen;/* Length of name without \0 */size_t d_namlen;/* File type */int d_type;/* File name */wchar_t d_name[PATH_MAX1];
};
typedef struct _wdirent _wdirent;struct _WDIR {/* Current directory entry */struct _wdirent ent;/* Private file data */WIN32_FIND_DATAW data;/* True if data is valid */int cached;/* Win32 search handle */HANDLE handle;/* Initial directory name */wchar_t *patt;
};
typedef struct _WDIR _WDIR;/* Multi-byte character version */
struct dirent {/* Always zero */long d_ino;/* File position within stream */long d_off;/* Structure size */unsigned short d_reclen;/* Length of name without \0 */size_t d_namlen;/* File type */int d_type;/* File name */char d_name[PATH_MAX1];
};
typedef struct dirent dirent;struct DIR {struct dirent ent;struct _WDIR *wdirp;
};
typedef struct DIR DIR;/* Dirent functions */
static DIR *opendir (const char *dirname);
static _WDIR *_wopendir (const wchar_t *dirname);static struct dirent *readdir (DIR *dirp);
static struct _wdirent *_wreaddir (_WDIR *dirp);static int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
static int _wreaddir_r(_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);static int closedir (DIR *dirp);
static int _wclosedir (_WDIR *dirp);static void rewinddir (DIR* dirp);
static void _wrewinddir (_WDIR* dirp);static int scandir (const char *dirname, struct dirent ***namelist,int (*filter)(const struct dirent*),int (*compare)(const struct dirent**, const struct dirent**));static int alphasort (const struct dirent **a, const struct dirent **b);static int versionsort (const struct dirent **a, const struct dirent **b);/* For compatibility with Symbian */
#define wdirent _wdirent
#define WDIR _WDIR
#define wopendir _wopendir
#define wreaddir _wreaddir
#define wclosedir _wclosedir
#define wrewinddir _wrewinddir/* Internal utility functions */
static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);static int dirent_mbstowcs_s(size_t *pReturnValue,wchar_t *wcstr,size_t sizeInWords,const char *mbstr,size_t count);static int dirent_wcstombs_s(size_t *pReturnValue,char *mbstr,size_t sizeInBytes,const wchar_t *wcstr,size_t count);static void dirent_set_errno (int error);/** Open directory stream DIRNAME for read and return a pointer to the* internal working area that is used to retrieve individual directory* entries.*/
static _WDIR*
_wopendir(const wchar_t *dirname)
{_WDIR *dirp;DWORD n;wchar_t *p;/* Must have directory name */if (dirname NULL || dirname[0] \0) {dirent_set_errno (ENOENT);return NULL;}/* Allocate new _WDIR structure */dirp (_WDIR*) malloc (sizeof (struct _WDIR));if (!dirp) {return NULL;}/* Reset _WDIR structure */dirp-handle INVALID_HANDLE_VALUE;dirp-patt NULL;dirp-cached 0;/** Compute the length of full path plus zero terminator** Note that on WinRT theres no way to convert relative paths* into absolute paths, so just assume it is an absolute path.*/
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)/* Desktop */n GetFullPathNameW (dirname, 0, NULL, NULL);
#else/* WinRT */n wcslen (dirname);
#endif/* Allocate room for absolute directory name and search pattern */dirp-patt (wchar_t*) malloc (sizeof (wchar_t) * n 16);if (dirp-patt NULL) {goto exit_closedir;}/** Convert relative directory name to an absolute one. This* allows rewinddir() to function correctly even when current* working directory is changed between opendir() and rewinddir().** Note that on WinRT theres no way to convert relative paths* into absolute paths, so just assume it is an absolute path.*/
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)/* Desktop */n GetFullPathNameW (dirname, n, dirp-patt, NULL);if (n 0) {goto exit_closedir;}
#else/* WinRT */wcsncpy_s (dirp-patt, n1, dirname, n);
#endif/* Append search pattern \* to the directory name */p dirp-patt n;switch (p[-1]) {case \\:case /:case ::/* Directory ends in path separator, e.g. c:\temp\ *//*NOP*/;break;default:/* Directory name doesnt end in path separator */*p \\;}*p *;*p \0;/* Open directory stream and retrieve the first entry */if (!dirent_first (dirp)) {goto exit_closedir;}/* Success */return dirp;/* Failure */
exit_closedir:_wclosedir (dirp);return NULL;
}/** Read next directory entry.** Returns pointer to static directory entry which may be overwritten by* subsequent calls to _wreaddir().*/
static struct _wdirent*
_wreaddir(_WDIR *dirp)
{struct _wdirent *entry;/** Read directory entry to buffer. We can safely ignore the return value* as entry will be set to NULL in case of error.*/(void) _wreaddir_r (dirp, dirp-ent, entry);/* Return pointer to statically allocated directory entry */return entry;
}/** Read next directory entry.** Returns zero on success. If end of directory stream is reached, then sets* result to NULL and returns zero.*/
static int
_wreaddir_r(_WDIR *dirp,struct _wdirent *entry,struct _wdirent **result)
{WIN32_FIND_DATAW *datap;/* Read next directory entry */datap dirent_next (dirp);if (datap) {size_t n;DWORD attr;/** Copy file name as wide-character string. If the file name is too* long to fit in to the destination buffer, then truncate file name* to PATH_MAX characters and zero-terminate the buffer.*/n 0;while (n PATH_MAX datap-cFileName[n] ! 0) {entry-d_name[n] datap-cFileName[n];n;}entry-d_name[n] 0;/* Length of file name excluding zero terminator */entry-d_namlen n;/* File type */attr datap-dwFileAttributes;if ((attr FILE_ATTRIBUTE_DEVICE) ! 0) {entry-d_type DT_CHR;} else if ((attr FILE_ATTRIBUTE_DIRECTORY) ! 0) {entry-d_type DT_DIR;} else {entry-d_type DT_REG;}/* Reset dummy fields */entry-d_ino 0;entry-d_off 0;entry-d_reclen sizeof (struct _wdirent);/* Set result address */*result entry;} else {/* Return NULL to indicate end of directory */*result NULL;}return /*OK*/0;
}/** Close directory stream opened by opendir() function. This invalidates the* DIR structure as well as any directory entry read previously by* _wreaddir().*/
static int
_wclosedir(_WDIR *dirp)
{int ok;if (dirp) {/* Release search handle */if (dirp-handle ! INVALID_HANDLE_VALUE) {FindClose (dirp-handle);}/* Release search pattern */free (dirp-patt);/* Release directory structure */free (dirp);ok /*success*/0;} else {/* Invalid directory stream */dirent_set_errno (EBADF);ok /*failure*/-1;}return ok;
}/** Rewind directory stream such that _wreaddir() returns the very first* file name again.*/
static void
_wrewinddir(_WDIR* dirp)
{if (dirp) {/* Release existing search handle */if (dirp-handle ! INVALID_HANDLE_VALUE) {FindClose (dirp-handle);}/* Open new search handle */dirent_first (dirp);}
}/* Get first directory entry (internal) */
static WIN32_FIND_DATAW*
dirent_first(_WDIR *dirp)
{WIN32_FIND_DATAW *datap;DWORD error;/* Open directory and retrieve the first entry */dirp-handle FindFirstFileExW(dirp-patt, FindExInfoStandard, dirp-data,FindExSearchNameMatch, NULL, 0);if (dirp-handle ! INVALID_HANDLE_VALUE) {/* a directory entry is now waiting in memory */datap dirp-data;dirp-cached 1;} else {/* Failed to open directory: no directory entry in memory */dirp-cached 0;datap NULL;/* Set error code */error GetLastError ();switch (error) {case ERROR_ACCESS_DENIED:/* No read access to directory */dirent_set_errno (EACCES);break;case ERROR_DIRECTORY:/* Directory name is invalid */dirent_set_errno (ENOTDIR);break;case ERROR_PATH_NOT_FOUND:default:/* Cannot find the file */dirent_set_errno (ENOENT);}}return datap;
}/** Get next directory entry (internal).** Returns*/
static WIN32_FIND_DATAW*
dirent_next(_WDIR *dirp)
{WIN32_FIND_DATAW *p;/* Get next directory entry */if (dirp-cached ! 0) {/* A valid directory entry already in memory */p dirp-data;dirp-cached 0;} else if (dirp-handle ! INVALID_HANDLE_VALUE) {/* Get the next directory entry from stream */if (FindNextFileW (dirp-handle, dirp-data) ! FALSE) {/* Got a file */p dirp-data;} else {/* The very last entry has been processed or an error occurred */FindClose (dirp-handle);dirp-handle INVALID_HANDLE_VALUE;p NULL;}} else {/* End of directory stream reached */p NULL;}return p;
}/** Open directory stream using plain old C-string.*/
static DIR*
opendir(const char *dirname)
{struct DIR *dirp;/* Must have directory name */if (dirname NULL || dirname[0] \0) {dirent_set_errno (ENOENT);return NULL;}/* Allocate memory for DIR structure */dirp (DIR*) malloc (sizeof (struct DIR));if (!dirp) {return NULL;}{int error;wchar_t wname[PATH_MAX 1];size_t n;/* Convert directory name to wide-character string */error dirent_mbstowcs_s(n, wname, PATH_MAX 1, dirname, PATH_MAX 1);if (error) {/** Cannot convert file name to wide-character string. This* occurs if the string contains invalid multi-byte sequences or* the output buffer is too small to contain the resulting* string.*/goto exit_free;}/* Open directory stream using wide-character name */dirp-wdirp _wopendir (wname);if (!dirp-wdirp) {goto exit_free;}}/* Success */return dirp;/* Failure */
exit_free:free (dirp);return NULL;
}/** Read next directory entry.*/
static struct dirent*
readdir(DIR *dirp)
{struct dirent *entry;/** Read directory entry to buffer. We can safely ignore the return value* as entry will be set to NULL in case of error.*/(void) readdir_r (dirp, dirp-ent, entry);/* Return pointer to statically allocated directory entry */return entry;
}/** Read next directory entry into called-allocated buffer.** Returns zero on success. If the end of directory stream is reached, then* sets result to NULL and returns zero.*/
static int
readdir_r(DIR *dirp,struct dirent *entry,struct dirent **result)
{WIN32_FIND_DATAW *datap;/* Read next directory entry */datap dirent_next (dirp-wdirp);if (datap) {size_t n;int error;/* Attempt to convert file name to multi-byte string */error dirent_wcstombs_s(n, entry-d_name, PATH_MAX 1, datap-cFileName, PATH_MAX 1);/** If the file name cannot be represented by a multi-byte string,* then attempt to use old 83 file name. This allows traditional* Unix-code to access some file names despite of unicode* characters, although file names may seem unfamiliar to the user.** Be ware that the code below cannot come up with a short file* name unless the file system provides one. At least* VirtualBox shared folders fail to do this.*/if (error datap-cAlternateFileName[0] ! \0) {error dirent_wcstombs_s(n, entry-d_name, PATH_MAX 1,datap-cAlternateFileName, PATH_MAX 1);}if (!error) {DWORD attr;/* Length of file name excluding zero terminator */entry-d_namlen n - 1;/* File attributes */attr datap-dwFileAttributes;if ((attr FILE_ATTRIBUTE_DEVICE) ! 0) {entry-d_type DT_CHR;} else if ((attr FILE_ATTRIBUTE_DIRECTORY) ! 0) {entry-d_type DT_DIR;} else {entry-d_type DT_REG;}/* Reset dummy fields */entry-d_ino 0;entry-d_off 0;entry-d_reclen sizeof (struct dirent);} else {/** Cannot convert file name to multi-byte string so construct* an erroneous directory entry and return that. Note that* we cannot return NULL as that would stop the processing* of directory entries completely.*/entry-d_name[0] ?;entry-d_name[1] \0;entry-d_namlen 1;entry-d_type DT_UNKNOWN;entry-d_ino 0;entry-d_off -1;entry-d_reclen 0;}/* Return pointer to directory entry */*result entry;} else {/* No more directory entries */*result NULL;}return /*OK*/0;
}/** Close directory stream.*/
static int
closedir(DIR *dirp)
{int ok;if (dirp) {/* Close wide-character directory stream */ok _wclosedir (dirp-wdirp);dirp-wdirp NULL;/* Release multi-byte character version */free (dirp);} else {/* Invalid directory stream */dirent_set_errno (EBADF);ok /*failure*/-1;}return ok;
}/** Rewind directory stream to beginning.*/
static void
rewinddir(DIR* dirp)
{/* Rewind wide-character string directory stream */_wrewinddir (dirp-wdirp);
}/** Scan directory for entries.*/
static int
scandir(const char *dirname,struct dirent ***namelist,int (*filter)(const struct dirent*),int (*compare)(const struct dirent**, const struct dirent**))
{struct dirent **files NULL;size_t size 0;size_t allocated 0;const size_t init_size 1;DIR *dir NULL;struct dirent *entry;struct dirent *tmp NULL;size_t i;int result 0;/* Open directory stream */dir opendir (dirname);if (dir) {/* Read directory entries to memory */while (1) {/* Enlarge pointer table to make room for another pointer */if (size allocated) {void *p;size_t num_entries;/* Compute number of entries in the enlarged pointer table */if (size init_size) {/* Allocate initial pointer table */num_entries init_size;} else {/* Double the size */num_entries size * 2;}/* Allocate first pointer table or enlarge existing table */p realloc (files, sizeof (void*) * num_entries);if (p ! NULL) {/* Got the memory */files (dirent**) p;allocated num_entries;} else {/* Out of memory */result -1;break;}}/* Allocate room for temporary directory entry */if (tmp NULL) {tmp (struct dirent*) malloc (sizeof (struct dirent));if (tmp NULL) {/* Cannot allocate temporary directory entry */result -1;break;}}/* Read directory entry to temporary area */if (readdir_r (dir, tmp, entry) /*OK*/0) {/* Did we get an entry? */if (entry ! NULL) {int pass;/* Determine whether to include the entry in result */if (filter) {/* Let the filter function decide */pass filter (tmp);} else {/* No filter function, include everything */pass 1;}if (pass) {/* Store the temporary entry to pointer table */files[size] tmp;tmp NULL;/* Keep up with the number of files */result;}} else {/** End of directory stream reached sort entries and* exit.*/qsort (files, size, sizeof (void*),(int (*) (const void*, const void*)) compare);break;}} else {/* Error reading directory entry */result /*Error*/ -1;break;}}} else {/* Cannot open directory */result /*Error*/ -1;}/* Release temporary directory entry */free (tmp);/* Release allocated memory on error */if (result 0) {for (i 0; i size; i) {free (files[i]);}free (files);files NULL;}/* Close directory stream */if (dir) {closedir (dir);}/* Pass pointer table to caller */if (namelist) {*namelist files;}return result;
}/* Alphabetical sorting */
static int
alphasort(const struct dirent **a, const struct dirent **b)
{return strcoll ((*a)-d_name, (*b)-d_name);
}/* Sort versions */
static int
versionsort(const struct dirent **a, const struct dirent **b)
{/* FIXME: implement strverscmp and use that */return alphasort (a, b);
}/* Convert multi-byte string to wide character string */
static int
dirent_mbstowcs_s(size_t *pReturnValue,wchar_t *wcstr,size_t sizeInWords,const char *mbstr,size_t count)
{int error;#if defined(_MSC_VER) _MSC_VER 1400/* Microsoft Visual Studio 2005 or later */error mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);#else/* Older Visual Studio or non-Microsoft compiler */size_t n;/* Convert to wide-character string (or count characters) */n mbstowcs (wcstr, mbstr, sizeInWords);if (!wcstr || n count) {/* Zero-terminate output buffer */if (wcstr sizeInWords) {if (n sizeInWords) {n sizeInWords - 1;}wcstr[n] 0;}/* Length of resulting multi-byte string WITH zero terminator */if (pReturnValue) {*pReturnValue n 1;}/* Success */error 0;} else {/* Could not convert string */error 1;}#endifreturn error;
}/* Convert wide-character string to multi-byte string */
static int
dirent_wcstombs_s(size_t *pReturnValue,char *mbstr,size_t sizeInBytes, /* max size of mbstr */const wchar_t *wcstr,size_t count)
{int error;#if defined(_MSC_VER) _MSC_VER 1400/* Microsoft Visual Studio 2005 or later */error wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);#else/* Older Visual Studio or non-Microsoft compiler */size_t n;/* Convert to multi-byte string (or count the number of bytes needed) */n wcstombs (mbstr, wcstr, sizeInBytes);if (!mbstr || n count) {/* Zero-terminate output buffer */if (mbstr sizeInBytes) {if (n sizeInBytes) {n sizeInBytes - 1;}mbstr[n] \0;}/* Length of resulting multi-bytes string WITH zero-terminator */if (pReturnValue) {*pReturnValue n 1;}/* Success */error 0;} else {/* Cannot convert string */error 1;}#endifreturn error;
}/* Set errno variable */
static void
dirent_set_errno(int error)
{
#if defined(_MSC_VER) _MSC_VER 1400/* Microsoft Visual Studio 2005 and later */_set_errno (error);#else/* Non-Microsoft compiler or older Microsoft compiler */errno error;#endif
}#ifdef __cplusplus
}
#endif
#endif /*DIRENT_H*/ 注意以上写死了模型路径为 ./model/best.onnx数据配置文件路径为 ./cfg/plane.yaml测试图像放在 ./images 路径下。将这些资源放到编译后生成的 C:\Users…\YOLOv8-Test\Test\x64\Release或Debug 目录下 现在双击 Test.exe 就能看到 YOLOv8 的识别结果了 最后的问题是如果在 vscode 里点击运行还是会报错找不到资源这是因为工作目录还在根目录修改属性页-调试 - 工作目录为 $(OutDir) 即可