当前位置: 首页 > news >正文

【Pytorch】Visualization of Feature Maps(3)

在这里插入图片描述

学习参考来自:

  • Image Style Transform–关于图像风格迁移的介绍
  • github:https://github.com/wmn7/ML_Practice/tree/master/2019_06_03

文章目录

  • 风格迁移


风格迁移

风格迁移出处:

《A Neural Algorithm of Artistic Style》(arXiv-2015)

在这里插入图片描述

在这里插入图片描述

风格迁移的实现

在这里插入图片描述

Random Image 在内容上可以接近 Content Image,在风格上可以接近 Style Image,当然, Random Image 可以初始化为 Content Image

导入基本库,数据读取

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optimfrom PIL import Image
import matplotlib.pyplot as pltimport torchvision.transforms as transforms
import torchvision.models as modelsimport numpy as np
import copy
import osdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")def image_loader(image_name, imsize):loader = transforms.Compose([transforms.Resize(imsize),  # scale imagestransforms.ToTensor()])image = Image.open(image_name).convert("RGB")image = loader(image).unsqueeze(0)return image.to(device, torch.float)def image_util(img_size=512, style_img="./1.jpg", content_img="./2.jpg"):"the size of style_img and contend_img should be same"imsize = img_size if torch.cuda.is_available() else 128  # use small size if no gpustyle_img = image_loader(style_img, imsize)content_img = image_loader(content_img, imsize)print("Style Image Size:{}".format(style_img.size()))print("Content Image Size:{}".format(content_img.size()))assert style_img.size() == content_img.size(), "we need to import style and content images of the same size"return style_img, content_img

定义内容损失

在这里插入图片描述

"content loss"
class ContentLoss(nn.Module):def __init__(self, target):super(ContentLoss, self).__init__()self.target = target.detach()def forward(self, input):self.loss = F.mse_loss(input, self.target)return input

定义风格损失

def gram_matrix(input):a, b, c, d = input.size()  # N, C,features = input.view(a * b, c * d)G = torch.mm(features, features.t())return G.div(a * b * c * d)

在这里插入图片描述

Gram Matrix 最后输出大小只和 filter 的个数有关(channels),上面的例子输出为 3x3

Gram Matrix 可以表示出特征出现的关系(特征 f1、f2、f3 之间的关系)。

我们可以通过计算 Gram Matrix 的差,来计算两张图片风格上的差距

在这里插入图片描述

class StyleLoss(nn.Module):def __init__(self, target_feature):# we "detach" the target content from the tree used to dynamically# compute the gradient: this is stated value, not a variable .# Otherwise the forward method of the criterion will throw an errorsuper(StyleLoss, self).__init__()self.target = gram_matrix(target_feature).detach()def forward(self, input):G = gram_matrix(input)self.loss = F.mse_loss(G, self.target)return input

写好前处理减均值,除方差

"based on VGG-16"
"put the normalization to the first layer"
class  Normalization(nn.Module):def __init__(self, mean, std):super(Normalization, self).__init__()# view the mean and std to make them [C,1,1] so that they can directly work with image Tensor of shape [B,C,H,W]self.mean = mean.view(-1, 1, 1)  # [3] -> [3, 1, 1]self.std = std.view(-1, 1, 1)def forward(self, img):return (img - self.mean) / self.std

定义网络,引入 loss

"modify to a style network"
def get_style_model_and_losses(cnn, normalization_mean, normalization_std,style_img, content_img,content_layers,style_layers):cnn = copy.deepcopy(cnn)# normalization modulenormalization = Normalization(normalization_mean, normalization_std).to(device)# just in order to have an iterable acess to or list of content / style# lossescontent_losses = []style_losses = []# assuming that cnn is a nn.Sequantial, so we make a new nn.Sequential to put# in modules that are supposed to be activated sequantiallymodel = nn.Sequential(normalization)i = 0  # increment every time we see a convfor layer in cnn.children():if isinstance(layer, nn.Conv2d):i += 1name = "conv_{}".format(i)elif isinstance(layer, nn.ReLU):name = "relu_{}".format(i)layer = nn.ReLU(inplace=False)elif isinstance(layer, nn.MaxPool2d):name = "pool_{}".format(i)elif isinstance(layer, nn.BatchNorm2d):name = "bn_{}".format(i)else:raise RuntimeError("Unrecognized layer: {}".format(layer.__class__.__name__))model.add_module(name, layer)if name in content_layers:# add content losstarget = model(content_img).detach()content_loss = ContentLoss(target)model.add_module("content_loss_{}".format(i), content_loss)content_losses.append(content_loss)if name in style_layers:# add style losstarget_feature = model(style_img).detach()style_loss = StyleLoss(target_feature)model.add_module("style_loss_{}".format(i), style_loss)style_losses.append(style_loss)# now we trim off the layers afater the last content and style lossesfor i in range(len(model)-1, -1, -1):if isinstance(model[i], ContentLoss) or isinstance(model[i], StyleLoss):breakmodel = model[:(i+1)]return model, style_losses, content_lossesdef get_input_optimizer(input_img):optimizer = optim.LBFGS([input_img.requires_grad_()])return optimizerdef run_style_transfer(cnn, normalization_mean, normalization_std, content_img, style_img, input_img, content_layers,style_layers, num_steps=50, style_weight=1000000, content_weight=1):print('Building the style transfer model..')model, style_losses, content_losses = get_style_model_and_losses(cnn, normalization_mean, normalization_std,style_img, content_img, content_layers,style_layers)optimizer = get_input_optimizer(input_img) # 网络不变,反向传播优化的是输入图片print('Optimizing..')run = [0]while run[0] <= num_steps:def closure():# correct the values of updated input imageinput_img.data.clamp_(0, 1)optimizer.zero_grad()model(input_img)  # 前向传播style_score = 0content_score = 0for sl in style_losses:style_score += sl.lossfor cl in content_losses:content_score += cl.lossstyle_score *= style_weightcontent_score *= content_weight# loss为style loss 和 content loss的和loss = style_score + content_scoreloss.backward()  # 反向传播# 打印loss的变化情况run[0] += 1if run[0] % 50 == 0:print("run {}:".format(run))print('Style Loss : {:4f} Content Loss: {:4f}'.format(style_score.item(), content_score.item()))print()return style_score + content_score# 进行参数优化optimizer.step(closure)# a last correction...# 数值范围的纠正, 使其范围在0-1之间input_img.data.clamp_(0, 1)return input_img

搭建完成,开始训练,仅优化更新 input image(get_input_optimizer),网络不更新

# 加载content image和style image
style_img,content_img = image_util(img_size=270, style_img="./style9.jpg", content_img="./content.jpg")  # [1, 3, 270, 270]
# input image使用content image
input_img = content_img.clone()
# 加载预训练好的模型
cnn = models.vgg19(pretrained=True).features.to(device).eval()
# 模型标准化的值
cnn_normalization_mean = torch.tensor([0.485, 0.456, 0.406]).to(device)
cnn_normalization_std = torch.tensor([0.229, 0.224, 0.225]).to(device)
# 定义要计算loss的层
content_layers_default = ['conv_4']
style_layers_default = ['conv_1', 'conv_2', 'conv_3', 'conv_4', 'conv_5']
# 模型进行计算
output = run_style_transfer(cnn, cnn_normalization_mean, cnn_normalization_std,content_img, style_img, input_img,content_layers=content_layers_default,style_layers=style_layers_default,num_steps=300, style_weight=100000, content_weight=1)image = output.cpu().clone()
image = image.squeeze(0)  # ([1, 3, 270, 270] -> [3, 270, 270])
unloader = transforms.ToPILImage()
image = unloader(image)
import cv2
image = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
cv2.imwrite("t9.jpg", image)
torch.cuda.empty_cache()"""VGG-19
Sequential((0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True)(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(6): ReLU(inplace=True)(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(8): ReLU(inplace=True)(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(11): ReLU(inplace=True)(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(13): ReLU(inplace=True)(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(15): ReLU(inplace=True)(16): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(17): ReLU(inplace=True)(18): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(19): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(20): ReLU(inplace=True)(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(22): ReLU(inplace=True)(23): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(24): ReLU(inplace=True)(25): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(26): ReLU(inplace=True)(27): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(29): ReLU(inplace=True)(30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(31): ReLU(inplace=True)(32): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(33): ReLU(inplace=True)(34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(35): ReLU(inplace=True)(36): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
""""""modify name, add loss layer
Sequential((0): Normalization()(conv_1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_1): StyleLoss()(relu_1): ReLU()(conv_2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_2): StyleLoss()(relu_2): ReLU()(pool_2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv_3): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_3): StyleLoss()(relu_3): ReLU()(conv_4): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(content_loss_4): ContentLoss()(style_loss_4): StyleLoss()(relu_4): ReLU()(pool_4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv_5): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_5): StyleLoss()(relu_5): ReLU()(conv_6): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_6): ReLU()(conv_7): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_7): ReLU()(conv_8): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_8): ReLU()(pool_8): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv_9): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_9): ReLU()(conv_10): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_10): ReLU()(conv_11): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_11): ReLU()(conv_12): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_12): ReLU()(pool_12): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv_13): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_13): ReLU()(conv_14): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_14): ReLU()(conv_15): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_15): ReLU()(conv_16): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(relu_16): ReLU()(pool_16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
""""""after trim
Sequential((0): Normalization()(conv_1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_1): StyleLoss()(relu_1): ReLU()(conv_2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_2): StyleLoss()(relu_2): ReLU()(pool_2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv_3): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_3): StyleLoss()(relu_3): ReLU()(conv_4): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(content_loss_4): ContentLoss()(style_loss_4): StyleLoss()(relu_4): ReLU()(pool_4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(conv_5): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(style_loss_5): StyleLoss()
)
"""

原图,花宝叽

在这里插入图片描述
不同风格

在这里插入图片描述
产生的结果

在这里插入图片描述

更直观的展示

在这里插入图片描述

相关文章:

【Pytorch】Visualization of Feature Maps(3)

学习参考来自&#xff1a; Image Style Transform–关于图像风格迁移的介绍github&#xff1a;https://github.com/wmn7/ML_Practice/tree/master/2019_06_03 文章目录 风格迁移 风格迁移 风格迁移出处&#xff1a; 《A Neural Algorithm of Artistic Style》&#xff08;ar…...

人工智能对我们的生活影响

目录 前言 一、人工智能的领域 二、人工智能的应用 三、对人工智能的看法 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4…...

Mysql存储引擎分类

Mysql存储引擎分类&#xff1a; 在选择存储引擎时&#xff0c;应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统&#xff0c;还可以根据实际情况选择多种存储引擎进行组合。 InnoDB: 是Mysql的默认存储引擎&#xff0c;支持事务、外键。如果应用对事务的完整性有…...

基于Python+TensorFlow+Django的交通标志识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 随着交通网络的不断扩展和智能交通系统的发展&#xff0c;交通标志的自动识别变得愈发重要。本项目旨在利用Python编…...

【Java 进阶篇】Jedis:让Java与Redis轻松对话的利器

在现代软件开发中&#xff0c;缓存系统是提高系统性能的常见手段之一&#xff0c;而Redis作为一个高性能的缓存数据库&#xff0c;被广泛应用于各类系统。如果你是Java开发者&#xff0c;那么使用Jedis库可以让你轻松地与Redis进行交互。本文将带你深入了解Jedis的快速入门&…...

【数据分享】我国12.5米分辨率的DEM地形数据(免费获取/地理坐标系)

DEM地形数据是我们在各种研究和设计中经常使用的数据&#xff01;之前我们分享过500米分辨率的DEM地形数据、90米分辨率的DEM地形数据、30米分辨率的DEM地形数据&#xff08;均可查看之前的文章获悉详情&#xff09;。 本次我们为大家带来的是分辨率为12.5m的DEM地形数据&#…...

C++设计模式之策略模式

策略模式 介绍示例示例测试运行结果应用场景优点总结 介绍 策略模式是一种行为设计模式。在策略模式中&#xff0c;可以创建一些独立的类来封装不同的算法&#xff0c;每一个类封装一个具体的算法&#xff0c;每一个封装算法的类叫做策略(Strategy)&#xff0c;为了保证这些策…...

spring-webflux的一些概念的理解

Spring5的webflux可以支持高吞吐量&#xff0c;使用相同的资源可以处理更加多的请求&#xff0c;它将会成为未来技术的趋势&#xff0c;但是相对于学习其他的框架相比&#xff0c;它的学习曲线很高&#xff0c;综合了很多现有的技术&#xff0c;即使按照教程学习能编写代码&…...

OpenCV快速入门:特征点检测与匹配

文章目录 前言一、角点检测1.1 角点特征1.1.1 角点特征概念1.1.2 角点的特点1.1.3 关键点绘制代码实现1.1.4 函数解析 1.2 Harris角点检测1.2.1 Harris角点检测原理1.2.2 Harris角点检测公式1.2.3 代码实现1.2.4 函数解析 1.3 Shi-Tomasi角点检测1.3.1 Shi-Tomasi角点检测原理1…...

旋转的数组

分享今天看到的一个题目&#xff0c;不同思路解法 题目 思路1&#xff1a;时间复杂度0(N*k&#xff09; void rotate(int *a,int N,int k)//N为数组元素个数 { while(k--) { int tema[N-1]; for(int rightN-2;right>0;right--) { a[right1]a[right]; } a[0]tem; …...

Hive VS Spark

spark是一个计算引擎&#xff0c;hive是一个存储框架。他们之间的关系就像发动机组与加油站之间的关系。 类似于spark的计算引擎还有很多&#xff0c;像mapreduce&#xff0c;flink等等。 类似于hive的存储框架也是数不胜数&#xff0c;比如pig。 最底层的存储往往都是使用h…...

SAST静态分析工具所支持的规则

综合国内外SAST工具支持的规则&#xff0c;这些规则包括了国际标准、国内标准、行业标准等&#xff0c;这里我罗列了一下&#xff0c;这些规则对应的标准集合。 评估一款SAST工具时&#xff0c;支持规则集的多少&#xff0c;且每个规则集是否为全集&#xff0c;或者接近全集&am…...

torch 的数据加载 Datasets DataLoaders

点赞收藏关注&#xff01; 如需要转载&#xff0c;请注明出处&#xff01; torch的模型加载有两种方式&#xff1a; Datasets & DataLoaders torch本身可以提供两数据加载函数&#xff1a; torch.utils.data.DataLoader&#xff08;&#xff09;和torch.utils.data.Datase…...

【Promise】某个异步方法执行结束后 在执行下面方法

使用Promise &#xff0c;当 layer.msg(查询成功) 这个方法执行结束后 &#xff0c;下面代码才会执行 let thas this async function showMessage() {await new Promise(resolve > layer.msg(查询成功, resolve));// 这里的代码将在 layer.msg 执行结束后执行thas.isGuaran…...

任意文件下载漏洞(CVE-2021-44983)

简介 CVE-2021-44983是Taocms内容管理系统中的一个安全漏洞&#xff0c;可以追溯到版本3.0.1。该漏洞主要源于在登录后台后&#xff0c;文件管理栏存在任意文件下载漏洞。简言之&#xff0c;这个漏洞可能让攻击者通过特定的请求下载系统中的任意文件&#xff0c;包括但不限于敏…...

C++(20):通过source_location实现日志函数

C++20中引入了std::source_location,用来描述函数调用的上下文信息。 其主要的成员函数如下: line():获取行号。column():获取列号。file_name():获取文件名。function_name():获取函数域名。#include <iostream> #include <string_view> #include <sour…...

【数据结构】树与二叉树(廿二):树和森林的遍历——后根遍历(递归算法PostOrder、非递归算法NPO)

文章目录 5.1 树的基本概念5.1.1 树的定义5.1.2 森林的定义5.1.3 树的术语 5.2 二叉树5.3 树5.3.1 树的存储结构1. 理论基础2. 典型实例3. Father链接结构4. 儿子链表链接结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法5.3.3 树和森林的遍历1. 先根遍历&#xff08;递归、非…...

精通Nginx(17)-安全管控之防暴露、限制访问、防DDos攻击、防爬虫、防非法引用

安全是每个系统都需要考虑的关键因素,Nginx在这方面提供了丰富的功能,使我们可以就实际情形做很精细调整。这些功能包括防信息暴露、客户端访问限制、通讯加密、防DDos攻击、防爬虫、防非法引用及防非法域名请求等。 目录 防信息暴露 关闭版本号 关闭目录列表 客户端访问…...

STM32 Flash

FLASH简介 Flash是常用的用于存储数据的半导体器件&#xff0c;它具有容量大&#xff0c;可重复擦写&#xff0c;按“扇区/块”擦除、掉电后数据可继续保存的特性。 常见的FLASH主要有NOR FLASH和NAND FLASH两种类型。NOR和NAND是两种数字门电路&#xff0c;可以简单地认为FL…...

文件批量重命名技巧:图片文件名太长怎么办?告别手动改名方法

在日常生活中&#xff0c;常常会遇到文件名过长导致的问题。尤其是在处理大量图片文件时&#xff0c;过长的文件名可能会使得文件管理变得混乱不堪。现在来看下云炫文件管理器如何批量重命名&#xff0c;让图片文件名变得更简洁&#xff0c;提高工作效率。 操作1、在云炫文件…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...