基于 Wav2Lip-GFPGAN 深度学习模型的数字人Demo

news2024/11/25 2:30:29

写在前面


  • 工作中遇到简单整理
  • 博文为 Wav2Lip-GFPGAN 环境搭建运行的 Demo
  • 理解不足小伙伴帮忙指正

对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧 ——赫尔曼·黑塞《德米安》


Demo简单介绍

Wav2Lip-GAN

Wav2Lip-GAN 是一种基于生成对抗网络(GAN)的语音到唇形的转换模型。https://github.com/Rudrabha/Wav2Lip

基本原理是使用语音信号和人脸图像来训练一个生成器网络,该网络可以将输入的语音信号转换为对应的唇形。

该模型包括两个子网络:

  • 一个是语音识别网络,用于将语音信号转换为文本;
  • 另一个是唇形生成网络,用于将文本和人脸图像作为输入,生成对应的唇形。

两个网络通过GAN框架进行训练,以使生成的唇形尽可能地逼真。在测试阶段,给定一个语音信号和一个人脸图像,该模型可以生成一个与语音信号相对应的唇形序列,从而实现语音到唇形的转换。

GFPGAN

腾讯 GFPGAN 是一种基于生成对抗网络(GAN)的图像超分辨率模型。https://github.com/TencentARC/GFPGAN

基本原理是使用低分辨率的图像作为输入,通过生成器网络将其转换为高分辨率的图像。

该模型包括两个子网络:

  • 一个是生成器网络,用于将低分辨率图像转换为高分辨率图像;
  • 另一个是判别器网络,用于评估生成的图像是否逼真。

两个网络通过GAN框架进行训练,以使生成的图像尽可能地接近真实图像。在测试阶段,给定一个低分辨率的图像,该模型可以生成一个与之对应的高分辨率图像。腾讯GFPGAN采用了一些创新的技术,如渐进式训练、自适应实例归一化等,使得其在图像超分辨率任务中表现出色。

Demo 来自下面的项目完成,小伙伴可以直接参考。作者提供了一个ipynb Demo GitHub\Wav2Lip-GFPGAN\Wav2Lip-GFPGAN.ipynb,有基础小伙伴按照步骤即可完成,下面的就不需要看了

https://github.com/ajay-sainy/Wav2Lip-GFPGAN/

有困难的小伙伴可以克隆下面的这个,fork 了上面的项目,提供了当前搭建环境步骤,需要的素材脚本:

https://github.com/LIRUILONGS/Wav2Lip-GFPGAN_Python_Demo

涉及到的模型和安装包下载

Wav2Lip

可以在项目中看到下载路径: https://github.com/Rudrabha/Wav2Lip

Wav2Lip:https://iiitaphyd-my.sharepoint.com/:u:/g/personal/radrabha_m_research_iiit_ac_in/Eb3LEzbfuKlJiR600lQWRxgBIY27JZg80f7V9jtMfbNDaQ?e=TBFBVW

Wav2Lip + GAN :https://iiitaphyd-my.sharepoint.com/:u:/g/personal/radrabha_m_research_iiit_ac_in/EdjI7bZlgApMqsVoEUUXpLsBxqXbn5z8VTmoxp55YNDcIA?e=n9ljGW

ffmpeg: https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-essentials.7z ,Linux 环境直接用包管理工具安装即可

ffmpeg 装完之后 win系统 需要配置环境变量,这里不多讲。

GFPGAN

GFPGANv1.3.pth:https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth

parsing_parsenet.pth:https://github.com/xinntao/facexlib/releases/download/v0.2.2/parsing_parsenet.pth

detection_Resnet50_Final.pth:https://github.com/xinntao/facexlib/releases/download/v0.1.0/detection_Resnet50_Final.pth

环境安装

wav2lip 环境

当前系统环境为 window11,Anaconda3 使用CPU 跑,虚拟环境创建

C:\Users\liruilong>conda create -n wav2lip python=3.8
C:\Users\liruilong>conda info --envs
# conda environments:
#
base                  *  C:\ProgramData\Anaconda3
myenv                    C:\Users\liruilong\AppData\Local\conda\conda\envs\myenv
wav2lip                  C:\Users\liruilong\AppData\Local\conda\conda\envs\wav2lip

切换虚拟环境的时候,报错了

C:\Users\liruilong>conda activate wav2lip
.....

后来在Anaconda Prompt (Anaconda3) 可以正常执行

(base) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>conda activate wav2lip

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>conda list
.....

安装 requirements.txt 中的依赖库,直接安装报错了

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>pip install -r requirements.txt   -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
Looking in indexes: http://pypi.douban.com/simple/

需要添加 --use-pep517

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>pip install -r requirements.txt   -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com  --use-pep517
Looking in indexes: http://pypi.douban.com/simple/

检测 wav2lip 环境运行Demo 测试一下,当前项目预留了一些素材,这里使用模型wav2lip.pth

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>python .\Wav2Lip-master\inference.py --checkpoint_path .\Wav2Lip-master\checkpoints\wav2lip.pth --face .\inputs\kim_7s_raw.mp4 --audio .\inputs\kim_audio.mp3 --outfile result.mp4
Using cpu for inference.
Reading video frames...
Number of frames available for inference: 223
Extracting raw audio...
...................................
[libx264 @ 0000022caf538200] Weighted P-Frames: Y:1.2% UV:1.2%
[libx264 @ 0000022caf538200] ref P L0: 68.7%  8.6% 16.2%  6.4%
[libx264 @ 0000022caf538200] ref B L0: 75.0% 20.2%  4.8%
[libx264 @ 0000022caf538200] ref B L1: 94.9%  5.1%
[libx264 @ 0000022caf538200] kb/s:1433.66
[aac @ 0000022caf528940] Qavg: 237.868

运行完会在当前目录生成 result.mp4 文件

https://www.bilibili.com/video/BV1fX4y187jW/

然后用模型wav2lip_gan.pth 在试下

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>python .\Wav2Lip-master\inference.py --checkpoint_path  .\inputs\wav2lip_gan.pth --face .\inputs\kim_7s_raw.mp4 --audio .\inputs\kim_audio.mp3 --outfile result.mp4
Using cpu for inference.

https://www.bilibili.com/video/BV1Vo4y1T7F2/

这里 wav2lip 环境已经安装完成

GFPGAN 环境

准备一个新的音视频,使用 wav2lip_gan 生成,准备GFPGAN 环境

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>python .\Wav2Lip-master\inference.py --checkpoint_path  .\inputs\wav2lip_gan.pth --face .\inputs\demo.mp4 --audio .\inputs\demo_5_y.mp3 --outfile result.mp4
Using cpu for inference.
Reading video frames...
Number of frames available for inference: 2116
Extracting raw audio..
。。。。。。。。。。。。。。。。。。。。。
[libx264 @ 000001ba2a798d80] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 18% 18% 48%  3%  2%  2%  2%  3%  3%
[libx264 @ 000001ba2a798d80] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 23% 22% 17%  6%  6%  6%  6%  7%  8%
[libx264 @ 000001ba2a798d80] i8c dc,h,v,p: 49% 20% 22%  8%
[libx264 @ 000001ba2a798d80] Weighted P-Frames: Y:0.0% UV:0.0%
[libx264 @ 000001ba2a798d80] ref P L0: 80.9% 10.0%  6.6%  2.5%
[libx264 @ 000001ba2a798d80] ref B L0: 87.8% 10.5%  1.7%
[libx264 @ 000001ba2a798d80] ref B L1: 98.7%  1.3%
[libx264 @ 000001ba2a798d80] kb/s:703.37
[aac @ 000001ba2a79a780] Qavg: 170.234

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>

https://www.bilibili.com/video/BV1cX4y1h7k8/

创建一个结果文件夹

PS C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN> mkdir results


    目录: C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----          2023/6/9      7:14                results


PS C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>

需要把上面生成的文件移到这个文件夹里面,然后执行下面的脚本

# day1.py

wav2lipFolderName = 'Wav2Lip-master'
gfpganFolderName = 'GFPGAN-master'
wav2lipPath =  '.\\' + wav2lipFolderName
gfpganPath = '.\\' + gfpganFolderName
outputPath = ".\\results"

import cv2
from tqdm import tqdm
from os import path

import os

# 上一步生成的视频
inputVideoPath = outputPath+'\\result.mp4'
# 中间数据
unProcessedFramesFolderPath = outputPath+'\\frames'

if not os.path.exists(unProcessedFramesFolderPath):
  os.makedirs(unProcessedFramesFolderPath)

vidcap = cv2.VideoCapture(inputVideoPath)
numberOfFrames = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = vidcap.get(cv2.CAP_PROP_FPS)
print("FPS: ", fps, "Frames: ", numberOfFrames)

for frameNumber in tqdm(range(numberOfFrames)):
    _,image = vidcap.read()
    cv2.imwrite(path.join(unProcessedFramesFolderPath, str(frameNumber).zfill(4)+'.jpg'), image)

print("unProcessedFramesFolderPath:",unProcessedFramesFolderPath)
print("inputVideoPath:",inputVideoPath)

作用是将wav2lip处理的视频按帧数逐帧读取,将每一帧保存为 JPEG 格式的图片,并将这些图片保存到指定的文件夹 unProcessedFramesFolderPath

(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN>python day1.py
FPS:  25.0 Frames:  1793
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1793/1793 [00:10<00:00, 166.99it/s]
unProcessedFramesFolderPath:  
inputVideoPath: .\results\result.mp4

(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN>

之后会在 .\results\frames 看到切好的照片

现在准备 GFPGAN-master 的环境

(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN\GFPGAN-master>pip install -r requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com --use-pep517
Looking in indexes: http://pypi.douban.com/simple/
..........
Installing collected packages: numpy, scikit-image
  Attempting uninstall: numpy
    Found existing installation: numpy 1.23.5
    Uninstalling numpy-1.23.5:
      Successfully uninstalled numpy-1.23.5
  Attempting uninstall: scikit-image
    Found existing installation: scikit-image 0.20.0
    Uninstalling scikit-image-0.20.0:
      Successfully uninstalled scikit-image-0.20.0
Successfully installed numpy-1.20.3 scikit-image-0.19.3

(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN\GFPGAN-master>

GFPGANv1.3.pth 模型放到 /experiments/pretrained_models 目录下

(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN\GFPGAN-master>mkdir -p .\\experiments\pretrained_models

(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN\GFPGAN-master>cd  .\\experiments\pretrained_models

确认模型

    目录: C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN\GFPGAN-master\experiments\pretrained_models


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----          2023/6/7      1:43      348632874 GFPGANv1.3.pth

之后执行下面的命令

python inference_gfpgan.py -i $unProcessedFramesFolderPath -o $outputPath -v 1.3 -s 2 --only_center_face --bg_upsampler None

替换对应的变量,如果模型无法下载,需要把前面下载的放到指定位置

(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN\GFPGAN-master>python inference_gfpgan.py -i ..\results\frames -o ..\results -v 1.3 -s 2 --only_center_face --bg_upsampler None
C:\Users\liruilong\AppData\Local\conda\conda\envs\wav2lip\lib\site-packages\torchvision\transforms\functional_tensor.py:5: UserWarning: The torchvision.transforms.functional_tensor module is deprecated in 0.15 and will be **removed in 0.17**. Please don't rely on it. You probably just need to use APIs in torchvision.transforms.functional or in torchvision.transforms.v2.functional.
  warnings.warn(
C:\Users\liruilong\AppData\Local\conda\conda\envs\wav2lip\lib\site-packages\torchvision\models\_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead.
  warnings.warn(
C:\Users\liruilong\AppData\Local\conda\conda\envs\wav2lip\lib\site-packages\torchvision\models\_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=None`.
  warnings.warn(msg)
Downloading: "https://github.com/xinntao/facexlib/releases/download/v0.1.0/detection_Resnet50_Final.pth" to C:\Users\liruilong\AppData\Local\conda\conda\envs\wav2lip\lib\site-packages\facexlib\weights\detection_Resnet50_Final.pth

100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 104M/104M [00:06<00:00, 16.1MB/s]
Downloading: "https://github.com/xinntao/facexlib/releases/download/v0.2.2/parsing_parsenet.pth" to C:\Users\liruilong\AppData\Local\conda\conda\envs\wav2lip\lib\site-packages\facexlib\weights\parsing_parsenet.pth

100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 81.4M/81.4M [00:05<00:00, 14.8MB/s]
0it [00:00, ?it/s]
  warnings.warn(msg)
  0%|                                                                                                                                                                                  | 0/1793 [00:00<?, ?it/s]Processing 0000.jpg ...
  0%|                                                                                                                                                                        | 1/1793 [00:06<3:18:38,  6.65s/it]Processing 0001.jpg ...
  0%|| 2/1793 [00:13<3:18:06,  6.64s/it]P
...............................
(wav2lip) C:\Users\liruilong\Documents\GitHub\Wav2Lip-GFPGAN\GFPGAN-master>

OK 跑完之后,需要用处理的图片合成视频,执行下面的脚本



import os


outputPath = ".\\results"

restoredFramesPath = outputPath + '\\restored_imgs\\'
processedVideoOutputPath = outputPath

dir_list = os.listdir(restoredFramesPath)
dir_list.sort()

import cv2
import numpy as np

batch = 0
batchSize = 300
from tqdm import tqdm
for i in tqdm(range(0, len(dir_list), batchSize)):
  img_array = []
  start, end = i, i+batchSize
  print("processing ", start, end)
  for filename in  tqdm(dir_list[start:end]):
      filename = restoredFramesPath+filename;
      img = cv2.imread(filename)
      if img is None:
        continue
      height, width, layers = img.shape
      size = (width,height)
      img_array.append(img)


  out = cv2.VideoWriter(processedVideoOutputPath+'\\batch_'+str(batch).zfill(4)+'.avi',cv2.VideoWriter_fourcc(*'DIVX'), 30, size)
  batch = batch + 1
 
  for i in range(len(img_array)):
    out.write(img_array[i])
  out.release()

concatTextFilePath = outputPath + "\\concat.txt"
concatTextFile=open(concatTextFilePath,"w")
for ips in range(batch):
  concatTextFile.write("file batch_" + str(ips).zfill(4) + ".avi\n")
concatTextFile.close()

concatedVideoOutputPath = outputPath + "\\concated_output.avi"
print("concatedVideoOutputPath:",concatedVideoOutputPath)

finalProcessedOuputVideo = processedVideoOutputPath+'\\final_with_audio.avi'
print("finalProcessedOuputVideo:",finalProcessedOuputVideo)
# ffmpeg -y -f concat -i {concatTextFilePath} -c copy {concatedVideoOutputPath} 

#ffmpeg -y -i {concatedVideoOutputPath} -i {inputAudioPath} -map 0 -map 1:a -c:v copy -shortest {finalProcessedOuputVideo}

#from google.colab import files
#files.download(finalProcessedOuputVideo)

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>python day2.py
  0%|                                                                                                                                                                                     | 0/6 [00:00<?, ?it/s]processing  0 300

  0%|                                                                                                                                                                                   | 0/300 [00:00<?, ?it/s]
  4%|██████▏                                                                                                                                                                  | 11/300 [00:00<00:02, 107.59it/s]
  7%|███████████▊                                                                                                                                                             | 21/300 [00:00<00:02, 104.49it/s]
 11%|██████████████████
 ...................
 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 293/293 [00:02<00:00, 107.10it/s]
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 6/6 [00:25<00:00,  4.26s/it]
concatedVideoOutputPath: .\results\concated_output.avi
finalProcessedOuputVideo: .\results\final_with_audio.avi

(wav2lip) C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN>

使用 ffmpeg 合并视频

PS C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN> cd .\results\
PS C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN\results> ffmpeg -y -f concat -i .\concat.txt  -c copy .\concated_output.avi
.....................
frame= 1793 fps=0.0 q=-1.0 Lsize=   24625kB time=00:00:59.76 bitrate=3375.3kbits/s speed=1.76e+03x
video:24577kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.197566%
PS C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN\results> ls


    目录: C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN\results


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----          2023/6/9      7:25                frames
d-----          2023/6/9     11:03                restored_imgs
-a----          2023/6/9     11:42        4231050 batch_0000.avi
-a----          2023/6/9     11:42        4274254 batch_0001.avi
-a----          2023/6/9     11:42        4281898 batch_0002.avi
-a----          2023/6/9     11:42        4165970 batch_0003.avi
-a----          2023/6/9     11:42        4222324 batch_0004.avi
-a----          2023/6/9     11:42        4069836 batch_0005.avi
-a----          2023/6/9     11:42            126 concat.txt
-a----          2023/6/9     11:52       25216450 concated_output.avi
-a----          2023/6/9      7:22        7515594 result.mp4

使用 ffmpeg 合并视频和音频

PS C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN\results> ffmpeg -y -i .\concated_output.avi -i ..\inputs\demo_5_y.mp3  -map 0 -map 1:a -c:v copy -shortest  .\final_with_audio.avi
ffmpeg version git-2020-08-31-4a11a6f Copyright (c) 2000-2020 the FFmpeg developers
........
frame= 1793 fps=699 q=-1.0 Lsize=   25618kB time=00:00:59.76 bitrate=3511.2kbits/s speed=23.3x
video:24577kB audio:934kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.417315%
PS C:\Users\山河已无恙\Documents\GitHub\Wav2Lip-GFPGAN\results>

生成结果

https://www.bilibili.com/video/BV1914y1U7dH/

关于 Demo 和小伙伴分享到这里

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知,这是一个开源项目,如果你认可它,不要吝啬星星哦 😃


https://github.com/ajay-sainy/Wav2Lip-GFPGAN


© 2018-2023 liruilonger@gmail.com, All rights reserved. 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

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

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

相关文章

人工智能(pytorch)搭建模型10-pytorch搭建脉冲神经网络(SNN)实现及应用

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能(pytorch)搭建模型10-pytorch搭建脉冲神经网络&#xff08;SNN&#xff09;实现及应用&#xff0c;脉冲神经网络&#xff08;SNN&#xff09;是一种基于生物神经系统的神经网络模型&#xff0c;它通过模拟神…

ASP.NET Core Web API入门之二:Swagger详细使用

ASP.NET Core Web API入门之二&#xff1a;Swagger详细使用 一、引言二、Swagger的作用以及优点2.1 作用2.2 优点 三、API接口添加注释3.1 编辑项目文件3.2 修改 Startup.cs 文件的 ConfigureServices 方法3.3 修改浏览器的网页标题3.4 接口添加注释 四、运行后效果 一、引言 …

(六)矢量数据的空间分析——缓冲区分析

矢量数据的空间分析——缓冲区分析 目录 矢量数据的空间分析——缓冲区分析 1.基本概念1.1图解1.2缓冲距离1.2.1固定距离1.2.2由字段决定的距离 2.缓冲区的建立2.1操作步骤2.1.1点状要素建立缓冲区2.1.2面状要素建立缓冲区 缓冲区是一组或一类地图要素&#xff08;点、线、面&a…

1.Tocmcat部署

文章目录 Tomcat部署介绍部署Tomcat安装jdk安装Tomcat添加tomcat系统服务 Tomcat部署虚拟主机tomcat多实例部署 Tomcat部署 Tomcat安装部署虚拟主机配置Tomcat优化 介绍 免费的、开放源代码的Web应用服务器Apache软件基金会(Apache Software Foundation)Jakarta项目中的- -个…

华为OD机试真题B卷 JavaScript 实现【5键键盘的输出】,附详细解题思路

一、题目描述 有一个特殊的5键键盘&#xff0c;上面有a&#xff0c;ctrl-c&#xff0c;ctrl-x&#xff0c;ctrl-v&#xff0c;ctrl-a五个键。 a键在屏幕上输出一个字母a&#xff1b;ctrl-c将当前选择的字母复制到剪贴板&#xff1b;ctrl-x将当前选择的字母复制到剪贴板&#…

【算法系列之哈希表I】leetcode15. 三数之和

242.有效的字母异位词 力扣题目链接 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 **注意&#xff1a;**若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 输入: s "anagram", t "nag…

快来给你个人微信公众号认个证吧

欢迎关注「全栈工程师修炼指南」公众号 点击 &#x1f447; 下方卡片 即可关注我哟! 作者安全运维学习答疑交流群&#xff1a;请关注公众号回复【学习交流群】 今天我一改往日&#xff0c;不谈技术只谈谈关于个人公众号认证流程&#xff0c;突然感觉自己有点不务正业了&#xf…

go语言学习——9

文章目录 goroutine概念goroutine调度模型 channelchannel介绍定义/声明channelchannel的关闭channel遍历channel其他细节 goroutine 前言&#xff1a;统计1~90000000数字中&#xff0c;哪些是素数&#xff1f; 使用循环&#xff0c;很慢使用并发或者并行的方式&#xff0c;将任…

【数据结构】二叉树(二)

目录 一、二叉树链式结构及实现 1、二叉树的结构 2、二叉树的遍历 2.1 前序遍历 2.2 中序遍历 2.3 后序遍历 2.4 层序遍历 3、二叉树链式结构的实现 3.1 创建一个节点 3.2 二叉树节点个数 3.3 二叉树叶子节点个数 3.4 二叉树的高度 3.5 二叉树第k层节点个数 3.6 二叉树查找值…

数据库管理-第八十二期 EMCC升级教程(20230607)

数据库管理 2023-06-07 第八十二期 EMCC升级教程1 升级EMCC1.1 升级概览1.2 拷贝相关文件1.3 升级OPatch1.4 升级OMSPatcher1.5 升级WLS1.6 升级OMS 2 升级Agent2.1 升级概览2.2 拷贝相关文件2.3 安装或升级AgentPatcher2.4 升级agent 3 升级Oracle数据库ASH包总结 第八十二期 …

什么时候适合加一层?

加一层能解决问题&#xff1a; 为什么加一层能解决问题&#xff1f; 什么时候适合加一层&#xff1f; 销售说不吵的&#xff0c; 道路检测说没有超标。 业主就是睡不着。 吃瓜群众说你为啥买那边的房子。 销售说开发商骗他&#xff0c;他也是受害者。 结果没问题&#xff0…

CSS 样式语言 选择器

CSS介绍 层叠样式表&#xff0c;是一种样式表语言&#xff0c;用来描述HTML和XML文档的呈现。随着HTML的发展&#xff0c;为了满足页面设计者的要求&#xff0c;HTML添加了很多显示功能&#xff0c;但是随着这些功能的增加&#xff0c;使得HTML越来越杂乱&#xff0c;HTML 页面…

「企业安全架构」EA874:安全需求,愿景、原则和流程

安全需求愿景 在开始任何安全架构工作之前&#xff0c;定义安全需求是很重要的。这些需求应该受到业务上下文和通用需求远景文档的影响。下面是一个图表&#xff0c;它显示安全需求是企业信息安全体系结构中业务上下文的一部分。 图1 安全需求远景&#xff08;SRV&#xff09;有…

Android系统原理性问题分析 - 系统 Root 的实现原理

声明 在Android系统中经常会遇到一些系统原理性的问题&#xff0c;在此专栏中集中来讨论下。Android低版本时经常听说Root系统&#xff0c;随着Android版本的升高&#xff0c;提Root的人越来越少了。不过我在系统开发时也有客户提出为系统Root的需求&#xff0c;所以在这里分析…

【产品经理】用户增长方法论

在做用户增长为核心的产品运营推广前&#xff0c;我们应从几个方面入手——打造核心功能点、转化方式要清晰、用户反馈与转化、传播渠道要合适、建立病毒式传播规则。 2017年&#xff0c;以营销见长的可口可乐公司将设置了24年之久的首席营销官&#xff08;CMO&#xff09;撤销…

[Maven高级]->近万字文章带你深入了解Maven

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;JavaEE ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&…

已经安装高版本CUDA的条件下bitsandbytes发现低版本的CUDA SETUP: Detected CUDA version 100解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Zabbix 配置钉钉报警

如有错误&#xff0c;敬请谅解&#xff01; 此文章仅为本人学习笔记&#xff0c;仅供参考&#xff0c;如有冒犯&#xff0c;请联系作者删除&#xff01;&#xff01; 1. 创建服务群【手机钉钉】|【电脑钉钉】- 右上角【】-【发起群聊】-【选人建群】/选择不同的群类型创建&…

数据库信息速递 甲骨文与微软合作,在Azure上推出数据库服务

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

Linux搭建配置jdk开发环境

因为ZooKeeper、Hadoop和Spark等大数据应用的运行需要Java环境的支持&#xff0c;所以需要我们来安装配置一下jdk环境。 安装步骤如下&#xff1a; 下载JDK 访问Oracle官网下载Linux x64操作系统的JDK安装包jdk-8u161-linux-x64.tar.gz。 上传JDK安装包 通过SecureCRT远程连接…