Python人脸识别图片视频
人脸识别技术发展现状及未来趋势
当前,随着人工智能、物联网等前沿技术的迅速发展,智能时代已悄然到来,"刷脸"逐渐成为了新的风潮。在人脸识别技术商业化应用领域不断扩张的趋势下,“刷脸”办事正愈发常见。
人脸识别,是基于人的脸部特征信息进行身份识别的一种生物识别技术。用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪人脸,进而对检测到的人脸进行脸部识别的一系列相关技术,通常也叫做人像识别、面部识别。
。
一、人脸识别技术发展背景
人脸识别,是基于人的脸部特征信息进行身份识别的一种生物识别技术。除了安防、金融这两大领域外,人脸识别还在交通、教育、医疗、警务、电子商务等诸多场景实现了广泛应用,且呈现出显著应用价值。为了进一步把握人脸识别技术所带来的重大机遇,我国出台了一系列政策予以支撑。
二、人脸识别技术发展历程
人脸识别最初在20世纪60年代已经有研究人员开始研究,真正进入初级的应用阶段是在90年代后期,发展至今其技术成熟度已经达到较高的程度。整个发展过程可以分为机械识别、半自动化识别、非接触式识别及互联网应用阶段。
与其他生物识别方式相比,人脸识别优势在于自然性、不被察觉性等特点。自然性即该识别方式同人类进行个体识别时所利用的生物特征相同。指纹识别、虹膜识别等均不具有自然性。不被察觉的特点使该识别方法不易使人抵触,而指纹识别或虹膜识别需利用电子压力传感器或红外线采集指纹、虹膜图像,在采集过程中体验感不佳。目前人脸识别需要解决的难题是在不同场景、脸部遮挡等应用时如何保证识别率。此外,隐私性和安全性也是值得考虑的问题。人脸识别优势明显,未来将成为识别主导技术。具体来说,相比指纹识别、虹膜识别等传统的生物识别方式,优点主要还集中在四点:非接触性、非侵扰性、硬件基础完善和采集快捷便利,可拓展性好。在复杂环境下,人脸识别精度问题得到解决后,预计人脸识别有望快速替代指纹识别成为市场大规模应用的主流识别技术。
import argparse
import os
import re
import sys
import urllib
import json
import socket
import urllib.request
import urllib.parse
import urllib.error
# 设置超时
import timetime_sleep = 0.1def handle_baidu_cookie(original_cookie, cookies):""":param string original_cookie::param list cookies::return string:"""if not cookies:return original_cookieresult = original_cookiefor cookie in cookies:result += cookie.split(';')[0] + ';'result.rstrip(';')return resultdef get_suffix(name):m = re.search(r'\.[^\.]*$', name)if m.group(0) and len(m.group(0)) <= 5:return m.group(0)else:return '.jpg'# 保存图片
def save_image(rsp_data, word, max_count):if not os.path.exists("./" + word):os.mkdir("./" + word)# 判断名字是否重复,获取图片长度counter = len(os.listdir('./' + word)) + 1for image_info in rsp_data['data']:try:if 'replaceUrl' not in image_info or len(image_info['replaceUrl']) < 1:continueobj_url = image_info['replaceUrl'][0]['ObjUrl']thumb_url = image_info['thumbURL']url = 'https://image.baidu.com/search/down?tn=download&ipn=dwnl&word=download&ie=utf8&fr=result&url=%s&thumburl=%s' % (urllib.parse.quote(obj_url), urllib.parse.quote(thumb_url))time.sleep(time_sleep)suffix = get_suffix(obj_url)# 指定UA和referrer,减少403opener = urllib.request.build_opener()opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'),]urllib.request.install_opener(opener)# 保存图片filepath = './%s/%s' % (word, str(counter) + str(suffix))urllib.request.urlretrieve(url, filepath)if os.path.getsize(filepath) < 5:print("下载到了空文件,跳过!")os.unlink(filepath)continueexcept urllib.error.HTTPError as urllib_err:print(urllib_err)continueexcept Exception as err:time.sleep(1)print(err)print("产生未知错误,放弃保存")continueelse:print("图片下载成功,已有" + str(counter) + "张图片")if counter == max_count:returncounter += 1returndef pic_num(file_path):return len(os.listdir(file_path))def request_json_str(request_url):try:user_headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0', 'Cookie': ''}req = urllib.request.Request(url=request_url, headers=user_headers)page = urllib.request.urlopen(req)user_headers['Cookie'] = handle_baidu_cookie(user_headers['Cookie'], page.info().get_all('Set-Cookie'))rsp = page.read()page.close()except UnicodeDecodeError as e:print(e)print('-----UnicodeDecodeErrorurl:', single_page_url)except urllib.error.URLError as e:print(e)print("-----urlErrorurl:", single_page_url)except socket.timeout as e:print(e)print("-----socket timout:", single_page_url)else:return rspdef decode_json(json_source):try:json_data = json.loads(json_source, strict=False)except json.decoder.JSONDecodeError:try:source_replace = str(json_source.decode(encoding='utf8')).replace('\\', '\\\\')json_data = json.loads(source_replace, strict=False)except json.decoder.JSONDecodeError:return Nonereturn json_datadef download_single_page(word, page_url, max_pic_num):print("开始下载" + page_url + "中的数据")max_err_num = 5err_count = 0rsp = request_json_str(page_url)rsp_data = decode_json(rsp)while(rsp_data == None or 'data' not in rsp_data):if rsp_data == None:print("JSON字符串错误,尝试重试")err_count += 1else:print("触发反爬机制,正在重试\r", end='')if err_count > max_err_num:print("JSON错误次数超过", max_err_num, "次,跳过该页")returnrsp = request_json_str(page_url)rsp_data = decode_json(rsp)save_image(rsp_data, word, max_pic_num)print("该页下载完成")def get_image(word, max_pic_num):os.mkdir('./' + word)start_page = 1per_page = 30start_amount = (start_page - 1) * per_pagesearch = urllib.parse.quote(word)pn = start_amountwhile pic_num('./' + word) < max_pic_num:single_page_url = 'https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=%s&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=&hd=&latest=©right=&word=%s&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=%s&rn=%d&gsm=1e&1594447993172=' % (search, search, str(pn), per_page)time.sleep(time_sleep)download_single_page(word, single_page_url, max_pic_num)pn += per_pageprint("下载任务结束")return#删除原文件夹
def del_file(path):list1 = os.listdir(path)for i in list1:c_path = os.path.join(path, i)if os.path.isdir(c_path):del_file(c_path)else:os.remove(c_path)# print(path,"已被删除")#爬图片
import os
image_name="美女"
image_count=10
if(os.path.exists(r'/home/aistudio/%s'%(image_name))):del_file(r'/home/aistudio/%s'%(image_name))os.rmdir(r'/home/aistudio/%s'%(image_name))if(os.path.exists(r'/home/aistudio/output')):del_file(r'/home/aistudio/output')os.rmdir(r'/home/aistudio/output')os.mkdir("output")print("已创建文件夹output")
else:os.mkdir("output")print("已创建文件夹output")get_image(image_name,image_count)
# 安装PaddleHub
!pip install paddlehub==1.8.0
检测人脸
%matplotlib inline
# 导入所需要使用的包
import cv2
import paddlehub as hub
from matplotlib import pyplot as plt# 加载Paddlehub人脸检测模型
face_detector = hub.Module(name="pyramidbox_lite_mobile")def renlian(path1,path2,image_count_i): #原始图片 检测后的图片 图片数量# 使用模型进行图片预测result = face_detector.face_detection(paths=[r'%s/%s.jpg'%(path1,image_count_i)], use_gpu=False, visualization=True, output_dir='/home/aistudio/output',confs_threshold=0.5)# 打印检测结果# print(result)# 显示可视化图片output = cv2.imread(r'%s/%s.jpg'%(path2,image_count_i))output = output[:,:,::-1]plt.imshow(output)plt.show()
显示图片
path1 = r'/home/aistudio/%s'%(image_name)
path2 = r'/home/aistudio/output'list1 = os.listdir(path1)
list2 = os.listdir(path2)for i in range(1,image_count+1):renlian(path1,path2,i)
结果展示(一)共10例(由于太长,这里只展示两例)
修改部分代码
#爬图片
import os
image_name="鞠婧祎"
image_count=10get_image(image_name,image_count)path1 = r'/home/aistudio/%s'%(image_name)
path2 = r'/home/aistudio/output'list1 = os.listdir(path1)
list2 = os.listdir(path2)for i in range(1,image_count+1):renlian(path1,path2,i)
结果展示2(由于太长,这里只展示三例)
更换原图片
缺陷
- 部分人脸无法识别出来
- 动物的脸也会被识别出来
- 多人无法识别出来
更换算法
代码
import matplotlib.pyplot as plt
import matplotlib.image as mpimg # 展示待预测图片path = '/home/aistudio/picture'
test_img_path = os.listdir(path)
print(test_img_path)
for i in test_img_path:if i[0] =='.': test_img_path.remove(i)test_img_path.sort()#排序
print('test_img_path:',test_img_path)# 待预测图片
test_img_path_s = ["/home/aistudio/picture/01.jpg","/home/aistudio/picture/02.jpg","/home/aistudio/picture/03.jpg",]test_img_path_s=[]
for i in test_img_path:test_img_path_s.append(path+'/'+i)print('test_img_path_s:',test_img_path_s)for i in test_img_path_s:img = mpimg.imread(i) plt.figure(figsize=(10,10))plt.imshow(img) plt.axis('off') plt.show()
说明:
利用Ultra-Light-Fast-Generic-Face-Detector-1MB完成对该文件的人脸检测,只需读入该文件,将文件内容存成list,list中每个元素是待预测图片的存放路径。
ultra_light_fast_generic_face_detector_1mb_320,在预测时会将图片输入缩放为320 * 240,预测速度更快。
ultra_light_fast_generic_face_detector_1mb_640,在预测时会将图片输入缩放为640 * 480,预测精度更高。
准备
import paddlehub as hubmodule = hub.Module(name="ultra_light_fast_generic_face_detector_1mb_640")
#module = hub.Moudle(name="ultra_light_fast_generic_face_detector_1mb_320")
接下来
def cpdd(img_name):img=[r'/home/aistudio/picture/%s'%(img_name)]print(img)# 多张脸单图片处理input_dict = {"image": img}# 预测结果展示results = module.face_detection(data=input_dict)for result in results:res1 = result['data']# print(res1)#绘制矩形并显示img = mpimg.imread(img[0]) for i in range(len(res1)):img = cv2.rectangle(img,(int(res1[i]['left']),int(res1[i]['top'])),(int(res1[i]['right']),int(res1[i]['bottom'])),(0,255,0),3)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)cv2.imwrite(r"/home/aistudio/output2/%s"%(img_name),img)plt.figure(figsize=(10,10))img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)plt.imshow(img)plt.axis('off') plt.show()def cpdds(test_img_path):if(os.path.exists(r'/home/aistudio/output2')):del_file(r'/home/aistudio/output2')os.rmdir(r'/home/aistudio/output2')os.mkdir("output2")print("已创建文件夹 output2")else:os.mkdir("output2")print("已创建文件夹 output2")for i in test_img_path:cpdd(i)cpdds(test_img_path)
输出:
已创建文件夹 output2
['/home/aistudio/picture/01.jpg']
['/home/aistudio/picture/02.jpg']
['/home/aistudio/picture/03.jpg']
应用1(以人脸替换为例)
检测到人脸可以戴上口罩、戴上眼镜、打马赛克等,以下为人脸替换示例
替换使用图片:
代码
对之前的代码进行小幅度修改
def cpdd(img_name,TF=False): #TF表示是否遮挡img=[r'/home/aistudio/picture/%s'%(img_name)]print(img)img_0=img# 多张脸单图片处理input_dict = {"image": img}# 预测结果展示results = module.face_detection(data=input_dict)for result in results:res = result['data']# print('res=',res)# print(type(res))#绘制矩形并显示img = mpimg.imread(img[0]) for i in range(len(res)):img = cv2.rectangle(img,(int(res[i]['left']),int(res[i]['top'])),(int(res[i]['right']),int(res[i]['bottom'])),(0,255,0),3)img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)cv2.imwrite(r"/home/aistudio/output2/%s"%(img_name),img)plt.figure(figsize=(10,10))img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)plt.imshow(img)plt.axis('off') plt.show()if(TF):z_cpdds(img_0,'/home/aistudio/mask.jpg',res)def cpdds(test_img_path,TF=False):if(os.path.exists(r'/home/aistudio/output2')):del_file(r'/home/aistudio/output2')os.rmdir(r'/home/aistudio/output2')os.mkdir("output2")print("已创建文件夹 output2")else:os.mkdir("output2")print("已创建文件夹 output2")for i in test_img_path:cpdd(i,TF)
增加一个新的函数
def z_cpdds(cpNB,cpTNB,res_list):print('cpNB,cpTNB=',cpNB,cpTNB)#被遮挡的图片路径(列表) #用来遮挡的图片路径#遮挡from PIL import Imageimport numpy as np #img = mpimg.imread(cpNB[0])img = cv2.imread(cpNB[0])for res in res_list:shape = (int(res['right']-res['left']),int(res['bottom']-res['top']))#人脸区域大小image = Image.open(cpTNB).resize(shape) #用来遮挡的图片face = img[int(res['top'])+10:int(res['top'])+image.size[1]+10, int(res['left'])+5:int(res['left'])+image.size[0]+5]#整体右下移动#print(image.size)#宽高#print(face.shape)#高宽# 图片加权合成scope_map = np.array(image)[:,:,-1] / 255scope_map = scope_map[:,:,np.newaxis]scope_map = np.repeat(scope_map, repeats=3, axis=2)res_image = np.multiply(scope_map, np.array(image)[:,:,:3]) + np.multiply((1-scope_map), np.array(face))img[int(res['top']):int(res['top'])+image.size[1], int(res['left']):int(res['left'])+image.size[0]] = np.uint8(image)[:, : , ::-1]plt.figure(figsize=(10,10))img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)plt.imshow(img)plt.axis('off') plt.show()
运行代码展示结果:
['01.jpg', '02.jpg', '03.jpg']
已创建文件夹 output2
['/home/aistudio/picture/01.jpg']
cpNB,cpTNB=
['/home/aistudio/picture/01.jpg']
/home/aistudio/mask.jpg
['/home/aistudio/picture/02.jpg']
cpNB,cpTNB=
['/home/aistudio/picture/02.jpg']
/home/aistudio/mask.jpg
['/home/aistudio/picture/03.jpg']
cpNB,cpTNB=
['/home/aistudio/picture/03.jpg']
/home/aistudio/mask.jpg
应用2(统计视频中人脸数)
使用的视频
视频1
代码
首先
!pip install paddlehub==1.8.0import cv2
import os
import numpy as np
import paddlehub as hub
函数(视频输出为图片->人脸检测->图片合成为视频)
def CutVideo2Image(video_path, img_path):#将视频输出为图像print('将视频输出为图像中')#video_path为输入视频文件路径#img_path为输出图像文件夹路径cap = cv2.VideoCapture(video_path)index = 0while(True):ret,frame = cap.read() if ret:cv2.imwrite(img_path+'/%d.jpg'%index, frame)index += 1else:breakcap.release()print('输出图像%d张'%(index))print('视频输出为图像完毕')def Iou(bbox1,bbox2):#计算Iou#bbox1,bbox为xyxy数据area1 = (bbox1[2]-bbox1[0])*(bbox1[3]-bbox1[1])area2 = (bbox2[2]-bbox2[0])*(bbox2[3]-bbox2[1])w = min(bbox1[3],bbox2[3])-max(bbox1[1],bbox2[1])h = min(bbox1[2],bbox2[2])-max(bbox1[0],bbox2[0])if w<=0 or h<=0:return 0area_mid = w*hreturn area_mid/(area1+area2-area_mid)def GetFace(in_path, out_path):#人脸检测,并计算通过的人数print('人脸检测中')#in_path为输入图像文件夹的路径#out_path为输出图像文件夹的路径,并为人脸标注检测框和进行计数files = os.listdir(in_path)face_detector = hub.Module(name="pyramidbox_lite_server")bbox_buffer = []count = 0 #统计人数for i in range(len(files)):#文件中的每张图片img = cv2.imread(in_path+'/%d.jpg' % i)result = face_detector.face_detection(images=[img])data = result[0]['data']bbox_upgrade = []index = []for j in range(len(data)):#图片中的每个bboxleft, right = int(data[j]['left']), int(data[j]['right'])top, bottom = int(data[j]['top']), int(data[j]['bottom'])bbox = (left, top, right, bottom)if right>1600 and left<1600:count = count+1for k in range(len(bbox_buffer)):if Iou(bbox, bbox_buffer[k])>0.1 and k not in index:count = count-1index.append(k)breakbbox_upgrade.append(bbox)cv2.rectangle(img, (left, top), (right, bottom), (0, 0, 255), 3)else: cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3)bbox_buffer = bbox_upgrade.copy()cv2.putText(img,'count=%d'%count,(50,900),cv2.FONT_HERSHEY_COMPLEX,6,(0,0,255),10)cv2.imwrite(out_path+'/%d.jpg'%i, img)print('人脸检测完毕,共%d张'%(count))def CombVideo(in_path, out_path, size):#将图片合成视频print('将图片合成视频中')#in_path为输入图像文件夹路径#out_path为输出视频文件路径fourcc = cv2.VideoWriter_fourcc(*'mp4v')out = cv2.VideoWriter(out_path,fourcc, 30.0, size)files = os.listdir(in_path)for i in range(len(files)):img = cv2.imread(in_path + '/%d.jpg' % i)#img = cv2.resize(img, size)out.write(img)out.release()print('图片合成视频完毕')
其它函数
#删除文件夹内的文件和文件夹
def del_file(path):list1 = os.listdir(path)for i in list1:c_path = os.path.join(path, i)if os.path.isdir(c_path):del_file(c_path)else:os.remove(c_path)print(path,"已被删除")#清空文件夹(不存在则创建)
def clear_path(out_path):if(os.path.exists(out_path)): #如果该文件夹存在del_file(out_path) #删除文件夹内的文件和文件夹os.rmdir(out_path) #删除文件夹os.mkdir(out_path) #创建文件夹else:os.mkdir(out_path)print("已清空文件夹",out_path)
main函数
clear_path('/home/aistudio/images_initial')
clear_path('/home/aistudio/images_face')if __name__ == '__main__':video_initial = '/home/aistudio/抖音素材.mp4'video_finish = '/home/aistudio/视频.mp4'images_initial = '/home/aistudio/images_initial'images_face = '/home/aistudio/images_face'CutVideo2Image(video_initial, images_initial)GetFace(images_initial, images_face)CombVideo(images_face, video_finish,(1920,1080))
不足之处
- 在人流过大时,会出现部分人群挡住另一部分的人群,导致一些图片小部分人未被检测到
- 当人流中若有小部分人移动速度过快(如慢跑)会导致计算的IOU过小,以致于让模型误判该图像的人与下一帧图像的人不是同一人
- 人脸检测后的视频丢失了音频
改进方案
- 在人脸检测的基础上再增加人脸识别的功能,则视频中出现的人则可以记录下来
- 采用多角度拍摄,可以避免拍摄的死角
解决丢失音频的问题
代码1(从原视频中提取音频)
会生成一个“抖音素材.mp4.mp3”的文件
!pip install ffmpeg moviepyimport moviepy.editor as mp
def extract_audio(videos_file_path):my_clip = mp.VideoFileClip(videos_file_path)my_clip.audio.write_audiofile(f'{videos_file_path}.mp3')extract_audio(r'/home/aistudio/抖音素材.mp4')
代码2(从原视频中提取音频并)
from moviepy import *
from moviepy.editor import *
import globvideo_dirs = glob.glob('/home/aistudio/视频.mp4')
audio = AudioFileClip("/home/aistudio/抖音素材.mp4.mp3")# 提取音轨
for video_dir in video_dirs:video = VideoFileClip(video_dir)# 读入视频video = video.set_audio(audio)# 将音轨合成到视频中 video.write_videofile("/home/aistudio/将音轨合成到视频中/" + video_dir.split("/")[-1])# 输出
最终结果(代码2生成的视频)
视频3
Python人脸识别图片视频相关推荐
- 【优秀课设】基于OpenCV的Python人脸识别、检测、框选(遍历目录下所有照片依次识别 视频随时标注)
基于OpenCV的Python人脸识别.检测.框选 (遍历目录下所有照片依次识别 视频随时标注) 移步: https://blog.csdn.net/weixin_53403301/article/d ...
- Java + opencv 实现人脸识别,图片人脸识别、视频人脸识别、摄像头实时人脸识别
搭建环境 opencv官网下载windows安装包 https://opencv.org/releases/ 选择最新版4.1.1 下载完成后是一个opencv-4.1.1-vc14_vc15.exe ...
- Python人脸识别——从入门到工程实践
参考书籍:<Python人脸识别从入门到工程实践> 全书共8章: 第 1 章:介绍了人脸识别的基础知识和必备常识: 第 2~4 章:详细讲解了与人脸识别相关的数学.机器学习.计算机视觉.O ...
- Python | 人脸识别系统 — 活体检测
本博客为人脸识别系统的活体检测代码解释 人脸识别系统博客汇总:人脸识别系统-博客索引 项目GitHub地址:Su-Face-Recognition: A face recognition for us ...
- python人工智能图像识别_人工智能之Python人脸识别技术,人人都能做识别!
原标题:人工智能之Python人脸识别技术,人人都能做识别! 作者丨Python小哥哥 https://www.jianshu.com/p/dce1498ef0ee 一.环境搭建 1.系统环境 Ubu ...
- python人脸识别、语音合成、智能签到系统
基于python+face_recognition+opencv+pyqt5+百度AI实现的人脸识别.语音播报.语音合成.模拟签到系统(1) 人脸识别效果图 源码看最下面 这是新版本地址人脸识别.语音 ...
- python人脸识别、语音合成、智能签到系统(2)
基于python+face_recognition+opencv+pyqt5+百度AI实现的人脸识别.语音播报.语音合成.模拟签到系统(2) 人脸识别效果图 简单介绍以及需要的配置在 python人脸 ...
- 人脸图像识别(python人脸识别技术)
python人脸识别 人脸识别的崛起 什么是人脸识别 人脸识别技术的应用和发展 python人脸识别 导入库 实现代码 人脸识别的崛起 什么是人脸识别 人脸识别是将采集到的数据信息,根据人脸特征信息进 ...
- python人脸识别考勤系统 dlib+OpenCV和Pyqt5、数据库sqlite 人脸识别系统 计算机 毕业设计 源码
一.项目介绍 Python语言.dlib.OpenCV.Pyqt5界面设计.sqlite3数据库 本系统使用dlib作为人脸识别工具,dlib提供一个方法可将人脸图片数据映射到128维度的空间向量,如 ...
最新文章
- GitHub标星近1万:只需5秒音源,这个网络就能实时“克隆”你的声音
- C#中base关键字的几种用法
- 熵是什么?熵的公式是什么?决策树如何把熵的递减变换为信息增益进行树枝的分叉以及树的生长的?
- [PHP] 现代化PHP之路:composer的镜像站设置
- Android--获取当前系统时间
- 在.Net Core WebAPI下给Swagger增加导出离线文档功能
- 图形工具包 linux,GTK 4.0图形工具包正式发布:时隔四年的重大版本!
- Scrapy爬虫报错AttributeError: ‘NoneType‘ object has no attribute ‘write‘
- 如何通过 Web 实现防御木马、病毒...... | 原力计划
- simpana oracle,华为认证云运维专家(HCIE-CDO)
- sql2005安装图解
- Pyqt QThread
- 瀚高数据库迁移工具常见问题
- SWUST OJ 480: Locker doors
- c语言 教学设计,C语言教案
- 《跃迁-成为高手的技术》读书笔记
- 元宇宙研讨会-空间设计与交互技术构造的叙事世界
- paip 刮刮卡砸金蛋抽奖概率算法跟核心流程
- 计算机自带录音机格式,Windows自带录音机
- ReactJS :我就是想把代码和HTML混在一起!