首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

C++ TensorRT yolov8

  • 25-02-19 03:42
  • 3137
  • 11321
blog.csdn.net

目录

效果

项目

代码

下载


效果

C++ TensorRT yolov8

项目

电脑环境

处理器:AMD Ryzen 7 7735H with Radeon Graphics 3.20 GHz
内存:16.0 GB 
显卡:NVIDIA GeForce RTX 4060 Laptop GPU
操作系统:Windows 10 企业版
opencv-4.8.1
CUDA12.4
TensorRT-8.6.1.6
VS2022

包含目录

库目录

附件依赖项

cublas.lib
cublasLt.lib
cuda.lib
cudadevrt.lib
cudart.lib
cudart_static.lib
cudnn.lib
cudnn64_8.lib
cudnn_adv_infer.lib
cudnn_adv_infer64_8.lib
cudnn_adv_train.lib
cudnn_adv_train64_8.lib
cudnn_cnn_infer.lib
cudnn_cnn_infer64_8.lib
cudnn_cnn_train.lib
cudnn_cnn_train64_8.lib
cudnn_ops_infer.lib
cudnn_ops_infer64_8.lib
cudnn_ops_train.lib
cudnn_ops_train64_8.lib
cufft.lib
cufftw.lib
cufilt.lib
curand.lib
cusolver.lib
cusolverMg.lib
cusparse.lib
nppc.lib
nppial.lib
nppicc.lib
nppidei.lib
nppif.lib
nppig.lib
nppim.lib
nppist.lib
nppisu.lib
nppitc.lib
npps.lib
nvblas.lib
nvJitLink.lib
nvJitLink_static.lib
nvjpeg.lib
nvml.lib
nvptxcompiler_static.lib
nvrtc-builtins_static.lib
nvrtc.lib
nvrtc_static.lib
OpenCL.lib
nvinfer.lib
nvinfer_dispatch.lib
nvinfer_lean.lib
nvinfer_plugin.lib
nvinfer_vc_plugin.lib
nvonnxparser.lib
nvparsers.lib
opencv_world481.lib

代码

#define _CRT_SECURE_NO_DEPRECATE

#include
#include
#include
#include
#include
#include
#include "NvInfer.h"

std::vectorstring> labels;
float score_threshold = 0.3f;
float nms_threshold = 0.5f;
int input_h = 640;
int input_w = 640;

std::string lable_path = "model/lable.txt";
std::string engin_path = "model/yolov8n.engine";
std::string video_path = "test/VID_2K.mp4";

NvinferStruct* p = nullptr;
Logger logger;

int w = 0;
int h = 0;
float x_factor = 0;
float y_factor = 0;
std::vector input_image;

float* output_data = nullptr;
size_t output_size = 0;

double preprocessTime = 0;
double inferTime = 0;
double postprocessTime = 0;
double totalTime = 0;
double detFps = 0;

int init() {

    std::ifstream lable_file(lable_path);
    if (!lable_file.is_open())
    {
        std::cerr << "Error opening file: " << lable_path << std::endl;
        return -1;
    }
    std::string line;
    while (std::getline(lable_file, line))
    {
        if (!line.empty())
        {
            labels.push_back(line);
        }
    }
    lable_file.close();

    // 以二进制方式读取文件
    std::ifstream engin_file(engin_path.data(), std::ios::binary);
    if (!engin_file.good()) {
        std::cerr << "文件无法打开,请确定文件是否可用!" << std::endl;
        return -1;
    }
    size_t size = 0;
    engin_file.seekg(0, engin_file.end);    // 将读指针从文件末尾开始移动0个字节
    size = engin_file.tellg();    // 返回读指针的位置,此时读指针的位置就是文件的字节数
    engin_file.seekg(0, engin_file.beg);    // 将读指针从文件开头开始移动0个字节
    char* modelStream = new char[size];
    engin_file.read(modelStream, size);
    engin_file.close();// 关闭文件

    //创建推理核心结构体,初始化变量
    p = new NvinferStruct();

    //初始化反序列化引擎
    p->runtime = nvinfer1::createInferRuntime(logger);

    // 初始化推理引擎
    p->engine = p->runtime->deserializeCudaEngine(modelStream, size);

    // 创建上下文
    p->context = p->engine->createExecutionContext();
    int numNode = p->engine->getNbBindings();

    // 创建gpu数据缓冲区
    p->dataBuffer = new void* [numNode];

    delete[] modelStream;

    for (int i = 0; i < numNode; i++) {
        nvinfer1::Dims dims = p->engine->getBindingDimensions(i);
        nvinfer1::DataType type = p->engine->getBindingDataType(i);
        std::vector shape(dims.d, dims.d + dims.nbDims);
        size_t size = std::accumulate(dims.d, dims.d + dims.nbDims, 1, std::multiplies());
        switch (type)
        {
        case nvinfer1::DataType::kINT32:
        case nvinfer1::DataType::kFLOAT: size *= 4; break;  // 明确为类型 float
        case nvinfer1::DataType::kHALF: size *= 2; break;
        case nvinfer1::DataType::kBOOL:
        case nvinfer1::DataType::kINT8:
        default:break;
        }
        cudaMalloc(&(p->dataBuffer[i]), size);
    }

    output_size = 1 * (labels.size() + 4) * 8400;;
    output_data = new float[output_size];

    return 0;
}

void preprocess(cv::Mat& frame) {
    //前处理
    w = frame.cols;
    h = frame.rows;
    int max = std::max(h, w);
    cv::Mat image = cv::Mat::zeros(cv::Size(max, max), CV_8UC3);
    cv::Rect roi(0, 0, w, h);
    frame.copyTo(image(roi));
    x_factor = image.cols / static_cast(input_w);
    y_factor = image.rows / static_cast(input_h);
    cv::resize(image, image, cv::Size(input_w, input_h));
    cv::cvtColor(image, image, cv::COLOR_BGR2RGB);
    std::vector bgrChannels(3);
    cv::split(image, bgrChannels);
    for (int c = 0; c < 3; c++)
    {
        bgrChannels[c].convertTo(bgrChannels[c], CV_32FC1, 1.0 / 255.0);
    }
    std::vector input_image;
    int image_area = input_h * input_w;
    input_image.clear();
    input_image.resize(3 * image_area);
    size_t single_chn_size = image_area * sizeof(float);
    memcpy(input_image.data(), (float*)bgrChannels[0].data, single_chn_size);
    memcpy(input_image.data() + image_area, (float*)bgrChannels[1].data, single_chn_size);
    memcpy(input_image.data() + image_area * 2, (float*)bgrChannels[2].data, single_chn_size);

    cudaMemcpy(p->dataBuffer[0], input_image.data(), input_image.size() * sizeof(float), cudaMemcpyHostToDevice);
}

void postprocess(std::vector& detectionResult) {


    cudaMemcpy(output_data, p->dataBuffer[1], output_size * sizeof(float), cudaMemcpyDeviceToHost);

    cv::Mat dout(labels.size() + 4, 8400, CV_32F, output_data);
    cv::Mat det_output = dout.t();

    std::vector boxes;
    std::vector classIds;
    std::vector confidences;

    for (int i = 0; i < det_output.rows; i++)
    {
        cv::Mat classes_scores = det_output.row(i).colRange(4, labels.size() + 4);
        cv::Point classIdPoint;
        double score;
        cv::minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint);

        if (score > score_threshold)
        {
            float cx = det_output.at(i, 0);
            float cy = det_output.at(i, 1);
            float ow = det_output.at(i, 2);
            float oh = det_output.at(i, 3);
            int x = static_cast((cx - 0.5 * ow) * x_factor);
            int y = static_cast((cy - 0.5 * oh) * y_factor);
            int width = static_cast(ow * x_factor);
            int height = static_cast(oh * y_factor);

            // 坐标值安全校验
            if (x < 0)x = 0;
            if (y < 0)y = 0;

            if (x > w)x = w;
            if (y > h)y = h;

            if (x + width > w)width = w - x;
            if (y + height > h)height = h - y;

            cv::Rect box;
            box.x = x;
            box.y = y;
            box.width = width;
            box.height = height;

            boxes.push_back(box);
            classIds.push_back(classIdPoint.x);
            confidences.push_back(score);
        }
    }

    std::vector indexes;
    cv::dnn::NMSBoxes(boxes, confidences, score_threshold, nms_threshold, indexes);


    for (size_t i = 0; i < indexes.size(); i++)
    {
        int index = indexes[i];
        detresult box(labels[classIds[index]], classIds[index], confidences[index], boxes[index]);
        detectionResult.push_back(box);
    }

}

void draw(cv::Mat& frame, std::vector& detectionResult) {

    for (size_t i = 0; i < detectionResult.size(); ++i)
    {
        detresult box = detectionResult[i];
        cv::rectangle(frame, box.rect, cv::Scalar(0, 0, 255), 2);
        std::string label = box.className + ":" + cv::format("%.2f", box.confidence);
        putText(frame, label, cv::Point(box.rect.x, box.rect.y - 5), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
    }

    // 绘制时间
    putText(frame, "preprocessTime:" + std::to_string(preprocessTime * 1000) + "ms", cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
    putText(frame, "inferTime:" + std::to_string(inferTime * 1000) + "ms", cv::Point(10, 70), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
    putText(frame, "postprocessTime:" + std::to_string(postprocessTime * 1000) + "ms", cv::Point(10, 110), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
    putText(frame, "totalTime:" + std::to_string(totalTime * 1000) + "ms", cv::Point(10, 150), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
    putText(frame, "detFps:" + std::to_string(detFps), cv::Point(10, 190), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);

    cv::imshow("detresult", frame);

}

void destroy() {

    delete output_data;
    delete p->dataBuffer;
    p->context->destroy();
    p->engine->destroy();
    p->runtime->destroy();
    delete p;
}

int main()
{
    init();

    //cv::Mat frame = cv::imread(img_path);
    //cv::imshow("1.jpg", frame);
    //cv::waitKey(0);

    cv::VideoCapture capture(video_path);
    // 检查视频是否成功打开
    if (!capture.isOpened())
    {
        std::cout << "无法读取视频文件" << std::endl;
        return -1;
    }

    double fps = capture.get(cv::CAP_PROP_FPS);
    int width = static_cast(capture.get(cv::CAP_PROP_FRAME_WIDTH));
    int height = static_cast(capture.get(cv::CAP_PROP_FRAME_HEIGHT));

    cv::Mat frame;
    while (true)
    {
        bool success = capture.read(frame); // 读取一帧数据
        // 检查是否成功读取帧
        if (!success)
        {
            std::cout << "读取完毕" << std::endl;
            break;
        }

        double start = (double)cv::getTickCount();
        preprocess(frame);
        preprocessTime = ((double)cv::getTickCount() - start) / cv::getTickFrequency();

        //推理
        start = (double)cv::getTickCount();
        p->context->executeV2(p->dataBuffer);
        inferTime = ((double)cv::getTickCount() - start) / cv::getTickFrequency();

        //后处理
        start = (double)cv::getTickCount();
        std::vector detectionResult;
        postprocess(detectionResult);
        postprocessTime = ((double)cv::getTickCount() - start) / cv::getTickFrequency();

        totalTime = preprocessTime + inferTime + postprocessTime;
        detFps = (1 / (totalTime));

        //绘制、显示
        cv::namedWindow("detresult", cv::WINDOW_NORMAL); // cv::WINDOW_NORMAL允许用户调整窗口大小
        cv::resizeWindow("detresult", width / 2, height / 2); // 设置窗口的宽度和高度
        draw(frame, detectionResult);

        if (cv::waitKey(1) == 27) // 通过按下ESC键退出循环
        {
            break;
        }
    }

    destroy();

    cv::destroyAllWindows();
    getchar();

    return 0;
}

  1. #define _CRT_SECURE_NO_DEPRECATE
  2. #include <iostream>
  3. #include <opencv2/opencv.hpp>
  4. #include <opencv2/imgproc.hpp>
  5. #include <opencv2/highgui.hpp>
  6. #include <fstream>
  7. #include <numeric>
  8. #include "NvInfer.h"
  9. std::vector<std::string> labels;
  10. float score_threshold = 0.3f;
  11. float nms_threshold = 0.5f;
  12. int input_h = 640;
  13. int input_w = 640;
  14. std::string lable_path = "model/lable.txt";
  15. std::string engin_path = "model/yolov8n.engine";
  16. std::string video_path = "test/VID_2K.mp4";
  17. NvinferStruct* p = nullptr;
  18. Logger logger;
  19. int w = 0;
  20. int h = 0;
  21. float x_factor = 0;
  22. float y_factor = 0;
  23. std::vector<float> input_image;
  24. float* output_data = nullptr;
  25. size_t output_size = 0;
  26. double preprocessTime = 0;
  27. double inferTime = 0;
  28. double postprocessTime = 0;
  29. double totalTime = 0;
  30. double detFps = 0;
  31. int init() {
  32. std::ifstream lable_file(lable_path);
  33. if (!lable_file.is_open())
  34. {
  35. std::cerr << "Error opening file: " << lable_path << std::endl;
  36. return -1;
  37. }
  38. std::string line;
  39. while (std::getline(lable_file, line))
  40. {
  41. if (!line.empty())
  42. {
  43. labels.push_back(line);
  44. }
  45. }
  46. lable_file.close();
  47. // 以二进制方式读取文件
  48. std::ifstream engin_file(engin_path.data(), std::ios::binary);
  49. if (!engin_file.good()) {
  50. std::cerr << "文件无法打开,请确定文件是否可用!" << std::endl;
  51. return -1;
  52. }
  53. size_t size = 0;
  54. engin_file.seekg(0, engin_file.end); // 将读指针从文件末尾开始移动0个字节
  55. size = engin_file.tellg(); // 返回读指针的位置,此时读指针的位置就是文件的字节数
  56. engin_file.seekg(0, engin_file.beg); // 将读指针从文件开头开始移动0个字节
  57. char* modelStream = new char[size];
  58. engin_file.read(modelStream, size);
  59. engin_file.close();// 关闭文件
  60. //创建推理核心结构体,初始化变量
  61. p = new NvinferStruct();
  62. //初始化反序列化引擎
  63. p->runtime = nvinfer1::createInferRuntime(logger);
  64. // 初始化推理引擎
  65. p->engine = p->runtime->deserializeCudaEngine(modelStream, size);
  66. // 创建上下文
  67. p->context = p->engine->createExecutionContext();
  68. int numNode = p->engine->getNbBindings();
  69. // 创建gpu数据缓冲区
  70. p->dataBuffer = new void* [numNode];
  71. delete[] modelStream;
  72. for (int i = 0; i < numNode; i++) {
  73. nvinfer1::Dims dims = p->engine->getBindingDimensions(i);
  74. nvinfer1::DataType type = p->engine->getBindingDataType(i);
  75. std::vector<int> shape(dims.d, dims.d + dims.nbDims);
  76. size_t size = std::accumulate(dims.d, dims.d + dims.nbDims, 1, std::multiplies<size_t>());
  77. switch (type)
  78. {
  79. case nvinfer1::DataType::kINT32:
  80. case nvinfer1::DataType::kFLOAT: size *= 4; break; // 明确为类型 float
  81. case nvinfer1::DataType::kHALF: size *= 2; break;
  82. case nvinfer1::DataType::kBOOL:
  83. case nvinfer1::DataType::kINT8:
  84. default:break;
  85. }
  86. cudaMalloc(&(p->dataBuffer[i]), size);
  87. }
  88. output_size = 1 * (labels.size() + 4) * 8400;;
  89. output_data = new float[output_size];
  90. return 0;
  91. }
  92. void preprocess(cv::Mat& frame) {
  93. //前处理
  94. w = frame.cols;
  95. h = frame.rows;
  96. int max = std::max(h, w);
  97. cv::Mat image = cv::Mat::zeros(cv::Size(max, max), CV_8UC3);
  98. cv::Rect roi(0, 0, w, h);
  99. frame.copyTo(image(roi));
  100. x_factor = image.cols / static_cast<float>(input_w);
  101. y_factor = image.rows / static_cast<float>(input_h);
  102. cv::resize(image, image, cv::Size(input_w, input_h));
  103. cv::cvtColor(image, image, cv::COLOR_BGR2RGB);
  104. std::vector<cv::Mat> bgrChannels(3);
  105. cv::split(image, bgrChannels);
  106. for (int c = 0; c < 3; c++)
  107. {
  108. bgrChannels[c].convertTo(bgrChannels[c], CV_32FC1, 1.0 / 255.0);
  109. }
  110. std::vector<float> input_image;
  111. int image_area = input_h * input_w;
  112. input_image.clear();
  113. input_image.resize(3 * image_area);
  114. size_t single_chn_size = image_area * sizeof(float);
  115. memcpy(input_image.data(), (float*)bgrChannels[0].data, single_chn_size);
  116. memcpy(input_image.data() + image_area, (float*)bgrChannels[1].data, single_chn_size);
  117. memcpy(input_image.data() + image_area * 2, (float*)bgrChannels[2].data, single_chn_size);
  118. cudaMemcpy(p->dataBuffer[0], input_image.data(), input_image.size() * sizeof(float), cudaMemcpyHostToDevice);
  119. }
  120. void postprocess(std::vector<detresult>& detectionResult) {
  121. cudaMemcpy(output_data, p->dataBuffer[1], output_size * sizeof(float), cudaMemcpyDeviceToHost);
  122. cv::Mat dout(labels.size() + 4, 8400, CV_32F, output_data);
  123. cv::Mat det_output = dout.t();
  124. std::vector<cv::Rect> boxes;
  125. std::vector<int> classIds;
  126. std::vector<float> confidences;
  127. for (int i = 0; i < det_output.rows; i++)
  128. {
  129. cv::Mat classes_scores = det_output.row(i).colRange(4, labels.size() + 4);
  130. cv::Point classIdPoint;
  131. double score;
  132. cv::minMaxLoc(classes_scores, 0, &score, 0, &classIdPoint);
  133. if (score > score_threshold)
  134. {
  135. float cx = det_output.at<float>(i, 0);
  136. float cy = det_output.at<float>(i, 1);
  137. float ow = det_output.at<float>(i, 2);
  138. float oh = det_output.at<float>(i, 3);
  139. int x = static_cast<int>((cx - 0.5 * ow) * x_factor);
  140. int y = static_cast<int>((cy - 0.5 * oh) * y_factor);
  141. int width = static_cast<int>(ow * x_factor);
  142. int height = static_cast<int>(oh * y_factor);
  143. // 坐标值安全校验
  144. if (x < 0)x = 0;
  145. if (y < 0)y = 0;
  146. if (x > w)x = w;
  147. if (y > h)y = h;
  148. if (x + width > w)width = w - x;
  149. if (y + height > h)height = h - y;
  150. cv::Rect box;
  151. box.x = x;
  152. box.y = y;
  153. box.width = width;
  154. box.height = height;
  155. boxes.push_back(box);
  156. classIds.push_back(classIdPoint.x);
  157. confidences.push_back(score);
  158. }
  159. }
  160. std::vector<int> indexes;
  161. cv::dnn::NMSBoxes(boxes, confidences, score_threshold, nms_threshold, indexes);
  162. for (size_t i = 0; i < indexes.size(); i++)
  163. {
  164. int index = indexes[i];
  165. detresult box(labels[classIds[index]], classIds[index], confidences[index], boxes[index]);
  166. detectionResult.push_back(box);
  167. }
  168. }
  169. void draw(cv::Mat& frame, std::vector<detresult>& detectionResult) {
  170. for (size_t i = 0; i < detectionResult.size(); ++i)
  171. {
  172. detresult box = detectionResult[i];
  173. cv::rectangle(frame, box.rect, cv::Scalar(0, 0, 255), 2);
  174. std::string label = box.className + ":" + cv::format("%.2f", box.confidence);
  175. putText(frame, label, cv::Point(box.rect.x, box.rect.y - 5), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
  176. }
  177. // 绘制时间
  178. putText(frame, "preprocessTime:" + std::to_string(preprocessTime * 1000) + "ms", cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
  179. putText(frame, "inferTime:" + std::to_string(inferTime * 1000) + "ms", cv::Point(10, 70), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
  180. putText(frame, "postprocessTime:" + std::to_string(postprocessTime * 1000) + "ms", cv::Point(10, 110), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
  181. putText(frame, "totalTime:" + std::to_string(totalTime * 1000) + "ms", cv::Point(10, 150), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
  182. putText(frame, "detFps:" + std::to_string(detFps), cv::Point(10, 190), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);
  183. cv::imshow("detresult", frame);
  184. }
  185. void destroy() {
  186. delete output_data;
  187. delete p->dataBuffer;
  188. p->context->destroy();
  189. p->engine->destroy();
  190. p->runtime->destroy();
  191. delete p;
  192. }
  193. int main()
  194. {
  195. init();
  196. //cv::Mat frame = cv::imread(img_path);
  197. //cv::imshow("1.jpg", frame);
  198. //cv::waitKey(0);
  199. cv::VideoCapture capture(video_path);
  200. // 检查视频是否成功打开
  201. if (!capture.isOpened())
  202. {
  203. std::cout << "无法读取视频文件" << std::endl;
  204. return -1;
  205. }
  206. double fps = capture.get(cv::CAP_PROP_FPS);
  207. int width = static_cast<int>(capture.get(cv::CAP_PROP_FRAME_WIDTH));
  208. int height = static_cast<int>(capture.get(cv::CAP_PROP_FRAME_HEIGHT));
  209. cv::Mat frame;
  210. while (true)
  211. {
  212. bool success = capture.read(frame); // 读取一帧数据
  213. // 检查是否成功读取帧
  214. if (!success)
  215. {
  216. std::cout << "读取完毕" << std::endl;
  217. break;
  218. }
  219. double start = (double)cv::getTickCount();
  220. preprocess(frame);
  221. preprocessTime = ((double)cv::getTickCount() - start) / cv::getTickFrequency();
  222. //推理
  223. start = (double)cv::getTickCount();
  224. p->context->executeV2(p->dataBuffer);
  225. inferTime = ((double)cv::getTickCount() - start) / cv::getTickFrequency();
  226. //后处理
  227. start = (double)cv::getTickCount();
  228. std::vector<detresult> detectionResult;
  229. postprocess(detectionResult);
  230. postprocessTime = ((double)cv::getTickCount() - start) / cv::getTickFrequency();
  231. totalTime = preprocessTime + inferTime + postprocessTime;
  232. detFps = (1 / (totalTime));
  233. //绘制、显示
  234. cv::namedWindow("detresult", cv::WINDOW_NORMAL); // cv::WINDOW_NORMAL允许用户调整窗口大小
  235. cv::resizeWindow("detresult", width / 2, height / 2); // 设置窗口的宽度和高度
  236. draw(frame, detectionResult);
  237. if (cv::waitKey(1) == 27) // 通过按下ESC键退出循环
  238. {
  239. break;
  240. }
  241. }
  242. destroy();
  243. cv::destroyAllWindows();
  244. getchar();
  245. return 0;
  246. }

下载

源码下载

天天代码码天天
微信公众号
.NET 人工智能实践
注:本文转载自blog.csdn.net的天天代码码天天的文章"https://lw112190.blog.csdn.net/article/details/143225616"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top