Single-Image Crowd Counting via Multi-Column Convolutional Neural Network
================================================================
Single-Image Crowd Counting via Multi-Column Convolutional Neural Network
- 论文背景
- 人群密度方法过去的发展历史
- 早期方法
- 基于轨迹聚类的方法
- 基于特征回归的方法
- 基于图像的方法
- Multi-column CNN用于人群计数
- 基于密度图的人群计数
- 通过几何自适应核生成密度图
- 密度图估计的多列CNN
论文背景
在2015年的上海大规模踩踏事件中,35人丧生。自那以后,世界各地发生了许多类似的人潮踩踏事件,导致更多的伤亡。因此,精确估算图像或视频中的人群数量对于计算机视觉技术在人群控制和公共安全方面的应用变得愈发重要。在公共集会、体育赛事等场景中,参与人数或密度是未来活动规划和空间设计的基本信息。良好的人群计数方法也可以扩展到其他领域,如从显微图像中计数细胞或细菌、在野生动物保护区估算动物群体的数量,或者估算交通枢纽或交通拥堵中的车辆数量等。
人群密度方法过去的发展历史
早期方法
以前的方法主要采用检测风格的框架,通过在视频序列的两个连续帧上扫描检测器,基于增强外观和运动特征,估算行人的数量。一些方法使用类似的基于检测的框架进行行人计数。然而,这些方法的局限性在于,它们通常假定人群由可以通过某些给定检测器检测到的单独实体组成,这在拥挤的环境或非常密集的人群中显着影响检测器性能和最终的估算准确性。
具体步骤如下
当我们想要数一群人的时候,可以通过观察视频中相邻两帧的变化来实现。方法是这样的:
- 看变化: 首先,我们会拿到视频中的两个连续画面,然后比较它们之间有哪些地方发生了变化,特别是有没有人在动。
- 找动的人: 如果有地方发生了变化,我们会认为那些是移动的个体,也就是人。这就是通过观察画面变化来找到人群的方法。
- 确认特征: 在找到的移动的地方,我们可能会再看一些其他特征,比如这些“移动的东西”是否看起来像人,或者它们的动作是不是像人的动作。
- 数人: 最后,通过统计在两个画面之间发现的“移动的东西”,我们就能大致估算视频中整个人群的数量。
基于轨迹聚类的方法
这种方法的核心思想是通过对视觉特征的轨迹进行聚类来计数人群。简单来说,就是通过观察视频中物体在一段时间内的运动轨迹,将相似的轨迹归为一类,从而估算人群的数量。但需要注意的是,这种方法适用于视频,而不适用于单个静止图像。
具体步骤如下
- 轨迹提取: 先从视频中提取物体的运动轨迹,可以使用一些跟踪器(比如KLT跟踪器)来追踪物体在不同帧之间的位置变化。
- 轨迹聚类: 将这些轨迹按照它们的相似度进行聚类,相似的轨迹被归为同一类。这里的相似度可能包括轨迹的形状、长度、速度等方面的特征。
- 估算人数: 每个聚类代表了一组相似运动的物体,我们可以认为这是同一群人。通过统计不同聚类中的轨迹数,就能估算出人群的数量。
基于特征回归的方法
这种方法通过对图像的前景进行分割,提取各种特征,然后使用回归函数来估算人群的数量。
具体步骤如下
- 分割前景: 在图像中,人群通常是前景,而其他部分是背景。首先,需要对图像进行前景分割,将人群从背景中分离出来。这可以使用图像分割算法来实现。
- 提取特征: 从前景图中提取各种特征,这些特征可以包括人群区域的面积、边缘数量、纹理特征等。这些特征将用作回归模型的输入。
- 回归函数: 使用回归函数来建模特征与人群数量之间的关系。回归函数的选择可以是简单的线性或分段线性函数,也可以采用更复杂的模型,如岭回归、高斯过程回归或神经网络。回归函数的目标是找到一个映射,使得输入特征可以准确地预测人群的数量。
具体的计算公式如下(以线性回归为例)
给定特征向量 x x x(包括面积、边缘数量、纹理等),人群数量的估计 y ^ \hat y y^为:
y ^ = w ⋅ x + b \hat y =w⋅x+b y^=w⋅x+b
其中, w w w是回归系数向量, b b b是偏置。通过训练回归模型,得到最优的 w w w和 b b b参数,使得预测值 y ^ \hat y y^接近实际的人群数量。
这种方法的优势在于简单且易于理解,而更复杂的模型可以处理更高度非线性的关系,提高估算的准确性。
基于图像的方法
一些研究专注于从静态图像中估算人群数量。不同于前面介绍的视频帧间运动或轨迹聚类方法,这些方法主要依赖于单个静态图像。以下是其中一些方法的原理:
- 多信息源计数: 一种方法是利用单个图像中的多个信息源来计算密集群中的个体数量。这些信息源可以包括SIFT(尺度不变特征变换)、傅立叶分析、小波分解、GLCM(灰度共生矩阵)特征以及对头部的低置信度检测。通过综合利用这些信息,可以更全面地估算人群数量。
- 特征融合和支持向量机(SVM): 另一种方法是利用预训练的卷积神经网络(CNN)提取图像特征,并将这些特征用于训练支持向量机(SVM)。具体而言,研究者可以使用多个信息源,如SIFT、傅立叶分析、小波分解、GLCM特征以及低置信度头部检测,将它们融合为一个综合的特征向量。然后,这个特征向量可以用于训练SVM,从而建立图像特征与人群数量之间的关系。
具体而言,特征融合可以表示为:
特征向量=[SIFT特征,傅立叶分析特征,小波分解特征,GLCM特征,低置信度头部检测特征,…]
然后,将这个特征向量用于训练SVM模型,该模型可以根据输入的图像特征向量来预测人群的数量。
这些方法的优势在于能够从静态图像中获取人群数量的信息,而不需要考虑视频帧之间的运动或轨迹信息。然而,对于不同的场景和图像,需要综合利用多个信息源,以提高估算的准确性。
Multi-column CNN用于人群计数
基于密度图的人群计数
在通过卷积神经网络(CNNs)估算给定图像中人数的过程中,有两种自然的配置。
- 一种是输入为图像,输出为估算的头部计数的网络。
- 另一种是输出人群的密度图(每平方米多少人),然后通过积分得出头部计数。
本文支持第二种选择,因为密度图保留更多信息。相对于总人群数量,密度图给出了图像中人群的空间分布信息,这在许多应用中都很有用。例如,如果某个区域的密度远高于其他区域,可能表明该区域发生了异常情况。
提出了使用CNN学习密度图的方法,其学习的滤波器更适应于不同大小头部,从而更适用于透视效应变化显著的任意输入。
通过几何自适应核生成密度图
由于CNN需要从输入图像训练以估算密度图,训练数据中给定的密度质量在很大程度上决定了方法的性能。
具体步骤
首先,对于图像中的每个头,将用一个 δ δ δ函数来表示。这个 δ δ δ函数在图像上的位置由 x i x_i xi表示,其中 i i i是头部的编号。如果图像中有 N N N个头,那么将这些 δ δ δ函数的和表示为 H ( x ) H(x) H(x),其中 H ( x ) H(x) H(x)是一个包含 N N N个 δ δ δ函数的函数,即:
H ( x ) = ∑ i = 1 N δ ( x − x i ) H(x) = \sum_{i=1}^Nδ(x - x_i) H(x)=i=1∑Nδ(x−xi)
为了将其转换为连续的密度函数,可以将该函数与高斯核 G σ G_σ Gσ卷积,使得密度为:
F ( x ) = H ( x ) ∗ G σ ( x ) F(x) = H(x) * G_σ(x) F(x)=H(x)∗Gσ(x)
然而,这样的密度函数假定 x i x_i xi是图像平面上的独立样本,而实际上,每个 x i x_i xi是3D场景中地面上的人群密度样本,由于透视失真,与不同 x i x_i xi对应的像素对应于场景中不同尺寸的区域。
为了准确估算人群密度 F F F,需要考虑由地平面和图像平面之间的单应性引起的扭曲。然而,在任务和数据集中,通常并不知道场景的几何形状。尽管如此,如果假设每个头周围的人群在图像上是均匀分布的,那么头与其最近的 k k k个邻居(在图像上)之间的平均距离给出了透视效应引起的几何扭曲的合理估计。
因此,应该基于图像中每个人的头尺寸自适应地确定传播参数 σ σ σ。对于给定图像中的每个头 x i x_i xi,将其到其 k k k个最近邻居的距离表示为 [ d 1 i , d 2 i , . . . , d m i ] [d^i_1, d^i_2, ..., d^i_m] [d1i,d2i,...,dmi]。平均距离是 d ˉ i = 1 m ∑ j = 1 m d j i \bar d^i = \frac{1}{m}\sum_{j=1}^m d^i_j dˉi=m1∑j=1mdji。
因此,与 x i x_i xi关联的像素大致对应于场景中地面上半径与 d ˉ i \bar d_i dˉi成比例的区域。因此,为了估算 x i x_i xi周围的人群密度,需要将 δ ( x − x i ) δ(x - x_i) δ(x−xi)与方差 σ i σ_i σi成比例的高斯核卷积。更具体地说,密度 F F F应为
F ( x ) = ∑ i = 1 N δ ( x − x i ) ∗ G σ ( x ) F(x) =\sum_{i=1}^Nδ(x-x_i) * G_σ(x) F(x)=i=1∑Nδ(x−xi)∗Gσ(x),
其中 σ i = β ∗ d ˉ i σ_i = β * \bar d_i σi=β∗dˉi, β β β是参数。换句话说,我们使用自适应于每个数据点周围局部几何的密度核,称为几何自适应核。在实验中,我们经验性地发现 β = 0.3 β = 0.3 β=0.3给出了最佳结果。
密度图估计的多列CNN
由于透视失真,图像通常包含不同大小的头,因此具有相同大小感受野的滤波器不太可能捕捉到不同尺度的人群密度特征。因此,更自然的方法是使用具有不同局部感受野大小的滤波器来学习原始像素到密度图的映射。受多列深度神经网络(MDNNs)成功的启发,提出使用多列卷积神经网络(MCNN)来学习目标密度图。在我们的MCNN中,对于每一列,我们使用不同大小的滤波器来建模与不同尺度头相对应的密度图。例如,具有较大感受野的滤波器对应于建模与较大头相对应的密度图。模型架构图如下:
MCNN包含三个平行的CNN,其滤波器具有不同大小的局部感受野。为简化起见,我们对所有列使用相同的网络结构(即,conv–pooling–conv–pooling),除了滤波器的大小和数量。对于每个2×2区域,应用最大池化,并且由于ReLU对于CNN的性能良好,采用修正线性单元(ReLU)作为激活函数。
为了减少计算复杂性(要优化的参数数量),对具有较大滤波器的CNN使用较少的滤波器。堆叠所有CNN的输出特征图,并将它们映射到密度图。为了将特征图映射到密度图,采用滤波器大小为1×1。然后,使用欧几里得距离来衡量估算的密度图与地面实况之间的差异。损失函数定义如下:
其中, Θ Θ Θ是MCNN中可学习参数的集合,N是训练图像的数量, X i X_i Xi是输入图像, F i F_i Fi是图像 X i X_i Xi的地面实况密度图。 F ( X i ; Θ ) F(X_i; \Theta) F(Xi;Θ)表示由带有参数 Θ Θ Θ的MCNN生成的估算密度图, L L L是估算密度图与地面实况密度图之间的损失。
注意事项:
- 由于使用两层最大池化,每个图像的空间分辨率减少了1/4。因此,在训练阶段,我们在生成密度图之前将每个训练样本下采样1/4。
- 传统的CNN通常将输入图像规范化为相同的大小。这里我们更喜欢输入图像保持其原始大小,因为将图像调整为相同的大小会引入难以估计的密度图中的额外失真。
- 除了CNN中的滤波器具有不同的大小之外,MCNN与传统MDNN之间的另一个区别是使用具有可学习权重的所有CNN的输出(即,1×1滤波器)进行组合。相比之下,在提出的MDNNs中,输出简单地平均。
骨干结构在计算机视觉模型中无论是图像分类目标检测或者人群计数等任务中起到了提取图像特征的作用。因此它骨干模型的内部输出图像其实就是一个类似的密度图,MCNN再结合多尺度就会把整个图片里所有人头都检测
我这里有一个实现骨干模型内部可视化的脚本可以参考,模型就用的最常见的骨干模型VGG,VGG模型代码在后面。
import torch
import torch.nn as nn
from torch.autograd import Variable
from torchvision.transforms import transforms
import numpy as np
import cv2
from functools import partial
import matplotlib
import os
import json
matplotlib.use('agg')
import matplotlib.pyplot as plt
import requestsfrom models import Vgg16Conv
from models import Vgg16Deconvdef load_and_preprocess_image(img_path):"""加载和预处理图像"""# 从img_path读取图像img = cv2.imread(img_path)img = cv2.resize(img, (224, 224))# PyTorch必须通过以下均值和标准差对图片进行标准化transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])img = transform(img)img.unsqueeze_(0)return imgdef hook_function(module, input, output, key):"""用于存储特征图的钩子函数"""if isinstance(module, nn.MaxPool2d):model.feature_maps[key] = output[0]model.pool_locs[key] = output[1]else:model.feature_maps[key] = outputdef register_hooks(model):"""为骨干模型注册特征图存储钩子"""def hook(module, key):layer.register_forward_hook(partial(hook_function, key=key))for idx, layer in enumerate(model._modules.get('features')): # _modules返回一个有序字典hook(layer, key=idx)def visualize_layer(layer, vgg16_conv, vgg16_deconv):"""可视化骨干模型的某一层的反卷积结果"""num_feat = vgg16_conv.feature_maps[layer].shape[1]# 将其他特征图激活设置为零new_feat_map = vgg16_conv.feature_maps[layer].clone()# 选择最大激活的特征图act_lst = []for i in range(0, num_feat):choose_map = new_feat_map[0, i, :, :]activation = torch.max(choose_map)act_lst.append(activation.item())act_lst = np.array(act_lst)mark = np.argmax(act_lst)choose_map = new_feat_map[0, mark, :, :]max_activation = torch.max(choose_map)# 对其他特征图进行零值处理if mark == 0:new_feat_map[:, 1:, :, :] = 0else:new_feat_map[:, :mark, :, :] = 0if mark != vgg16_conv.feature_maps[layer].shape[1] - 1:new_feat_map[:, mark + 1:, :, :] = 0choose_map = torch.where(choose_map==max_activation,choose_map,torch.zeros(choose_map.shape))# 对其他激活进行零值处理new_feat_map[0, mark, :, :] = choose_map# 输出反卷积结果deconv_output = vgg16_deconv(new_feat_map, layer, mark, vgg16_conv.pool_locs)new_img = deconv_output.data.numpy()[0].transpose(1, 2, 0) # (H, W, C)# 归一化new_img = (new_img - new_img.min()) / (new_img.max() - new_img.min()) * 255new_img = new_img.astype(np.uint8)return new_img, int(max_activation)if __name__ == '__main__':img_path = './data/cat.jpg'# 前向处理img = load_and_preprocess_image(img_path)vgg16_conv = Vgg16Conv()vgg16_conv.eval()register_hooks(vgg16_conv)conv_output = vgg16_conv(img)pool_locs = vgg16_conv.pool_locs# 反向处理vgg16_deconv = Vgg16Deconv()vgg16_deconv.eval()plt.figure(num=None, figsize=(16, 12), dpi=80)plt.subplot(2, 4, 1)plt.title('Original Picture')img = cv2.imread(img_path)img = cv2.resize(img, (224, 224))plt.imshow(img) for idx, layer in enumerate([14, 17, 19, 21, 24, 26, 28]):# for idx, layer in enumerate(vgg16_conv.conv_layer_indices): plt.subplot(2, 4, idx+2)img, activation = visualize_layer(layer, vgg16_conv, vgg16_deconv)plt.title(f'{layer} Layer, Max Activation: {activation}')plt.imshow(img)plt.savefig('result.jpg')print('Result picture has been saved at ./result.jpg')
model.vgg16_conv.py
import torch
import torch.nn as nn
import torchvision.models as models
import torchvisionfrom collections import OrderedDictclass Vgg16Conv(nn.Module):"""vgg16 convolution network architecture"""def __init__(self, num_cls=1000):"""Inputnumber of class, default is 1k."""super(Vgg16Conv, self).__init__()self.features = nn.Sequential(# conv1nn.Conv2d(3, 64, 3, padding=1),nn.ReLU(),nn.Conv2d(64, 64, 3, padding=1),nn.ReLU(),nn.MaxPool2d(2, stride=2, return_indices=True),# conv2nn.Conv2d(64, 128, 3, padding=1),nn.ReLU(),nn.Conv2d(128, 128, 3, padding=1),nn.ReLU(),nn.MaxPool2d(2, stride=2, return_indices=True),# conv3nn.Conv2d(128, 256, 3, padding=1),nn.ReLU(),nn.Conv2d(256, 256, 3, padding=1),nn.ReLU(),nn.Conv2d(256, 256, 3, padding=1),nn.ReLU(),nn.MaxPool2d(2, stride=2, return_indices=True),# conv4nn.Conv2d(256, 512, 3, padding=1),nn.ReLU(),nn.Conv2d(512, 512, 3, padding=1),nn.ReLU(),nn.Conv2d(512, 512, 3, padding=1),nn.ReLU(),nn.MaxPool2d(2, stride=2, return_indices=True),# conv5nn.Conv2d(512, 512, 3, padding=1),nn.ReLU(),nn.Conv2d(512, 512, 3, padding=1),nn.ReLU(),nn.Conv2d(512, 512, 3, padding=1),nn.ReLU(),nn.MaxPool2d(2, stride=2, return_indices=True))self.classifier = nn.Sequential(nn.Linear(512 * 7 * 7, 4096),nn.ReLU(),nn.Dropout(),nn.Linear(4096, 4096),nn.ReLU(),nn.Dropout(),nn.Linear(4096, num_cls),nn.Softmax(dim=1))# index of convself.conv_layer_indices = [0, 2, 5, 7, 10, 12, 14, 17, 19, 21, 24, 26, 28]# feature mapsself.feature_maps = OrderedDict()# switchself.pool_locs = OrderedDict()# initial weightself.init_weights()def init_weights(self):"""initial weights from preptrained model by vgg16"""vgg16_pretrained = models.vgg16(pretrained=True)# fine-tune Conv2dfor idx, layer in enumerate(vgg16_pretrained.features):if isinstance(layer, nn.Conv2d):self.features[idx].weight.data = layer.weight.dataself.features[idx].bias.data = layer.bias.data# fine-tune Linearfor idx, layer in enumerate(vgg16_pretrained.classifier):if isinstance(layer, nn.Linear):self.classifier[idx].weight.data = layer.weight.dataself.classifier[idx].bias.data = layer.bias.datadef check(self):model = models.vgg16(pretrained=True)return modeldef forward(self, x):for idx, layer in enumerate(self.features):if isinstance(layer, nn.MaxPool2d):x, location = layer(x)# self.pool_locs[idx] = locationelse:x = layer(x)# reshape to (1, 512 * 7 * 7)x = x.view(x.size()[0], -1)output = self.classifier(x)return outputif __name__ == '__main__':model = models.vgg16(pretrained=True)print(model)
model.vgg16_deconv.py
import torch
import torch.nn as nn
import torchvision.models as modelsimport sysclass Vgg16Deconv(nn.Module):"""vgg16 transpose convolution network architecture"""def __init__(self):super(Vgg16Deconv, self).__init__()self.features = nn.Sequential(# deconv1nn.MaxUnpool2d(2, stride=2),nn.ReLU(),nn.ConvTranspose2d(512, 512, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(512, 512, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(512, 512, 3, padding=1),# deconv2nn.MaxUnpool2d(2, stride=2),nn.ReLU(),nn.ConvTranspose2d(512, 512, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(512, 512, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(512, 256, 3, padding=1),# deconv3nn.MaxUnpool2d(2, stride=2),nn.ReLU(),nn.ConvTranspose2d(256, 256, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(256, 256, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(256, 128, 3, padding=1),# deconv4nn.MaxUnpool2d(2, stride=2),nn.ReLU(),nn.ConvTranspose2d(128, 128, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(128, 64, 3, padding=1),# deconv5nn.MaxUnpool2d(2, stride=2),nn.ReLU(),nn.ConvTranspose2d(64, 64, 3, padding=1),nn.ReLU(),nn.ConvTranspose2d(64, 3, 3, padding=1) )self.conv2deconv_indices = {0:30, 2:28, 5:25, 7:23,10:20, 12:18, 14:16, 17:13,19:11, 21:9, 24:6, 26:4, 28:2}self.unpool2pool_indices = {26:4, 21:9, 14:16, 7:23, 0:30}self.init_weight()def init_weight(self):vgg16_pretrained = models.vgg16(pretrained=True)for idx, layer in enumerate(vgg16_pretrained.features):if isinstance(layer, nn.Conv2d):self.features[self.conv2deconv_indices[idx]].weight.data = layer.weight.data#self.features[self.conv2deconv_indices[idx]].bias.data\# = layer.bias.datadef forward(self, x, layer, activation_idx, pool_locs):if layer in self.conv2deconv_indices:start_idx = self.conv2deconv_indices[layer]else:raise ValueError('layer is not a conv feature map')for idx in range(start_idx, len(self.features)):if isinstance(self.features[idx], nn.MaxUnpool2d):x = self.features[idx]\(x, pool_locs[self.unpool2pool_indices[idx]])else:x = self.features[idx](x)return x
从上面图片来看,每层都有一些特征保留出来,而这种特征看起来像是一些opencv特征算法提取的感觉。这种特征结合高斯密度函数,就可以转为密度图啦
相关文章:
Single-Image Crowd Counting via Multi-Column Convolutional Neural Network
Single-Image Crowd Counting via Multi-Column Convolutional Neural Network 论文背景人群密度方法过去的发展历史早期方法基于轨迹聚类的方法基于特征回归的方法基于图像的方法 Multi-column CNN用于人群计数基于密度图的人群计数通过几何自适应核生成密度图密度图估计的多列…...
el-cascader隐藏某一级的勾选框及vue报错Error in callback for watcher “options“的解决办法
今天用到饿了么的级联选择器时出现了这个报错Error in callback for watcher “options“: “TypeError: Cannot read propertie ‘level‘ of null,因为需求是在不同类型 el-cascader多选的时候默认是可以勾选所有级的选项的,如下图: 包含级联cascader的options、select的…...
2024美赛数学建模思路A题B题C题D题E题F题思路汇总 选题分析
文章目录 1 赛题思路2 美赛比赛日期和时间3 赛题类型4 美赛常见数模问题5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 美赛比赛日期和时间 比赛开始时间:北京时间2024年2月2日(周五ÿ…...
C++ 常用设计模式
一、工厂模式 from:C开发常用的设计模式及其实现详解 - 知乎 摘抄: 简单工厂、工厂、抽象工厂: 简单工厂需要工厂内部判断,而工厂模式不需要修改工厂类: 抽象工厂: 接上图: 未完待续.........
高性价比的高速吹风机/高速风筒解决方案,基于普冉单片机开发
高速吹风机是近些年非常火的一款产品,快速崛起并颠覆了传统吹风机,高速吹风机也成为了传统吹风机替代的一个大趋势。高速吹风机是利用高转速产生的大风量来快速吹干头发,由于其精巧的外观设计、超低的噪声、出色的干发效果,高速吹…...
toRefs的用法
文章目录 toRefs是什么toRefs的作用以及为什么要用它? toRefs是什么 toRefs 是 Vue 3 Composition API 中的一个函数,它用于将响应式对象转换为普通对象,其中对象的每个属性都是 ref 对象。这是因为在 Vue 3 中,reactive 创建的对…...
MySQL基础篇(三)约束
一、概述 概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。 目的:保证数据库中数据的正确、有效性和完整性。 分类: 注意:约束是作用于表中字段上的,可以在创建表/修改表的时候添加约束。 二…...
Java进阶 1-2 枚举
目录 常量特定方法 职责链模式的枚举实现 状态机模式的枚举实现 多路分发 1、使用枚举类型实现分发 2、使用常量特定方法实现分发 3、使用EnumMap实现分发 4、使用二维数组实现分发 本笔记参考自: 《On Java 中文版》 常量特定方法 在Java中,我们…...
一个人最大的内驱力是什么?
1、不因为孤独或外界压力而降低「生活标准“」的能力。 ”因为寂寞去约炮“、“因为家里催婚匆忙结婚“、”因为没谈过恋爱随便找个人交往。 “你的每一次选择都是在为自己想要的世界而投的票,往后余生是幸福还是悲剧,就是在这一次次 的将就与坚持死磕中…...
解决方法:公众号的API上传素材报错40005
公众号的API上传素材报错40005 Error uploading file : {"errcode":40005,"errmsg":"invalid file type hint: [YOkxGA0122w487] rid: 223442-323247e7bd5-5d75322d88"}上传错误原因分析: 之前成功的示例,文件名为"…...
音量控制软件sound control mac功能亮点
sound control mac可以帮助用户控制某个独立应用程序的音量,通过每应用音量,均衡器,平衡和音频路由独立控制每个应用的音频,还有整个系统的音量。 sound control mac功能亮点 每个应用程序的音量控制 独立控制应用的数量。 键盘音…...
Spring Boot 生产就绪中文文档-下
本文为官方文档直译版本。原文链接 由于篇幅较长,遂分两篇。上半部分中文文档 Spring Boot 生产就绪中文文档-下 度量标准入门受支持的监控系统AppOpticsAtlasDatadogDynatracev2 API自动配置手动配置 v1 API (旧版)与版本无关的设置 ElasticGangliaGraphiteHumioIn…...
DS|树结构及应用
题目一:DS树 -- 树的先根遍历(双亲转先序) 题目描述: 给出一棵树的双亲表示法结果,用一个二维数组表示,位置下标从0开始,如果双亲位置为-1则表示该结点为根结点 编写程序,输出该树…...
Java 读取超大excel文件
注意:此参考解决方案只是针对xlsx格式的excel文件! Maven <dependency><groupId>com.monitorjbl</groupId><artifactId>xlsx-streamer</artifactId><version>2.2.0</version> </dependency>读取方式1…...
K8S中的job和CronJob
Job 介绍 Kubernetes jobs主要是针对短时和批量的工作负载。它是为了结束而运行的,而不是像deployment、replicasets、replication controllers和DaemonSets等其他对象那样持续运行。 示例 apiVersion: batch/v1 kind: Job metadata:name: pispec:template:spec:r…...
中国文化文物和旅游统计年鉴,数据含pdf、excel等格式,文本形式呈现,可预览数据
基本信息. 数据名称: 中国旅游统计年鉴 数据格式: pdf、xls不定 数据时间: 2012-2020年 数据几何类型: 文本 数据坐标系: —— 数据来源:文化和旅游部、网络公开数据 原名为《中国旅游统计年鉴》2020年后更名为《中国文化文物和旅游统计年鉴》ÿ…...
Java版企业电子招标采购系统源码——鸿鹄电子招投标系统的技术特点
在数字化时代,采购管理也正经历着前所未有的变革。全过程数字化采购管理成为了企业追求高效、透明和规范的关键。该系统通过Spring Cloud、Spring Boot2、Mybatis等先进技术,打造了从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通过…...
go语言语法基础
文章目录 前言一、输入和输出常用的字符串格式化符号 二、注释三、Go常用基本语言数据类型数字类型布尔类型字符类型变量与常量数组和切片数组切片 map类型创建map增删改查特别提醒 指针 四、运算符五、条件判断语句if系列switch六、循环语句for循环标准写法死循环while循环do …...
eclipse 和java环境的安装教程
安装 Eclipse 和配置 Java 环境是一个多步骤的过程,涉及到安装 Java Development Kit (JDK) 和 Eclipse IDE。以下是基本步骤: 安装 Java Development Kit (JDK) 下载 JDK: 访问 Oracle 官方网站(Oracle JDK)或者选择…...
Win11系统的优化方法参考文档(彻底优化策略)
目录 一、个性化-应用-关闭防火墙等的设置 二、任务栏优化设置 三、Win11开始菜单更改为Win10经典菜单 四、将Micresoft Store 从固定任务栏取消 五、电源性能优化 六、解决卡顿 七、卸载系统自带软件 八、任务管理器开机启动项的禁用 九、调整为最佳性能 十…...
Leetcode13-解密消息(2325)
1、题目 给你字符串 key 和 message ,分别表示一个加密密钥和一段加密消息。解密 message 的步骤如下: 使用 key 中 26 个英文小写字母第一次出现的顺序作为替换表中的字母 顺序 。 将替换表与普通英文字母表对齐,形成对照表。 按照对照表 …...
二进制安装包安装Prometheus插件安装(mysql_exporter)
简介 mysql_exporter是用来收集MysQL或者Mariadb数据库相关指标的,mysql_exporter需要连接到数据库并有相关权限。既可以用二进制安装部署,也可以通过容器形式部署,但为了数据收集的准确性,推荐二进制安装。 一,下载安…...
原生微信小程序如何动态修改svg图片颜色及尺寸、宽高(封装svgIcon组件)
最终效果 前言 动态设置Svg图片颜色就是修改Svg源码的path中的fill属性, 通过wx.getFileSystemManager().readFile读取.xlsx文件 把文件转成base64 封装svg-icon组件 1、在项目的components下新建svg-icon文件夹,新增base64.js文件 class Base64 {cons…...
Python从入门到网络爬虫(面向对象详解)
前言 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本…...
NPDP产品经理含金量高吗?难考吗?
NPDP的中文翻译为产品经理国际资格认证。NPDP考试起源于美国,由美国产品开发与管理协会(PDMA)发起。NPDP认证是集理论、方法与实践为一体的全方位知识体系,为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。࿰…...
目标检测 YOLOv5 - 推理时的数据增强
目标检测 YOLOv5 - 推理时的数据增强 flyfish 版本 YOLOv5 6.2 参考地址 https://github.com/ultralytics/yolov5/issues/303在训练时可以使用数据增强,在推理阶段也可以使用数据增强 在测试使用数据增强有个名字叫做Test-Time Augmentation (TTA) 实际使用中使…...
篇二:springboot2.7 OAuth2 server使用jdbc存储RegisteredClient
上一篇 <<springboot 2.7 oauth server配置源码走读一>>中简单描述了oauth2 server的配置,其中使用了内存保存 RegisteredClient,本篇改用mysql存储。 db存储需要创建表,表结构应该是什么样的呢,从spring给我们封装好…...
卷积神经网络|导入图片
在学习卷积神经网络时,我们通常使用的就是公开的数据集,这里,我们不使用公开数据集,直接导入自己的图片数据,下面,就简单写个程序实现批量图片的导入。 import osfrom PIL import Imageimport numpy as np…...
关于unity的组件VerticalLayoutGroup刷新显示不正常的问题
先说明一下我是如何用到,有哪些处理的 用到这个组件基本上都是将列表进行排版操作的,竖着,或者横着,横着用HorizontalLayoutGroup 还有一个和这个组件搭配的组件叫ContentSizeFitter 先说我是怎么发现这个组件不好用的 //本地读取…...
wait 和 notify 这个为什么要在synchronized 代码块中?
一个工作七年的小伙伴,竟然不知道” wait”和“notify”为什么要在 Synchronized 代码块中 。 好吧,如果屏幕前的你也不知道,请在公屏上刷”不知道“。 对于这个问题,我们来看看普通人和高手的回答。 一、问题解析 1. wait 和 n…...
安徽六安彩礼一般给多少/百度 seo 工具
查接口找到的,分享给大家,希望对大家以后开发有用 火车车次查询-余票查询--Api接口 1.来自12306的火车车次数据 使用12306网站的接口,查询余票。此接口采集自这里。全国火车站代号字典,下载。火车票余票查询 http://dynamic.123…...
一个网站要怎么做/谷歌浏览器官网下载
原标题:一个冬天没下雪的北京终于要下雪了?超级计算机:还不能完全确定1月30日,寒潮南下我国中东部,在我国黄淮江淮一线与冷空气交战掀起大范围雨雪天气,局地还可能有暴雪,这是今年新年以来出现的…...
网站建设全过程及如何赚钱/搜索引擎seo如何赚钱
引用国外友人搭建RUBiS的一句心得,RUBiS is a PAIN!! 很多搞阔研的人在做实验的时候都会用到RUBiS,但是RUBiS的搭建确实很让人头大。一来,使用到RUBiS的人少之又少。二来,RUBiS项目已经停止维护了,最经的一次更新也是在…...
网站扁平化结构和树形结构/网络服务有哪些
一、修改文件所有者 chown newowner 文件/目录 改变所有者 chown newowner:newgroup文件/目录改变所有者和所在组 -R 如果是目录则使其下所有子文件或目录递归生效 案列1:请将/home/aa.txt文件的所有者修改成yaya 案列2:请将/home/zhangsan目录…...
众筹网站建设 网站定制开发/中国万网官网登录
2008年6月,上海市宝山有线电视中心成功实施Mocha BSM。该项目的实施,使宝山有线电视中心能够更加快捷的进行IT运维管理,使IT管理人员从被动响应式的工作方式转变为主动服务,准确、快速地定位故障产生的根本原因。客户简介宝山有线…...
写好网页怎么建成网站/org域名注册
MongoDB安装并实现远程授权连接(Linux) 1. 到官网下载压缩包mongodb-linux-x86_64-4.0.27.tgz 官网地址:https://www.mongodb.com/try/download/community 按照图示,选择社区版4.0.x,Linux(legacy),tgz即可 2. 上传压缩包到Li…...