三维人脸实践:基于Face3D的渲染、生成与重构 <一>
face3d: Python tools for processing 3D face
git code: https://github.com/yfeng95/face3d
paper list: PaperWithCode
该方法广泛用于基于三维人脸关键点的人脸生成、属性检测(如位姿、深度、PNCC等),能够快速实现人脸建模与渲染。推荐!!!
目录
- face3d: Python tools for processing 3D face
- 一、介绍
- 1.1 目录
- 1.2 构建
- 1.2.1先决条件
- 1.3 使用
- 1.3.1 克隆
- 1.3.2 编译C++文件为.so文件,用于python;如果使用numpy版本,则忽略此步。
- 1.3.3 准备BFM数据(如果不使用3dmm可跳过此步)
- 1 下载原始的BFM模型
- 2 下载额外的BFM信息:
- 3 下载STN中的UV坐标
- 1.3.4 运行
- 1.4 运行例子
- 2 pipeline源码解读
- 2.0导入相关库文件
- 2.1 加载网格数据(mesh data)
- 2.2 修改顶点(vertices)
- 2.3 修改颜色/纹理(添加光照)
- 2.4 修改顶点(映射,改变相机位置)
- 2.5 转化为2D图像
- 总结
相机坐标下的人脸变换
光照渲染
3DMM模型
提示:对于初学者来说,作者强烈建议按照这个顺序来运行样例,然后再看mesh_numpy中的代码和读每个文件中的注释。
一、介绍
这里尝试去实现有关三维人脸的一些基础功能,如处理网格数据mesh data、基于morphable model的人脸生成,基于单张人脸图片及其关键点的三维人脸重构,带有不同光照效果的人脸渲染等操作。
该工程大部分代码基于python,但有些功能如rasterization使用C++实现循环渲染会快很多,并使用Cython编译供python环境使用,该工具轻量而运行快。
1.1 目录
三维网络数据,是最流行的三维人脸表征方法;3DMM模型广泛用于产生和重构三维人脸。
# Since triangle mesh is the most popular representation of 3D face,
# the main part is mesh processing.
mesh/ # written in python and c++
| cython/ # c++ files, use cython to compile
| io.py # read & write obj
| vis.py # plot mesh
| transform.py # transform mesh & estimate matrix
| light.py # add light & estimate light(to do)
| render.py # obj to image using rasterization rendermesh_numpy/ # the same with mesh/, with each part written in numpy# slow but easy to learn and modify# 3DMM is one of the most popular methods to generate & reconstruct 3D face.
morphable_model/
| morphable_model.py # morphable model class: generate & fit
| fit.py # estimate shape&expression parameters. 3dmm fitting.
| load.py # load 3dmm data
1.2 构建
1.2.1先决条件
Python 2 or Python 3
Python packages:numpyskimage (for reading&writing image)scipy (for loading mat)matplotlib (for show)Cython (for compiling c++ file)%可参考pip3命令行下载国内源:
pip3 install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install scikit-image -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install scipy -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
pip3 install Cython -i https://pypi.tuna.tsinghua.edu.cn/simple
1.3 使用
1.3.1 克隆
git clone https://github.com/YadiraF/face3d
cd face3d
1.3.2 编译C++文件为.so文件,用于python;如果使用numpy版本,则忽略此步。
cd face3d/mesh/cython
python setup.py build_ext -i
1.3.3 准备BFM数据(如果不使用3dmm可跳过此步)
1 下载原始的BFM模型
链接:https://faces.dmi.unibas.ch/bfm/main.php?nav=1-2&id=downloads
将所有框都勾上,填写对应的信息后会收到一个下载link,将下载后的文件拷贝:
copy 01_MorphabelModel.mat to raw/
2 下载额外的BFM信息:
链接:3DFFA
下载【face profiling】和【3DFFA】
链接:HPEN
下载HPEN
将下载好的三个压缩包解压,分别在里面找到如下文件:
model_info.mat Model_Expression.mat Model_face_contour_trimed.mat Model_tri_mouth.mat Modelplus_nose_hole.mat Modelplus_parallel.mat vertex_code.mat
然后在face3d/examples/Data/BFM目录下新建一个文件夹3ddfa,将上述文件拷贝进去。
3DDFA(Face Alignment Across Large Poses: A 3D Solution) HFPE(High-Fidelity Pose and Expression Normalization for Face Recognition in the Wild)
3 下载STN中的UV坐标
链接:BFM_UV
点击download下载后解压,在face3d/examples/Data/BFM目录下新建一个文件夹stn,再将BFM_UV.mat复制到stn/
1.3.4 运行
在BFM目录下创建Out文件夹
运行Matlab中的generate.m,产生的文件将会保存在 Out/
提示:一些空文件夹可能需要通过mkdir创建
1.4 运行例子
examples使用cython版本,如果使用numpy,将mesh替换为mesh_numpy即可
cd examples
python 1_pipeline.py
如果得到如下输出,并且在pipeline下有生产的照片说明运行成功
2 pipeline源码解读
提示:为了方便理解,源码解读可能会使用numpy版本;而示例使用的是cython版本。
Pipeline:将3D目标转化为2D图像
2.0导入相关库文件
''' Simple example of pipeline
3D obj(process) --> 2d image
'''
import os, sys
import numpy as np
import scipy.io as sio
from skimage import io
from time import time
import matplotlib.pyplot as pltsys.path.append('..')
import face3d
from face3d import mesh
2.1 加载网格数据(mesh data)
网格数据包含:顶点,三角网格数据,颜色(可选),纹理(可选)。这里使用颜色来表征人脸面部的纹理
# ------------------------------ 1. load mesh data
# -- mesh data consists of: vertices, triangles, color(optinal), texture(optional)
# -- here use colors to represent the texture of face surface
C = sio.loadmat('Data/example1.mat')
vertices = C['vertices']; colors = C['colors']; triangles = C['triangles']
colors = colors/np.max(colors)
这里示例的网格数据来自.mat文件,分别获取其中的vertices、color和triangles数据,并将颜色归一化。
2.2 修改顶点(vertices)
改变网格对象在世界坐标系中的位置。三维物体的变换方式有:缩放(scale)、旋转、平移等操作。这里在y通道上设置scale尺度为180,旋转30°,原地平移。
# ------------------------------ 2. modify vertices(transformation. change position of obj)
# -- change the position of mesh object in world space
# scale. target size=180 for example
s = 180/(np.max(vertices[:,1]) - np.min(vertices[:,1]))
# rotate 30 degree for example
R = mesh.transform.angle2matrix([0, 30, 0])
# no translation. center of obj:[0,0]
t = [0, 0, 0]
transformed_vertices = mesh.transform.similarity_transform(vertices, s, R, t)
其中,angle2matrix的源码如下:
def angle2matrix(angles):''' get rotation matrix from three rotation angles(degree). right-handed.Args:angles: [3,]. x, y, z anglesx: pitch. positive for looking down.y: yaw. positive for looking left. z: roll. positive for tilting head right. Returns:R: [3, 3]. rotation matrix.'''x, y, z = np.deg2rad(angles[0]), np.deg2rad(angles[1]), np.deg2rad(angles[2])# xRx=np.array([[1, 0, 0],[0, cos(x), -sin(x)],[0, sin(x), cos(x)]])# yRy=np.array([[ cos(y), 0, sin(y)],[ 0, 1, 0],[-sin(y), 0, cos(y)]])# zRz=np.array([[cos(z), -sin(z), 0],[sin(z), cos(z), 0],[ 0, 0, 1]])R=Rz.dot(Ry.dot(Rx))return R.astype(np.float32)
其作用是根据输入的角度生产旋转矩阵。
x:pitch 倾斜。正,向下看。
y: yaw 偏转。正,向左看。
z: roll 滚动。正,表示向右倾斜头部。
similarity_transform 的源码如下:
def similarity_transform(vertices, s, R, t3d):''' similarity transform. dof = 7.3D: s*R.dot(X) + tHomo: M = [[sR, t],[0^T, 1]]. M.dot(X)Args:(float32)vertices: [nver, 3]. s: [1,]. scale factor.R: [3,3]. rotation matrix.t3d: [3,]. 3d translation vector.Returns:transformed vertices: [nver, 3]'''t3d = np.squeeze(np.array(t3d, dtype = np.float32))transformed_vertices = s * vertices.dot(R.T) + t3d[np.newaxis, :]return transformed_vertices
输入三维顶点、缩放因子s、旋转角R和平移向量t3d,即可得到变换后的新坐标
2.3 修改颜色/纹理(添加光照)
添加点光源。光源位置在世界坐标系中定义
# ------------------------------ 3. modify colors/texture(add light)
# -- add point lights. light positions are defined in world space
# set lights
light_positions = np.array([[-128, -128, 300]])
light_intensities = np.array([[1, 1, 1]])
lit_colors = mesh.light.add_light(transformed_vertices, triangles, colors, light_positions, light_intensities)
其中,mesh.light.add_light定义如下
def add_light(vertices, triangles, colors, light_positions = 0, light_intensities = 0):''' Gouraud shading. add point lights.In 3d face, usually assume:1. The surface of face is Lambertian(reflect only the low frequencies of lighting)2. Lighting can be an arbitrary combination of point sources3. No specular (unless skin is oil, 23333)Ref: https://cs184.eecs.berkeley.edu/lecture/pipeline Args:vertices: [nver, 3]triangles: [ntri, 3]light_positions: [nlight, 3] light_intensities: [nlight, 3]Returns:lit_colors: [nver, 3]'''nver = vertices.shape[0]normals = get_normal(vertices, triangles) # [nver, 3]# ambient# La = ka*Ia# diffuse# Ld = kd*(I/r^2)max(0, nxl)direction_to_lights = vertices[np.newaxis, :, :] - light_positions[:, np.newaxis, :] # [nlight, nver, 3]direction_to_lights_n = np.sqrt(np.sum(direction_to_lights**2, axis = 2)) # [nlight, nver]direction_to_lights = direction_to_lights/direction_to_lights_n[:, :, np.newaxis]normals_dot_lights = normals[np.newaxis, :, :]*direction_to_lights # [nlight, nver, 3]normals_dot_lights = np.sum(normals_dot_lights, axis = 2) # [nlight, nver]diffuse_output = colors[np.newaxis, :, :]*normals_dot_lights[:, :, np.newaxis]*light_intensities[:, np.newaxis, :]diffuse_output = np.sum(diffuse_output, axis = 0) # [nver, 3]# specular# h = (v + l)/(|v + l|) bisector# Ls = ks*(I/r^2)max(0, nxh)^p# increasing p narrows the reflectionloblit_colors = diffuse_output # only diffuse part here.lit_colors = np.minimum(np.maximum(lit_colors, 0), 1)return lit_colors
Gouraud 着色法:是用于网格中插值的着色方法,可实现边缘的连续变化。在三维人脸中,通常由以下假设:
1、人脸表面是Lambertian,即朗博表面,只会反射低频的光
2、光照可以是点光源的任意组合。
3、无镜面反射。
这些参考了https://cs184.eecs.berkeley.edu/lecture/pipeline。但是这个网站好像挂掉了
get_normal函数在源码中另有定义,这里不再赘述。
输入的参数有:顶点坐标、三角网格数据、光源位置、光线强度。经过运算后输出加入点光源后的颜色数据。这里,如果没有相关知识,默认拿来使用即可。
2.4 修改顶点(映射,改变相机位置)
将对象从世界坐标系转换为相机坐标系,即观察者角度。如果使用标准相机,可忽略。
# ------------------------------ 4. modify vertices(projection. change position of camera)
# -- transform object from world space to camera space(what the world is in the eye of observer).
# -- omit if using standard camera
camera_vertices = mesh.transform.lookat_camera(transformed_vertices, eye = [0, 0, 200], at = np.array([0, 0, 0]), up = None)
# -- project object from 3d world space into 2d image plane. orthographic or perspective projection
projected_vertices = mesh.transform.orthographic_project(camera_vertices)
其中,相机坐标系lookat_camera的定义如下:
def normalize(x):epsilon = 1e-12norm = np.sqrt(np.sum(x**2, axis = 0))norm = np.maximum(norm, epsilon)return x/norm
def lookat_camera(vertices, eye, at = None, up = None):""" 'look at' transformation: from world space to camera spacestandard camera space: camera located at the origin. looking down negative z-axis. vertical vector is y-axis.Xcam = R(X - C)Homo: [[R, -RC], [0, 1]]Args:vertices: [nver, 3] eye: [3,] the XYZ world space position of the camera.5at: [3,] a position along the center of the camera's gaze.up: [3,] up direction Returns:transformed_vertices: [nver, 3]"""if at is None:at = np.array([0, 0, 0], np.float32)if up is None:up = np.array([0, 1, 0], np.float32)eye = np.array(eye).astype(np.float32)at = np.array(at).astype(np.float32)z_aixs = -normalize(at - eye) # look forwardx_aixs = normalize(np.cross(up, z_aixs)) # look righty_axis = np.cross(z_aixs, x_aixs) # look upR = np.stack((x_aixs, y_axis, z_aixs))#, axis = 0) # 3 x 3transformed_vertices = vertices - eye # translationtransformed_vertices = transformed_vertices.dot(R.T) # rotationreturn transformed_vertices
标准相机空间设定为:相机在原点;向下看,是负Z轴;垂直向量为Y轴。
输入参数为:顶点,摄像机在世界坐标系的位置,沿着相机视线中心的位置(默认为[0,0,0]),向上方向(默认为(0,1,0))
根据输入,计算出旋转矩R,并通过Xcam=R(X-C)计算出新顶点的位置。
2.5 转化为2D图像
设置图像宽高为256
# ------------------------------ 5. render(to 2d image)
# set h, w of rendering
h = w = 256
# change to image coords for rendering
image_vertices = mesh.transform.to_image(projected_vertices, h, w)
# render
rendering = mesh.render.render_colors(image_vertices, triangles, lit_colors, h, w)
mesh.transform.to_image部分的源码如下:
def to_image(vertices, h, w, is_perspective = False):''' change vertices to image coord system3d system: XYZ, center(0, 0, 0)2d image: x(u), y(v). center(w/2, h/2), flip y-axis. Args:vertices: [nver, 3]h: height of the renderingw : width of the renderingReturns:projected_vertices: [nver, 3] '''image_vertices = vertices.copy()if is_perspective:# if perspective, the projected vertices are normalized to [-1, 1]. so change it to image size first.image_vertices[:,0] = image_vertices[:,0]*w/2image_vertices[:,1] = image_vertices[:,1]*h/2# move to center of imageimage_vertices[:,0] = image_vertices[:,0] + w/2image_vertices[:,1] = image_vertices[:,1] + h/2# flip vertices along y-axis.image_vertices[:,1] = h - image_vertices[:,1] - 1return image_vertices
输入参数为:顶点坐标、图像宽高、透视选项(默认为Fals),通过计算得到二维顶点坐标。
mesh.render.render_colors的源码如下:(此为numpy版本)
def render_colors(vertices, triangles, colors, h, w, c = 3):''' render mesh with colorsArgs:vertices: [nver, 3]triangles: [ntri, 3] colors: [nver, 3]h: heightw: width Returns:image: [h, w, c]. '''assert vertices.shape[0] == colors.shape[0]# initial image = np.zeros((h, w, c))depth_buffer = np.zeros([h, w]) - 999999.for i in range(triangles.shape[0]):tri = triangles[i, :] # 3 vertex indices# the inner bounding boxumin = max(int(np.ceil(np.min(vertices[tri, 0]))), 0)umax = min(int(np.floor(np.max(vertices[tri, 0]))), w-1)vmin = max(int(np.ceil(np.min(vertices[tri, 1]))), 0)vmax = min(int(np.floor(np.max(vertices[tri, 1]))), h-1)if umax<umin or vmax<vmin:continuefor u in range(umin, umax+1):for v in range(vmin, vmax+1):if not isPointInTri([u,v], vertices[tri, :2]): continuew0, w1, w2 = get_point_weight([u, v], vertices[tri, :2])point_depth = w0*vertices[tri[0], 2] + w1*vertices[tri[1], 2] + w2*vertices[tri[2], 2]if point_depth > depth_buffer[v, u]:depth_buffer[v, u] = point_depthimage[v, u, :] = w0*colors[tri[0], :] + w1*colors[tri[1], :] + w2*colors[tri[2], :]return image
输入为顶点坐标、三角网格数据、网格颜色数据以及目标图片的长宽。
输出为目标的带纹理的二维图像数据。
# ---- show rendering
# plt.imshow(rendering)
# plt.show()
save_folder = 'results/pipeline'
if not os.path.exists(save_folder):os.mkdir(save_folder)
io.imsave('{}/rendering.jpg'.format(save_folder), rendering)
# ---- show mesh
# mesh.vis.plot_mesh(camera_vertices, triangles)
# plt.show()
这里展示二维图片效果:
也可展示出相加空间下的模型:
总结
这里主要介绍如何重现效果,以及解读如何从3D人脸数据转换为二维人脸数据的代码。那么,三维数据又包含哪些信息呢?如何实现不同的三维人脸生成呢?继续系列二。
相关文章:
三维人脸实践:基于Face3D的渲染、生成与重构 <一>
face3d: Python tools for processing 3D face git code: https://github.com/yfeng95/face3d paper list: PaperWithCode 该方法广泛用于基于三维人脸关键点的人脸生成、属性检测(如位姿、深度、PNCC等),能够快速实现人脸建模与渲染。推荐…...
Javascript 设计模式
设计模式的五大设计原则(SOLID)单一职责:一个程序只需要做好一件事。如果功能过于复杂就拆分开,保证每个部分的独立开放封闭原则:对扩展开放,对修改封闭。增加需求时,扩展新代码,而不是修改源代码。这是软件设计的终极…...
JAVA-文档工具screw-gui
前言 为什么萌生了写文档工具得想法,因为在项目开发得过程中,经常需要补充一些文档,比如数据库文档、详细设计文档等等,文档与项目相绑定,在项目需求新增或变更时,文档也需要反反复复得修改。 1. 数据库…...
开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一)
开源鸿蒙南向嵌入学习笔记——NAPI框架学习(一) 前言——系列介绍 本系列文章主要是记录笔者在鸿蒙南向的学习与工作中的知识点笔记记录,其中不止会针对鸿蒙中的学习问题进行思考与记录,也会对涉及到的一些嵌入式等其他领域知识&…...
Spring - Spring框架概述面试题总结
文章目录01. 什么是Spring?02. Spring框架的设计目标,设计理念,和核心是什么?03. Spring的优点是什么?04. Spring框架中都用到了哪些设计模式?05. Spring有哪些应用场景?06. Spring由哪些模块组成…...
学习python好就业么
Python的普及与数据挖掘、人工智能和数值计算等领域的蓬勃发展相关,但同时也与普遍编程需求的增加有关。 Python作为人工智能的头号语言,一方面会吸引大量计划从事人工智能的人来学习,另一方面自然也带动了网络上对这门“新语言”的关注和讨…...
瑞幸咖啡的最终目标并不是做国内市场大哥
出品 | 何玺 排版 | 叶媛 日前,瑞幸咖啡发布2022年第四季度及全年财报。数据显示,在刚刚过去的2022年,瑞幸咖啡首次实现了营收超百亿,门店规模也超越老对手星巴克,成为了国内第一连锁咖啡品牌。 那么,瑞幸…...
GPT 模型介绍 | GPT3 / GPT3.5 + Flask | Github源码链接
1. 模型介绍 Chatgpt 使用与 InstructGPT相同的方法,使用来自人类反馈的强化学习 (RLHF) 来训练该模型,但数据收集设置略有不同。我们使用监督微调训练了一个初始模型:人类 AI 训练员提供对话,他们在对话中扮演双方——用户和 AI…...
蓝桥杯入门即劝退(二十六)组合问题(回溯算法)
-----持续更新Spring入门系列文章----- 如果你也喜欢Java和算法,欢迎订阅专栏共同学习交流! 你的点赞、关注、评论、是我创作的动力! -------希望我的文章对你有所帮助-------- 专栏:蓝桥杯系列 一、题目描述 给定两个整数 n …...
现代卷积神经网络(ResNet)
专栏:神经网络复现目录 本章介绍的是现代神经网络的结构和复现,包括深度卷积神经网络(AlexNet),VGG,NiN,GoogleNet,残差网络(ResNet),稠密连接网络…...
PTA:L1-019 谁先倒、L1-020 帅到没朋友、L1-021 重要的话说三遍(C++)
目录 L1-019 谁先倒 问题描述: L1-020 帅到没朋友 问题描述: 实现代码(只过了部分): L1-021 重要的话说三遍 问题描述: 实现代码: 无解析 L1-019 谁先倒 问题描述: 划拳是…...
STL常见容器之set/multiset、map/multimap
set/multiset—集合容器 特点 所有元素都会在插入时自动被排序 本质 set/multiset属于关联式容器,底层结构是二叉树实现 set和multiset区别 set不可以插入重复数据,而multiset可以set插入数据的同时会返回插入结果,表示插入是否成功multiset…...
ThreadLocal 实现原理
每个 Thread 中都存储着一个成员变量:ThreadLocalMap /** InheritableThreadLocal values pertaining to this thread. This map is* maintained by the InheritableThreadLocal class.*/ThreadLocal.ThreadLocalMap inheritableThreadLocals null; ThreadLocal 本…...
BUUCTF [羊城杯 2020]easyre 题解
一.查壳 64位无壳 二.主函数逻辑 可以得知flag长度为38,然后进行三次加密 第一次加密是base64加密,得到code1 第二次加密是将code1拆成四段赋给code2 第三次加密是将code2内的数字和字母移3位,其他字符不变 str2保存的是最终的加密字符 三.encode_one_base64 看到主函数…...
网络协议(十二):HTTPS(SSL/TLS、TLS1.2的连接)
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
九九乘法表--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)
实例9:九九乘法表 乘法口诀是中国古代筹算中进行乘法、除法、开方等运算的基本计算规则,沿用至今已有两千多年。古代的乘法口诀与现在使用的乘法口诀顺序相反,自上而下从“九九八十一”开始到“一一如一”为止,因此,古…...
在超算上安装文件树命令tree
超算平台使用的centos系统没有内置tree命令,需要通过源码安装。记录安装流程如下。 1. 下载源码包 下载链接如下: http://mama.indstate.edu/users/ice/tree/ 选择“Download the latest version” 如本文下载了源码包“tree-2.1.0.tgz”. 2. 源码包…...
论文投稿指南——中文核心期刊推荐(经济管理)
【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…...
在vue中如果computed属性是一个异步操作怎么办?
在计算属性中使用异步方法时,可以使用async/await来处理异步操作。由于计算属性是基于它们的依赖缓存的,所以我们需要使用一个返回Promise的异步方法来确保计算属性能够正常运行。 下面是一个简单的示例,演示如何在计算属性中使用异步方法&am…...
SRP合批问题
1)SRP合批问题 2)多个Base相机渲染到同一个渲染目标,移动平台花屏的问题 3)粒子系统对GPU Instancing的支持 4)如何修改URP下场景和UI分辨率分离(不需要改颜色空间) 这是第327篇UWA技术知识分…...
蓝牙5.1低功耗SOC 私有协议2.4GHz芯片HS6621
HS6621CxC是一个优化功耗真正芯片系统(SOC)解决方案,适用于蓝牙低功耗和私有的2.4GHz应用场景。它集成了一个高性能、小功率的射频收发器,具有蓝牙基带和丰富的外围IO扩展。还集成了电源管理,以提供高效的电源管理。 …...
数据库连接池
数据库连接---执行完毕---释放 连接--释放 十分浪费系统资源 池化技术:准备一些预先的资源,过来就连接预先准备好的 最小连接数: 10 最大连接数:15 业务最高承载上限 排队等待, 等待超时:100…...
Arrays-sort-的用法
1.集合交换元素 Collections.swap(List<?> list, int i, int j); 源码: /*** Swaps the elements at the specified positions in the specified list.* (If the specified positions are equal, invoking this method …...
华为OD机试真题Java实现【寻找相同子串】真题+解题思路+代码(20222023)
寻找相同子串 题目 给你两个字符串 t 和 p ,要求从 t 中找到一个和 p 相同的连续子串,并输出该字串第一个字符的下标。 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Java)真题目录汇总 输入描述: 输入文件包括两行,分别表示字符串 t 和 p ,保证 t 的长度…...
性能指标 确定性能目标 性能场景设计
性能测试指标 性能测试指标分为业务技术指标和系统资源指标,在服务端性能业务技术指标中分为三个指标,系统吞吐量,响应时间和并发用户数。响应时间分为前端展现时间和系统响应时间两部分,系统吞吐量体现软件系统负载承受能力的指…...
ENVI_Classic:快速入门_菜单栏常见功能的基本介绍
说明:由于实验要求,所以并没有对各个功能进行详尽的解释,大多点到为止,少部分实验内容是实验要求所以步骤详尽。当然由于经验不足,有一些可能存在错误恳请指正.1. 实验目的通过ENVI Classic对自行下载的遥感图像进行一…...
【深度探讨】公共部门在选择区块链平台时要考虑的6个方面
发表时间:2022年8月17日 信息来源:bsvblockchain.org 与私营企业相比,全球的公共部门组织在考虑升级软件解决方案时面临着一系列的全新挑战。公共部门的决策流程冗长而复杂,他们要不惜一切代价避免对现有业务造成干扰,…...
基于阿里云物联网平台设计的实时图传系统_采用MQTT协议传输图像
一、项目功能介绍 当前基于MQTT协议设计了一个实时图传系统,通过这个项目来演示,两个MQTT设备如何互相订阅,进行消息流转。 在阿里云服务器上创建2个设备,分为为设备A和设备B;设备A负责采集本地摄像头画面上传,设备B负责接收设备A上传的数据然后解析显示出来。在阿里云服…...
42-Golang中的单元测试
Golang中的单元测试需求传统方法基本介绍单元测试快速入门总结综合案例需求 在工作中,我们会遇到这样的情况,就是去确认一个函数,或者一个模块的结果是否正确 传统方法 在main函数中,调用addUpper函数,看看实际输出…...
python实现k_means聚类
K-Means算法是将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上来看是簇是一组一组聚集在一起的数据,在一个簇中的数据就认为是同一类。簇就是聚类的结果表现。簇中所有数据的均值通常被称为这个簇的“质心”(Centroids)。在一个二维平面中ÿ…...
浏览网站内下载文件/91关键词
之前用springboot的时候,只知道捕获异常使用try{}catch,一个接口一个try{}catch,这也是大多数开发人员异常处理的常用方式,虽然屡试不爽,但会造成一个问题,就是一个Controller下面,满屏幕的try{…...
网站建设方案及报价单/百度人工服务热线
2019独角兽企业重金招聘Python工程师标准>>> Can not deserialize instance of java.lang.String out of START_OBJECT token 前端和后端对应得数据类型不一致,前端传得是对象中得一个类型是json,后端是字符串类型 转载于:https://my.oschina…...
百度网站建设中的自由容器/互动营销名词解释
在这之前,我曾认真的研究过鸿洋大神的Android 自定义ViewGroup 实战篇 -> 实现FlowLayout,按照大神的思路写出了一个流式布局,所有的东西都是难者不会会者不难,当自己能自定义流式布局的时候就会觉得这东西原来很简单了。如果各…...
网页配色网站/软件外包公司
孙广东 2015.6.20 先贴一个 Grid网格吧。 可以标记一个对象的正方形范围等拖拽到指定的对象就OK了。 using UnityEngine; using System.Collections;// DrawGizmoGrid.cs // draws a useful reference grid in the editor in Unity. // 09/01/15 - Hayden Scott-Baron // …...
英国人做愛无网站/百度知道客服电话人工服务
(文章出处不详,转自:http://blog.csdn.net/hairetz/article/details/4137000) C中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用…...
做相册的网站dw/深圳关键词快速排名
TIOBE 公布了2020年4月编程语言排行榜,总体排名变化不大,排名前十的分别是:Java, C, C, Python, Visual Basic .NET, C#, JavaScript, SQL, PHP 和 汇编语言。 值得一提的是,基于图形块的编程语言 Scratch 本月进入了 TIOBE 指数…...