自动驾驶多任务框架Hybridnets——同时处理车辆检测、可驾驶区域分割、车道线分割模型部署(C++/Python)

news2025/1/17 1:32:35

一、多感知任务

在移动机器人的感知系统,包括自动驾驶汽车和无人机,会使用多种传感器来获取关键信息,从而实现对环境的感知和物体检测。这些传感器包括相机、激光雷达、雷达、惯性测量单元(IMU)、全球导航卫星系统(GNSS)等。在自动驾驶和移动机器人的感知系统里面,相机的功能主要是周围的物体,这些感知任务包括任务包括物体检测和分割。
物体检测:物体检测是指通过处理传感器数据来检测环境中的物体,如汽车、行人、骑自行车的人、红绿灯等。YOLO系列网络是常用于实时物体检测的解决方案。这些网络可以实时识别多个物体,并提供它们的位置和边界框。
在这里插入图片描述

实例分割:实例分割是一项更复杂的任务,它不仅可以检测物体,还可以将它们分割成属于不同实例的部分。这对于跟踪和识别不同的车辆或行人非常有用。通常,Mask R-CNN等网络用于实例分割。
在这里插入图片描述

语义分割:语义分割是将图像中的每个像素分配到特定的语义类别的任务,例如将道路、建筑物、车辆等分割成不同的区域。U-Net和全卷积网络(FCN)等CNN架构通常用于语义分割。
在处理这些任务时,有两种主要方法可以考虑:
单一模型:开发一个单一的神经网络模型,可以同时处理多个感知任务,如检测、分割。这种方法可以提高计算效率,但需要大量的训练数据和复杂的网络结构。
多模型集成:使用多个独立的模型来处理不同的感知任务,每个模型专注于一个任务。这种方法可以更容易地处理不同任务之间的数据不平衡,并且可以根据任务的重要性对不同模型进行资源分配。

二、Hybridnets多任务框架

Hybridnets一种多任务处理的端到端多感知网络,它提出了几种关键的优化方法以提高精度。

  1. 引入了基于加权双向特征网络的高效分割头和边界框/类别预测网络。
  2. 提出了加权双向特征网络中各层的自动定制锚定方法。
  3. 提出了一种有效的训练损失函数和训练策略,以平衡和优化网络性能。

基于这些优化,Hybridnets开发了一种端到端感知网络,用于执行多任务处理,包括交通目标检测、可驾驶区域分割和车道线检测,将其称为混合网。混合网在伯克利DeepDrive数据集上表现出色,平均精度达到了77.3%,平均交并比为31.6%,并且参数数量仅为1283万,浮点操作数为156亿。此外,它能够实时执行视觉感知任务,因此是一个实用而准确的多任务处理解决方案。
在这里插入图片描述
算法源码:https://github.com/datvuthanh/HybridNets.git

三、使用C++进行模型部署

把训练好的模型转成onnx格式的模型,然后使用OpenCV 4.6 和contrib dnn模块进行推理,使用的IDE是Vs 2019。
首先定义一人模型推理的类,这里使用为了方便演示,只用CPU进行推理。

struct Net_config
{
	float confThreshold; 
	float nmsThreshold; 
	std::string modelpath;
	std::string anchorpath;
};

class HybridNets
{
public:
	HybridNets(Net_config config);
	cv::Mat detect(cv::Mat frame); 
	~HybridNets(); 
private:
	int inpWidth;
	int inpHeight;
	std::vector<std::string> det_class_names = { "car" };
	std::vector<std::string> seg_class_names = { "Background", "Lane", "Line" };
	int det_num_class;
	int seg_numclass;

	float confThreshold;
	float nmsThreshold;
	cv::dnn::Net net;
	float* anchors = nullptr;
	const float mean_[3] = { 0.485, 0.456, 0.406 };
	const float std_[3] = { 0.229, 0.224, 0.225 };
	const bool keep_ratio = true;
	cv::Mat resize_image(cv::Mat srcimg, int* newh, int* neww, int* padh, int* padw);
	cv::Mat normalize_(cv::Mat img);
	std::vector<cv::Vec3b> class_colors = { cv::Vec3b(0,0,0), cv::Vec3b(0, 255, 0), cv::Vec3b(255, 0, 0) };
};

HybridNets::HybridNets(Net_config config)
{
	this->confThreshold = config.confThreshold;
	this->nmsThreshold = config.nmsThreshold;

	this->net = cv::dnn::readNet(config.modelpath); 
	this->det_num_class = det_class_names.size();
	this->seg_numclass = seg_class_names.size();

	size_t pos = config.modelpath.rfind("_");
	size_t pos_ = config.modelpath.rfind(".");
	int len = pos_ - pos - 1;
	std::string hxw = config.modelpath.substr(pos + 1, len);

	pos = hxw.rfind("x");
	std::string h = hxw.substr(0, pos);
	len = hxw.length() - pos;
	std::string w = hxw.substr(pos + 1, len);
	this->inpHeight = stoi(h);
	this->inpWidth = stoi(w);

	pos = config.anchorpath.rfind("_");
	pos_ = config.anchorpath.rfind(".");
	len = pos_ - pos - 1;
	std::string len_ = config.anchorpath.substr(pos + 1, len);
	len = stoi(len_);
	this->anchors = new float[len];
	FILE* fp = fopen(config.anchorpath.c_str(), "rb");
	fread(this->anchors, sizeof(float), len, fp);
	fclose(fp);
}

HybridNets::~HybridNets()
{
	delete[] anchors;
	anchors = nullptr;
}

cv::Mat HybridNets::resize_image(cv::Mat srcimg, int* newh, int* neww, int* padh, int* padw)
{
	int srch = srcimg.rows, srcw = srcimg.cols;
	*newh = this->inpHeight;
	*neww = this->inpWidth;
	cv::Mat dstimg;
	if (this->keep_ratio && srch != srcw) {
		float hw_scale = (float)srch / srcw;
		if (hw_scale > 1) {
			*newh = this->inpHeight;
			*neww = int(this->inpWidth / hw_scale);
			resize(srcimg, dstimg, cv::Size(*neww, *newh), cv::INTER_LINEAR);
			*padw = int((this->inpWidth - *neww) * 0.5);
			copyMakeBorder(dstimg, dstimg, 0, 0, *padw, this->inpWidth - *neww - *padw, cv::BORDER_CONSTANT, 114);
		}
		else {
			*newh = (int)this->inpHeight * hw_scale;
			*neww = this->inpWidth;
			resize(srcimg, dstimg, cv::Size(*neww, *newh), cv::INTER_LINEAR);
			*padh = (int)(this->inpHeight - *newh) * 0.5;
			copyMakeBorder(dstimg, dstimg, *padh, this->inpHeight - *newh - *padh, 0, 0, cv::BORDER_CONSTANT, 114);
		}
	}
	else {
		resize(srcimg, dstimg, cv::Size(*neww, *newh), cv::INTER_LINEAR);
	}
	return dstimg;
}

cv::Mat HybridNets::normalize_(cv::Mat img)
{
	std::vector<cv::Mat> bgrChannels(3);
	split(img, bgrChannels);
	for (int c = 0; c < 3; c++)
	{
		bgrChannels[c].convertTo(bgrChannels[c], CV_32FC1, 1.0 / (255.0 * std_[c]), (0.0 - mean_[c]) / std_[c]);
	}
	cv::Mat m_normalized_mat;
	merge(bgrChannels, m_normalized_mat);
	return m_normalized_mat;
}

cv::Mat HybridNets::detect(cv::Mat srcimg)
{
	int newh = 0, neww = 0, padh = 0, padw = 0;
	cv::Mat rgbimg;
	cvtColor(srcimg, rgbimg, cv::COLOR_BGR2RGB);
	cv::Mat dstimg = this->resize_image(rgbimg, &newh, &neww, &padh, &padw);
	cv::Mat normalized_mat = this->normalize_(dstimg);


	cv::Mat blob = cv::dnn::blobFromImage(normalized_mat);
	this->net.setInput(blob);
	std::vector<cv::Mat> outs;
	this->net.forward(outs, this->net.getUnconnectedOutLayersNames());

	float* classification = (float*)outs[0].data;
	float* box_regression = (float*)outs[1].data;
	float* seg = (float*)outs[2].data;

	std::vector<cv::Rect> boxes;
	std::vector<float> confidences;
	std::vector<int> classIds;
	float ratioh = (float)srcimg.rows / newh, ratiow = (float)srcimg.cols / neww;
	const int num_proposal = outs[1].size[1];  
	for (int n = 0; n < num_proposal; n++)
	{
		float conf = classification[n];
	
		if (conf > this->confThreshold)
		{
			const int row_ind = n * 4;
			float x_centers = box_regression[row_ind + 1] * this->anchors[row_ind + 2] + this->anchors[row_ind];
			float y_centers = box_regression[row_ind] * this->anchors[row_ind + 3] + this->anchors[row_ind + 1];
			float w = exp(box_regression[row_ind + 3]) * this->anchors[row_ind + 2];
			float h = exp(box_regression[row_ind + 2]) * this->anchors[row_ind + 3];

			float xmin = (x_centers - w * 0.5 - padw) * ratiow;
			float ymin = (y_centers - h * 0.5 - padh) * ratioh;
			w *= ratiow;
			h *= ratioh;
			cv::Rect box = cv::Rect(int(xmin), int(ymin), int(w), int(h));
			boxes.push_back(box);
			confidences.push_back(conf);
			classIds.push_back(0);
		}
	}
	
	std::vector<int> indices;
	cv::dnn::NMSBoxes(boxes, confidences, this->confThreshold, this->nmsThreshold, indices);

	cv::Mat outimg = srcimg.clone();
	for (size_t i = 0; i < indices.size(); ++i)
	{
		int idx = indices[i];
		cv::Rect box = boxes[idx];
		rectangle(outimg, cv::Point(box.x, box.y), cv::Point(box.x + box.width, box.y + box.height), cv::Scalar(0, 0, 255), 2);
		std::string label = cv::format("%.2f", confidences[idx]);
		label = this->det_class_names[classIds[idx]] + ":" + label;
		putText(outimg, label, cv::Point(box.x, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(0, 0, 255), 1);
	}

	const int area = this->inpHeight * this->inpWidth;
	int i = 0, j = 0, c = 0;
	for (i = 0; i < outimg.rows; i++)
	{
		for (j = 0; j < outimg.cols; j++)
		{
			const int x = int(j / ratiow) + padw;  
			const int y = int(i / ratioh) + padh;
			int max_id = -1;
			float max_conf = -10000;
			for (c = 0; c < seg_numclass; c++)
			{
				float seg_conf = seg[c * area + y * this->inpWidth + x];
				if (seg_conf > max_conf)
				{
					max_id = c;
					max_conf = seg_conf;
				}
			}
			if (max_id > 0)
			{
				outimg.at<cv::Vec3b>(i, j)[0] = this->class_colors[max_id][0];
				outimg.at<cv::Vec3b>(i, j)[1] = this->class_colors[max_id][1];
				outimg.at<cv::Vec3b>(i, j)[2] = this->class_colors[max_id][2];
			}
		}
	}
	return outimg;
}

读取视频,然后使用模型进行推理

int main()
{
	Net_config cfg = { 0.3, 0.5, "models/hybridnets_768x1280.onnx", "models/anchors_736560.bin" };
	HybridNets net(cfg);

	//cv::VideoWriter outputVideo;
	cv::VideoCapture cap("test2.mp4");

	//cv::Size S = cv::Size((int)cap.get(cv::CAP_PROP_FRAME_WIDTH),
		//(int)cap.get(cv::CAP_PROP_FRAME_HEIGHT));
	//std::string out_path = "dst.ma4";
	if (cap.isOpened())
	{
		//outputVideo.open(out_path, -1, 30.0, S, true);
		cv::Mat cv_fram;
		while (1)
		{
			cap.read(cv_fram);
			if (!cv_fram.empty())
			{
				cv::Mat outimg = net.detect(cv_fram);
				//outputVideo << outimg;
				cv::imshow("视频", outimg);
			}
			
			if (cv::waitKey(100) == 27)break;
		}
	}

	cap.release();
	return 0;
}

推理效果如下:
在这里插入图片描述

四、使用Python进行模型部署

import cv2
import argparse
import numpy as np
import os

print(cv2.__version__)

class HybridNets():
    def __init__(self, modelpath, anchorpath, confThreshold=0.5, nmsThreshold=0.5):
        self.det_classes = ["car"]
        self.seg_classes = ["Background", "Lane", "Line"]

        self.net = cv2.dnn.readNet(modelpath)
        self.confThreshold = confThreshold
        self.nmsThreshold = nmsThreshold
        
        h, w = os.path.basename(modelpath).split('_')[-1].replace('.onnx', '').split('x')
        self.inpHeight, self.inpWidth = int(h), int(w)
        self.mean_ = np.array([0.485, 0.456, 0.406], dtype=np.float32).reshape((1, 1, 3))
        self.std_ = np.array([0.229, 0.224, 0.225], dtype=np.float32).reshape((1, 1, 3))
        self.anchors = np.load(anchorpath)  ### cx_cy_w_h
    
    def resize_image(self, srcimg, keep_ratio=True):
        padh, padw, newh, neww = 0, 0, self.inpWidth, self.inpHeight
        if keep_ratio and srcimg.shape[0] != srcimg.shape[1]:
            hw_scale = srcimg.shape[0] / srcimg.shape[1]
            if hw_scale > 1:
                newh, neww = self.inpHeight, int(self.inpWidth / hw_scale)
                img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_LINEAR)
                padw = int((self.inpWidth - neww) * 0.5)
                img = cv2.copyMakeBorder(img, 0, 0, padw, self.inpWidth - neww - padw, cv2.BORDER_CONSTANT,
                                         value=(114, 114, 114))  # add border
            else:
                newh, neww = int(self.inpHeight * hw_scale), self.inpWidth
                img = cv2.resize(srcimg, (neww, newh), interpolation=cv2.INTER_LINEAR)
                padh = int((self.inpHeight - newh) * 0.5)
                img = cv2.copyMakeBorder(img, padh, self.inpHeight - newh - padh, 0, 0, cv2.BORDER_CONSTANT,
                                         value=(114, 114, 114))
        else:
            img = cv2.resize(srcimg, (self.inpWidth, self.inpHeight), interpolation=cv2.INTER_LINEAR)
        return img, newh, neww, padh, padw
    
    def detect(self, srcimg):
        img, newh, neww, padh, padw = self.resize_image(cv2.cvtColor(srcimg, cv2.COLOR_BGR2RGB))
        scale_h, scale_w = srcimg.shape[0] / newh, srcimg.shape[1] / neww
        img = (img.astype(np.float32) / 255.0 - self.mean_) / self.std_
        # Sets the input to the network
        blob = cv2.dnn.blobFromImage(img)
        self.net.setInput(blob)
        
        classification, box_regression, seg = self.net.forward(self.net.getUnconnectedOutLayersNames())

        x_centers = box_regression[..., 1] * self.anchors[..., 2] + self.anchors[..., 0]
        y_centers = box_regression[..., 0] * self.anchors[..., 3] + self.anchors[..., 1]
        w = np.exp(box_regression[..., 3]) * self.anchors[..., 2]
        h = np.exp(box_regression[..., 2]) * self.anchors[..., 3]

        xmin = x_centers - w * 0.5
        ymin = y_centers - h * 0.5
        
        bboxes_wh = np.stack([xmin, ymin, w, h], axis=2).squeeze(axis=0)
        
        confidences = np.max(classification.squeeze(axis=0), axis=1)  ####max_class_confidence
        classIds = np.argmax(classification.squeeze(axis=0), axis=1)
        mask = confidences > self.confThreshold
        bboxes_wh = bboxes_wh[mask]
        confidences = confidences[mask]
        classIds = classIds[mask]
        
        bboxes_wh -= np.array([[padw, padh, 0, 0]])  
        bboxes_wh *= np.array([[scale_w, scale_h, scale_w, scale_h]])
        
        indices = cv2.dnn.NMSBoxes(bboxes_wh.tolist(), confidences.tolist(), self.confThreshold,
                                   self.nmsThreshold).flatten().tolist()
        
        drive_area_mask = np.squeeze(seg, axis=0)[:, padh:(self.inpHeight - padh), padw:(self.inpWidth - padw)]
        seg_id = np.argmax(drive_area_mask, axis=0).astype(np.uint8)
        seg_id = cv2.resize(seg_id, (srcimg.shape[1], srcimg.shape[0]), interpolation=cv2.INTER_NEAREST)
     
        outimg = srcimg.copy()
        for ind in indices:
            x, y, w, h = bboxes_wh[ind,:].astype(int)
            cv2.rectangle(outimg, (x, y), (x + w, y + h), (0, 0, 255), thickness=2, lineType=cv2.LINE_AA)
            cv2.putText(outimg, self.det_classes[classIds[ind]]+ ":" + str(round(confidences[ind], 2)), (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255),
                        thickness=1, lineType=cv2.LINE_AA)

        outimg[seg_id == 1] = [0, 255, 0]
        outimg[seg_id == 2] = [255, 0, 0]
        return outimg


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--imgpath', type=str, default='images/test.jpg', help="image path")
    parser.add_argument('--modelpath', type=str, default='models/hybridnets_768x1280.onnx')
    parser.add_argument('--anchorpath', type=str, default='models/anchors_768x1280.npy')
    parser.add_argument('--confThreshold', default=0.3, type=float, help='class confidence')
    parser.add_argument('--nmsThreshold', default=0.5, type=float, help='nms iou thresh')
    args = parser.parse_args()
    
    yolonet = HybridNets(args.modelpath, args.anchorpath, confThreshold=args.confThreshold,
                         nmsThreshold=args.nmsThreshold)
    srcimg = cv2.imread(args.imgpath)
    srcimg = yolonet.detect(srcimg)
    
    cv2.namedWindow('dst', 0)
    cv2.imshow('dst', srcimg)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/998034.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux UDP编程流程

文章目录 UDP编程流程UDP协议无连接的特点UDP协议数据报的特点 UDP编程流程 UDP 提供的是无连接、不可靠的、数据报服务。服务器端和客户端没有什么本质上的区别。编程流程如下&#xff1a; socket()用来创建套接字&#xff0c;使用 udp 协议时&#xff0c;选择数据报服务 SOC…

新手小白制作产品册的攻略合集

在如今竞争激烈的市场中&#xff0c;一个精美而专业的产品册可以帮助你吸引更多的客户和提升品牌形象。然而&#xff0c;对于新手小白来说&#xff0c;制作产品册可能会显得有些困难。不用担心&#xff01;小编将告诉大家一些制作产品册的攻略&#xff0c;帮助你轻松入门 首先我…

MySQL学习问题记录

文章目录 MySQL学习问题记录1、查询记录自动根据id排序&#xff1f; MySQL学习问题记录 1、查询记录自动根据id排序&#xff1f; step1&#xff1a;建表 表项信息&#xff1a; 写入数据顺序id为10 2 7 1。查寻时返回记录顺序为1 2 7 10&#xff1f; 更新一条数据后仍然按照…

在Linux系统上用C++将主机名称转换为IPv4、IPv6地址

在Linux系统上用C将主机名称转换为IPv4、IPv6地址 功能 指定一个std::string类型的主机名称&#xff0c;函数解析主机名称为IP地址&#xff0c;含IPv4和IPv6&#xff0c;解析结果以std::vector<std::string>类型返回。解析出错或者解析失败抛出std::string类型的异常消…

第19章_瑞萨MCU零基础入门系列教程之RTC

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

【基于递归混合尺度:无监督GAN:Pansharpening】

Pansharpening Using Unsupervised Generative Adversarial Networks With Recursive Mixed-Scale Feature Fusion &#xff08;基于递归混合尺度特征融合的无监督生成对抗网络泛锐化&#xff09; 全色锐化(pansharpening)是提高多光谱图像空间分辨率的重要技术。大多数模型都…

记录DatagramSocket的使用 | UDP协议下的数据传输 | java学习笔记

a端 import java.io.*; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress;/*** a端发送“今天星期几”给b端*/ public class UDPa {public static void main(String[] args) throws IOException {//a端绑定9999端口————a端从…

编辑器的缩略图实现原理

一、背景 部分 Web 版的 IDE 编辑器未曾实现缩略图功能&#xff0c;探寻一下缩略图的实现逻辑。以 VSCode 为例。 VSCode 的编辑器是monaco实现的&#xff0c;编辑器的编辑区都是采用的虚拟渲染&#xff0c;即仅渲染可视区的代码&#xff0c;可视区之外的动态去除 DOM 节点。…

Windows上安装和配置Apache Kafka

Apache Kafka是一个开源的流式平台&#xff0c;用于处理实时数据流。它可以用于各种用途&#xff0c;包括日志聚合、事件处理、监控等。本文将向您展示如何在Windows操作系统上安装和配置Apache Kafka。 步骤1&#xff1a;下载和解压Kafka 首先&#xff0c;让我们从Apache Ka…

adworld-web2

web2 GFSJ0627积分 2金币 2 91最佳Writeup由 Robert_Wei 提供 收藏 反馈 难度&#xff1a;2 方向&#xff1a;Web 题解数&#xff1a;108 解出人数&#xff1a;10185 题目来源: CTF 题目描述: 解密 题目场景: http://61.147.171.105:56591 100% 倒计时: 3时59分…

基于SIFT图像特征识别的匹配方法比较与实现

基于SIFT图像特征识别的匹配方法比较与实现 1 匹配器选择 目前常用的匹配器有 BFMatcher and FlannBasedMatcher 1.1 BFMatcher BFMatcher 全称是 Brute-Force Matcher&#xff08;直译即为暴力匹配器&#xff09; 大致原理&#xff1a; 对于 img1 中的每个描述符&#x…

LVS DR模式负载均衡群集部署

目录 1 LVS-DR 模式的特点 1.1 数据包流向分析 1.2 DR 模式的特点 2 DR模式 LVS负载均衡群集部署 2.1 配置负载调度器 2.1.1 配置虚拟 IP 地址 2.1.2 调整 proc 响应参数 2.1.3 配置负载分配策略 2.2 部署共享存储 2.3 配置节点服务器 2.3.1 配置虚拟 IP 地址 2.3.2…

初学unity开发学习笔记----第一天

以下是学习unity知识的心得&#xff0c;类似备忘录&#xff0c;肯定是存在有漏洞的地方或者专业名词使用不恰当的地方。。。 目标&#xff1a;编写小球wasd移动的效果 1.下载unity hub和unity引擎: (1).前往官网:Unity实时内容开发平台 -实时3D引擎、2D、VR&AR可视化数据…

【新版】系统架构设计师 - 软件架构设计<SOA与微服务>

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 架构 - 软件架构设计&#xff1c;SOA与微服务&#xff1e; 考点摘要 面向服务SOA&#xff08;★★★★&#xff09;微服务&#xff08;★★★★&#xff09; 基于/面向服务的&#xff08;SOA&#xff09; 在SO…

【新版】系统架构设计师 - 软件架构设计<新版>

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 软件架构设计&#xff1c;新版&#xff1e;考点摘要概念架构的 4 1 视图架构描述语言ADL基于架构的软件开发方法ABSDABSD的开发模型ABSDMABSD&#xff08;ABSDM模型&#xff09;的开发过程 软件架…

C++ 多线程(future篇)

引言 在前面介绍了启动线程&#xff0c;以及多线程下如何保证共享资源的竞争访问、线程同步这些。但是thread类无法访问从线程直接返回的值&#xff0c;如果要想获取线程的的执行结果&#xff0c;一般都是依靠全局或static变量&#xff0c;或是以实参传递的变量&#xff0c;然后…

C# 辗转相除法求最大公约数

辗转相除法求最大公约数 public static void CalcGCD(int largeNumber, int smallNumber, out int GCD){GCD 1;int remain -1;while (remain ! 0){remain largeNumber % smallNumber;GCD smallNumber;largeNumber smallNumber;smallNumber remain;}}

华为云云耀云服务器L实例评测|华为云耀云L搭建zerotier服务测试

0. 环境 - Win10 - 云耀云L服务器 1. 安装docker 检查yum源&#xff0c;本EulerOS的源在这里&#xff1a; cd /etc/yum.repos.d 更新源 yum makecache 安装 yum install -y docker-engine 运行测试 docker run hello-world 2. 运行docker镜像 默认配…

计算机专业毕业设计项目推荐03-Wiki系统设计与实现(JavaSpring+Vue+Mysql)

Wiki系统设计与实现&#xff08;JavaSpringVueMysql&#xff09; **介绍****系统总体开发情况-功能模块****各部分模块实现** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较了解计算机专业的毕业设…

大秒杀系统设计

参考链接&#xff1a;http://www.taodudu.cc/news/show-5770725.html?actiononClick 1. 一些数据 大家还记得2013年的小米秒杀吗&#xff1f;三款小米手机各11万台开卖&#xff0c;走的都是大秒系统&#xff0c;3分钟后成为双十一第一家也是最快破亿的旗舰店。 经过日志统计…