三维人脸实践:基于Face3D的渲染、生成与重构 <一>

news2025/7/17 21:20:40

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 render

mesh_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:
	numpy
	skimage (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 plt

sys.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 angles
        x: 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])
    # x
    Rx=np.array([[1,      0,       0],
                 [0, cos(x),  -sin(x)],
                 [0, sin(x),   cos(x)]])
    # y
    Ry=np.array([[ cos(y), 0, sin(y)],
                 [      0, 1,      0],
                 [-sin(y), 0, cos(y)]])
    # z
    Rz=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) + t
    Homo: 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 sources
    3. 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 reflectionlob

    lit_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-12
    norm = 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 space
    standard 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.5
      at: [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 forward
    x_aixs = normalize(np.cross(up, z_aixs)) # look right
    y_axis = np.cross(z_aixs, x_aixs) # look up

    R = np.stack((x_aixs, y_axis, z_aixs))#, axis = 0) # 3 x 3
    transformed_vertices = vertices - eye # translation
    transformed_vertices = transformed_vertices.dot(R.T) # rotation
    return 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 system
    3d 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 rendering
        w : width of the rendering
    Returns:
        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/2
        image_vertices[:,1] = image_vertices[:,1]*h/2
    # move to center of image
    image_vertices[:,0] = image_vertices[:,0] + w/2
    image_vertices[:,1] = image_vertices[:,1] + h/2
    # flip vertices along y-axis.
    image_vertices[:,1] = h - image_vertices[:,1] - 1
    return image_vertices

输入参数为:顶点坐标、图像宽高、透视选项(默认为Fals),通过计算得到二维顶点坐标。

mesh.render.render_colors的源码如下:(此为numpy版本)

def render_colors(vertices, triangles, colors, h, w, c = 3):
    ''' render mesh with colors
    Args:
        vertices: [nver, 3]
        triangles: [ntri, 3] 
        colors: [nver, 3]
        h: height
        w: 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 box
        umin = 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:
            continue

        for u in range(umin, umax+1):
            for v in range(vmin, vmax+1):
                if not isPointInTri([u,v], vertices[tri, :2]): 
                    continue
                w0, 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_depth
                    image[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人脸数据转换为二维人脸数据的代码。那么,三维数据又包含哪些信息呢?如何实现不同的三维人脸生成呢?继续系列二。

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

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

相关文章

学生使用的台灯该怎么选择?2023适合学生房间的灯推荐

随着社会的进步发展&#xff0c;我们的生活水平越来越高&#xff0c;很多家庭的孩子都开始使用台灯这种家居产品&#xff0c;对于学习任务繁重的他们来说&#xff0c;台灯确实可以起到保护眼睛、提高学习专注度的作用。那么不知道朋友们是否了解过&#xff0c;台灯该怎么选择呢…

本地开发vue项目联调遇到访问接口跨域问题

本地开发vue项目联调遇到访问接口跨域问题 修改本地的localhost 一&#xff1a;按winr打开运行窗口&#xff0c;输入drivers &#xff0c;然后回车 二&#xff1a;打开etc文件夹&#xff0c;然后用记事本的方式打开里面的hosts文件&#xff0c; 三&#xff1a;这时我们就可…

oneblog_justauth_三方登录配置【QQ】

文章目录oneblog添加第三方平台QQ互联平台创建三方应用完善信息登录oneblog添加第三方平台 1.oneblog管理端&#xff0c;点击左侧菜单 网站管理——>社会化登录配置管理 ,添加一个社会化登录 2.编辑信息如下&#xff0c;选择QQ平台后复制redirectUri,然后去QQ互联平台获取…

UART 串口通信

第18.1讲 UART串口通信原理讲解_哔哩哔哩_bilibili 并行通信 一个周期同时发送8bit的数据&#xff0c;占用引脚资源多 串行通信 串行通信的通信方式&#xff1a; 同步通信 同一时钟下进行数据传输 异步通信 发送设备和接收设备的时钟不同 但是需要约束波特率&#xff08;…

大数据|HDFS分布式文件系统

前文回顾&#xff1a;Hadoop系统 目录 &#x1f4da;HDFS概述 &#x1f4da;HDFS在设计时的假设和目标 &#x1f4da;HDFS的基本特征 &#x1f4da;HDFS的体系结构 &#x1f407;目录节点 &#x1f407;数据节点 &#x1f4da;HDFS的副本机制 &#x1f4da;HDFS的数据存…

KD500全自动电容电感测试仪

一、产品特点 1.本仪器采用了先进的测量原理与四端测量技术&#xff0c;可以精确测量、测试重复性能好&#xff1b; 2.能在不拆线的状态下&#xff0c;测量成组并联着的单个电容器的电容量和成组并联着电容器组的总电容量&#xff1b; 3.大屏幕液晶显示屏&#xff08;320X24…

关于Activiti7审批工作流绘画流程图(2)

文章目录一、25张表详解二、安装插件一.定制流程提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、25张表详解 虽然表很多&#xff0c;但是仔细观察&#xff0c;我们会发现Activiti 使用到的表都是 ACT_ 开头的。表名的第二部分用两个字母表明表的用…

vuex基础之初始化功能、state、mutations、getters、模块化module的使用

vuex基础之初始化功能、state、mutations、getters、模块化module的使用一、Vuex的介绍二、初始化功能三、state3.1 定义state3.2 获取state3.2.1 原始形式获取3.2.2 辅助函数获取(mapState)四、mutations4.1 定义mutations4.2 调用mutations4.2.1 原始形式调用($store)4.2.2 辅…

数据分析方法及名词解释总结_(面试2)

1、用户画像 1.1、什么是用户画像&#xff1f;如何构建用户画像&#xff1f; - 知乎提到用户画像&#xff0c; 很多人都可能存在的错误认知&#xff0c;即把用户画像简单理解成用户各种特征&#xff0c;比如说姓名、性别、…https://www.zhihu.com/question/372802348/answer/2…

spi 子系统

spi在应用层的体现 spi 分为主机模式和从机模式&#xff0c;一般soc 自带的spi 控制器&#xff0c;我们都将它用作主机模式与外挂的从设备通信。从设备例如 oled芯片、flash芯片、陀螺仪芯片等等。 那么spi 驱动和设备&#xff0c;自然也就分为主机驱动、设备和从机驱动、设备…

云原生时代顶流消息中间件Apache Pulsar部署实操之Pulsar IO与Pulsar SQL

文章目录Pulsar IO (Connector连接器)基础定义安装Pulsar和内置连接器连接Pulsar到Cassandra安装cassandra集群配置Cassandra接收器创建Cassandra Sink验证Cassandra Sink结果删除Cassandra Sink连接Pulsar到PostgreSQL安装PostgreSQL集群配置JDBC接收器创建JDBC Sink验证JDBC …

redis cluster配置之read-mode

背景生产部署了redis集群&#xff0c;三台机器&#xff08;三主三从&#xff0c;主从不在同一台机器上&#xff09;&#xff0c;redission连接使用。当有一个master节点挂掉时&#xff0c;redis整个集群不可用。解决过程运维登上机器上&#xff0c;执行cluster info发现集群OK状…

JAVA开发(数据类型String和HasMap的实现原理)

在JAVA开发中&#xff0c;使用最多的数据类型恐怕是String 和 HasMap两种数据类型。在开发的过程中我们每天都使用的不亦乐乎。但是相信很多人都没有考虑过String数据类型的实现原理或者说是在数据结构中的存储原理&#xff0c;还有一个就是是HashMap&#xff0c;也很少有人去了…

SNAP中根据入射角和相干图使用波段计算计算垂直形变--以门源地震为例

SNAP计算垂直形变0 写在前面1 具体步骤1.1 准备数据1.2 在SNAP中打开波段运算Band Maths1.3 之前计算的水平位移displacement如下图数据的其他处理请参考博文在SNAP中用sentinel-1数据做InSAR测量&#xff0c;以门源地震为例 0 写在前面 如果假设没有平行于传感器视线的水平运…

案例27-单表从9个更新语句调整为2个

目录 一&#xff1a;背景介绍 二&#xff1a;思路&方案 三&#xff1a;过程 1.项目结构 2.准备一个普通的maven项目&#xff0c;部署好mysql数据库 3.在项目中引入pom依赖 5.编写MyBitis配置文件 6.编写Mysql配置类 7.编写通用Update语句 8.项目启动类 四&#xff1a;总…

用GRU实现情感分析:不需要长记忆,也能看懂你的心情

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️&#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

JavaScript_Object.keys() Object.values()

目录 一、Object.keys() 二、Object.values() 一、Object.keys() Object.keys( ) 的 用法 : 作用 &#xff1a;遍历对象 { } 返回结果&#xff1a;返回 对象中 每一项 的 key 值 返回值 : 是一个 *** [ 数 组 ] *** 例子 ( 1 ) : <script>// 1. 定义一个对象var obj …

【硬件】P沟道和N沟道MOS管开关电路设计

场效应管做的开关电路一般分为两种&#xff0c;一种是N沟道&#xff0c;另一种是P沟道&#xff0c;如果电路设计中要应用到高端驱动的话&#xff0c;可以采用PMOS来导通。P沟道MOS管开关电路PMOS的特性&#xff0c;Vgs小于一定的值就会导通&#xff0c;当Vgs<0,即Vs>Vg,管…

扬帆优配|高送转+高分红+高增长潜力股揭秘

高送转且高分红的高增加股票&#xff0c;有望跑赢大盘。 此前七连阴的泽宇智能&#xff0c;今日早盘大幅高开。到上午收盘&#xff0c;该股飙涨9.3%&#xff0c;位居涨幅榜前列。音讯面上&#xff0c;3月7日晚间&#xff0c;泽宇智能发表2022年年报&#xff0c;年报显现&#x…

深入学习Spring——笔记

实习之余多学点&#xff0c;希望一个月之内能够完成这个笔记 Spring笔记3-8BeanFactory && ApplicationContextBeanFactoryApplicationContext3-8 BeanFactory && ApplicationContext BeanFactory 首先&#xff0c;从SpringBoot的主启动类来看 SpringBootA…