卡通角色表情驱动系列一

前言

分析完ThreeDPoseTracker来做卡通角色的身体驱动,接下来在卡通驱动领域还有一个是表情驱动。对这个真的是一窍不通啊,只能慢慢看论文了。

国际惯例,参考博客/论文:

  • 《Landmark-guided deformation transfer of template facial expressions for automatic generation of avatar blendshapes》
  • 《FACSvatar: An Open Source Modular Framework for Real-Time FACS based Facial Animation》
  • 《Real-time Facial Animation for Untrained Users》
  • 《Modeling Facial Expressions in 3D Avatars from 2D Images》
  • 《Practice and Theory of Blendshape Facial Models》
  • 《Real-Time Facial Motion Capture System》
  • 《Semantic 3D Motion Retargeting for Facial Animation》
  • 《Learning Controls for Blend Shape Based Realistic Facial Animation》
  • 《Performance Driven Facial Animation using Blendshape Interpolation》
  • 《Expression Cloning Jun-yong》
  • 苹果的ARKit blendShapes
  • 如何在Maya流程下创建一整套面部绑定

简述

此块内容受知识限制,描述内容有限或者可能有误,所以大家有何见解可在评论区或者微信公众号私信我讨论。

从参考文献来看,表情驱动大致分为三种:

  • 网格形变/编辑(mesh deform)
    • 直接基于面部顶点进行网格形变,比如我之前的博客径向基函数RBF三维网格变形就是其中一种变形方法,但是在表情驱动中,不同论文也会提出各种不同的变形方法,使变形后的人脸表情更加自然,其核心就是变形算法,例如《Landmark-guided deformation transfer of template facial expressions for automatic generation of avatar blendshapes》、《Deformation transfer for triangle meshes》,可以将捕捉到的人脸网格重定向到一个数字人面部,同步他俩的动作。
    • 比如Blender 2.8 Facial motion capture tutorial利用关键点和blender自带的形变功能,此博客中要求人脸3D模型和人脸关键点保持一致(作者进行了人工绑定),所以无法用到卡通角色上;不过如果自己能找到人脸和其它卡通角色的面部捕捉点对应关系,同时也能建立一个真人面部关键点动作到虚拟角色对应关键点运动的映射关系(因为卡通角色和人脸角色的网格差距可能会很大),也可以做卡通角色的驱动。
  • 骨骼驱动。在面部创建骨骼,利用软件对面部肌肉和骨骼进行权重绑定,然后调整骨骼的时候,面部肌肉会根据绑定值自动计算面部顶点信息,此时不需要网格形变算法,直接基于权重重新计算人脸蒙皮。这个过程很接近人体蒙皮算法,后续应该会开一个博客解析如何将皮肤与骨骼绑定。
    • 比如B站的这个教程使用maya建立面部骨骼,然后做表情绑定的教程。
  • 使用blendshape融合变形;在美术领域,这个方法就是表情控制器的制作基础,每个表情控制器对应一套BS。关于详细可看苹果的ARKit blendShapes列出的BS类型,针对每个表情预先做好对应的面部模型,从无表情到有表情用一个0-1的系数即可控制每种表情的程度;人脸重建的基本方法3DMM就是基于BS的,核心在于如何获取当前人脸对应的BS系数。通常有两种方法
    • 一种是用最小二乘法求解,使得所有表情BS组合起来的人脸的关键点更加接近真实人脸提取的关键点。比如Realtime Facial Animation for Untrained User,StrongTrack
    • 用几何的方法直接算,比如Blender & OpenCV - Windows Guide - Facial Motion Capture,预先在做好了卡通角色的面部骨骼动画控制器,然后根据人脸关键点计算出五官变化,从而控制虚拟角色的表情。
    • 另一种是直接用深度学习去获取BS系数,但是非常受限于数据集,比如openface,具体应用为FACSvatar

还有直接用图像算法驱动表情的我就不说了,比如最近比较火的“蚂蚁雅黑”表情驱动就是基于first-order-model的,不想把它归到3D驱动中。

【注】上述方法不要区分太开,因为本质都是网格形变,只不过骨骼驱动是通过控制面部骨骼,利用预定义的(骨骼对面部影响)权重来自动计算对应表情的网格;BS也是用画刷结合权重,利用maya或者其它工具调整面部网格做出来的。所以要么是利用算法做网格变形实现驱动,要么预定义网格变形实现驱动。例如还是这个B站教程使用Maya工具节点绑定角色面部表情教程 - Rig a face using Maya’s Utility nodes,或者对应的图文解析如何在Maya流程下创建一整套面部绑定,就用骨骼驱动人脸,然后用blendshape实现微调,简单说就是“blendShapes的优势就是可以提供更精确的表情,而关节可以实现面部区域的拉伸,增加更多的表情灵活性”。因此每种方法都有自己优劣势,也可以结合使用,只不过常见代码中的做法基本都是基于BS来实现表情驱动的。

本文和接下来的系列博文,将先针对BS驱动,分析和抽取几个源码内容,来加深理解。

源码理论与实验分析

拿strongtrack的源码开刀,作者提供了效果视频,在油管上自己观看

【吐槽】本来想把视频转发到B站的,但是坑货B站把视频当做恐怖内容了,因为作者的视频只有头没有身体,就被当成恐怖镜头了,审核不通过。

准备工作

作者提供了一个人头BlendShape模型,关于Blender的模型可以去作者提供的谷歌网盘下载,也可以从我的百度云下载

链接:https://pan.baidu.com/s/15tlWmJ9grXw4eI6TiVC-Iw
提取码:871c

为了便于分析理论和BS的操作,我预先把所有的BS模型从Blender文件中导出来了,所有的BS可以在我的github上找到,作者做了50组BS,名字分别如下:

'eyeBlinkLeft', 'eyeBlinkRight', 'eyeSquintLeft', 'eyeSquintRight', 'eyeLookDownLeft', 'eyeLookDownRight', 'eyeLookInLeft', 
'eyeLookInRight', 'eyeWideLeft', 'eyeWideRight', 'eyeLookOutLeft', 'eyeLookOutRight', 'eyeLookUpLeft', 'eyeLookUpRight', 'browDownLeft', 'browDownRight', 
'browInnerUp', 'browOuterUpLeft', 'browOuterUpRight', 'jawOpen', 'mouthClose', 'jawLeft', 'jawRight', 'jawFwd',
'mouthUpperUpLeft', 'mouthUpperUpRight', 'mouthLowerDownLeft', 'mouthLowerDownRight', 'mouthRollUpper', 
'mouthRollLower', 'mouthSmileLeft', 'mouthSmileRight', 'mouthDimpleLeft','mouthDimpleRight', 'mouthStretchLeft', 
'mouthStretchRight', 'mouthFrownLeft', 'mouthFrownRight', 'mouthPressLeft', 'mouthPressRight', 'mouthPucker', 'mouthFunnel', 'mouthLeft','mouthRight',
'mouthShrugLower','mouthShrugUpper', 'noseSneerLeft', 'noseSneerRight', 'cheekPuff', 'cheekSquintLeft', 'cheekSquintRight'

至于每一组BS代表的表情,可以自行去Blender查看,或者用meshlab打开我导出的OBJ文件观看。

提前说一句,从代码里面可以发现,作者只用了其中10组表情基(BS),详细如下:

Basis, jawOpen, mouthSmile, mouthSmileLeft, mouthSmileRight, mouthFrown, mouthFunnel, mouthPucker, browInnerUp, browDown

源码流程

先大概介绍一下作者算法流程,在strongtrack.pyVideoThread函数中可以逐步分析

  • 先使用dlib获取人脸关键点,并且做了微调训练
  • 分别记录真人的10个关键姿态(与使用的BS对应),表情分别为:NeutralJaw Open, Closed Smile, Smile Left, Smile Right, Mouth Frown, Lip Funnel, Lip Pucker, Brows Up, Brows Down
  • 进入实时驱动阶段时候,核心在decomp_function.py文件中的findCoeffAll函数,其步骤为
    • 提取嘴部系数:因为与嘴巴相关的BS有八个,因此源码中先针对关键姿态和当前帧的嘴部关键点做中心对齐,然后使用稀疏编码求解系数
    • 提取眉毛系数:因为与眉毛相关的BS只有2个,而且一个向上,另一个向下,区分非常明显,所以可以直接计算,源码的方法是计算当前帧的眉毛中心相对于自然状态下眉毛中心的偏移量,分别除以两个BS相对于自然状态下眉毛中心的偏移量,就分别得到了眉毛两个BS的系数,然后对眉毛向下的情形做一下系数值的约束即可。
    • 提取眨眼系数:这个更简单了,以内外眼角平均坐标值为眼睛中心,上下眼框分别计算坐标中心,除一个指定的固定值即可。
  • 所有系数计算完毕以后,即可驱动模型表情

源码简化

上述的整个源码流程中,我最看好那个稀疏编码求解系数的过程,涨知识了。其它的都是利用几何关系计算,没什么技术含量。结果代码还写了好多好多,其中有很大一部分是写界面,介绍如何训练人脸关键点检测模型,以及利用OSC建立pythonblender的实时通信。

所以按照博客宗旨,我们仅分析系数计算这一块内容,跳过关键点检测模型的训练以及通信代码的书写。因此,在实验时候,10个真人表情对应的2D人脸关键点,我直接从对应BS中获取(去掉深度坐标轴),然后随便组合两组BS导出来,作为实时驱动时候的人脸关键点。

随后,在源码的基础上抽取了提取表情系数部分的代码,同时针对性修改和简化了一下:

  • 对齐关键点,嘴巴和眉毛是分开提取系数的,所以它们的位置是分开做中心对齐的,流程就是分别提取关键表情和当前帧中人脸对应部位关键点,然后根据脸宽缩放,最后按照中心坐标对齐

    '''
    将表情基的人脸关键点与当前表情关键点对齐
    可以用于处理局部关键点,源码中分别处理眼、嘴
    '''
    def shiftKeyPoses(new_width, centroid, keyposes, config):   #Scale keypose based on head width to accomodate for translation or different video size.width_keypose = (keyposes[0][67][0]-keyposes[0][51][0]) # 表情基中第一个姿态的人脸宽度width_fac = width_keypose/new_width # 表情基脸宽/真人脸宽keyposes = np.divide(keyposes, [width_fac,width_fac]).astype(int) # 依据比例系数,将所有表情基关键点缩放到真人面部大小new_poses = []for i in range(keyposes.shape[0]): # 遍历所有的表情基#For brows we take average of eyes pointsif config == 'brows': keypose = np.array(keyposes[i][10:22])#Fo mouth we take average of mouth pointsif config == 'mouth':keypose = np.array(keyposes[i][31:51])centroid_keypose = keypose.mean(0) #表情基中眉毛或者嘴部的中心delta = centroid_keypose-centroid # 表情基眉毛或嘴中心与真人眉毛或嘴中心的偏移量new_pose = keyposes[i]-delta.astype(int) # 利用中心偏移量 重新调整表情基的位置new_poses.append(new_pose) # 将新的表情基加入数组中返回return np.array(new_poses)
    
  • 嘴部BS系数直接使用sklearn中的SparseCoder函数进行求解,用法也很简单

    '''
    嘴部BS
    '''
    # 对齐keypose和真人嘴部关键点
    mouth_center = testpose[31:51].mean(0)
    shift_kps_mouth = shiftKeyPoses(width_points,mouth_center,keyposes_mouth,"mouth")
    # 重组嘴部坐标,便于计算
    target_mouth = testpose[31:51].reshape((1,-1))
    dict_2d_mouth = []
    for i in range(shift_kps_mouth.shape[0]):dict_2d_mouth.append(shift_kps_mouth[i][31:51])
    dict_2d_mouth = np.array(dict_2d_mouth).reshape(shift_kps_mouth.shape[0],-1)
    # 提取嘴部运动的系数
    coder = SparseCoder(dictionary=dict_2d_mouth.astype("float32"),transform_n_nonzero_coefs=None,transform_alpha=10,transform_algorithm='lasso_lars')
    coeffs = coder.transform(target_mouth.astype("float32"))
    
  • 计算左右眉毛的上下运动,计算方法上面说过,就是关键表情的关键点和当前帧关键点的眉毛相对于自然状态下眉毛的偏移比例

    # 计算眉毛
    def calBrow(points, keyposes, config, config2):# 眉毛姿态集中,分别有正常,眉毛上,眉毛下if config == 'left':first = 5last = 10if config == 'right':first = 0last = 5if config2 == "up":target = 1 # 眉毛上else:target = 2 # 眉毛下# 计算挑眉的keypose相对于自然表情下眉毛移动deltashifted = keyposes[target][first:last] - keyposes[0][first:last]deltashifted = (sum(sum(abs(deltashifted))))# 计算当前人脸相对于自然表情下眉毛移动deltapoints = (points[first:last]) - (keyposes[target][first:last])deltapoints = (sum(sum(abs(deltapoints))))# 直接相除,得到比例系数if deltapoints < (deltashifted):val = 1 - (deltapoints / deltashifted)else:val = 0.0# 如果是眉毛向下,可以用垂直比例来辅助计算,不然不准if(target==2):ydelt  = keypose[2][first:last] - points[first:last]ydelt = sum(ydelt.T[1])if(ydelt<=0):val = 1.0return val
    

    眉毛向下的时候可能有点难算,或者出问题,所以额外加了个约束:

    # 约束
    def constraint(val,lower,upper):factor = 1 / lowerif lower > val:new_val = 0.0if lower <= val < upper:new_val = (val - lower) * factorif val >= upper:new_val = 1.0return new_val
    

    调用时候如下:

    # 对齐眉毛关键点
    eye_center = testpose[10:22].mean(0)
    shift_kps_eye = shiftKeyPoses(width_points,eye_center,keyposes_brows,"brows")
    # 分别提取左右眉毛上下运动的系数
    val_l_up = calBrow(testpose,shift_kps_eye,"left","up")
    val_r_up = calBrow(testpose,shift_kps_eye,"right","up")
    val_l_down = constraint(calBrow(testpose,shift_kps_eye,"left","down"),0.4,0.8)
    val_r_down = constraint(calBrow(testpose,shift_kps_eye,"right","down"),0.4,0.8)
    
  • 眨眼这个过程就是计算上下眼眶个子的中心坐标以及整个眼眶中心坐标的关系,但是涉及到常量,这个常量应该是依据场景确定出来的,所以代码无法过于深究:

    #左眼
    eye_top_r = testpose[11:13].mean(0)
    eye_mid_r = testpose[[10,13]].mean(0)
    eye_bottom_r = testpose[14:16].mean(0)
    blink_r_coeff = (eye_top_r[1]-eye_mid_r[1]+28)/48
    squint_r_coeff = (eye_mid_r[1]-eye_bottom_r[1]+17)/7.5
    #右眼
    eye_top_l = testpose[17:19].mean(0)
    eye_mid_l = testpose[[16,19]].mean(0)
    eye_bottom_l = testpose[20:22].mean(0)
    blink_l_coeff = (eye_top_l[1]-eye_mid_l[1]+28)/48
    squint_l_coeff = (eye_mid_l[1]-eye_bottom_l[1]+17)/7.5
    

源码计算BS的核心就是上面了,有点技术含量的就是计算嘴部BS使用的稀疏编码。

验证稀疏编码和BS结果

针对感兴趣的部分做一次验证,必须少不了可视化。提取嘴部BS的理论和代码就不重复了。

为了验证结果,上面说过利用BS做了两个测试用的表情模型,对应关键点如下:

在这里插入图片描述

关于BS融合变形的原理,通常是基于偏移量来计算的,也就是常看到的一个公式
R=Base+∑iwiOiR = Base + \sum_i w_i O_i R=Base+iwiOi
其中OiO_iOi代表的是表情基相对于自然表情基的顶点偏移量
Oi=Bi−BaseO_i = B_i-Base Oi=BiBase
所以利用代码得到BS融合结果,需要先把每个表情基偏移量算出来:

# 获取BS偏移量
# 0:Neutral
basicVerts = getVerts('./data/Basis.obj')
# 1:Jaw Open
jawopenVerts = getVerts('./data/jawOpen.obj')
# 2:Closed Smile
closesmileVerts = getVerts('./data/mouthSmile.obj')
# 3:Smile Left
smileleftVerts = getVerts('./data/mouthSmileLeft.obj')
# 4:Smile Right
smilerightVerts = getVerts('./data/mouthSmileRight.obj')
# 5:Mouth Frown
mouthfrownVerts = getVerts('./data/mouthFrown.obj')
# 6:Lip Funnel
lipfunnelVerts = getVerts('./data/mouthFunnel.obj')
# 7:Lip Pucker
lippuckerVerts = getVerts('./data/mouthPucker.obj')offset = []
offset.append(basicVerts-basicVerts)
offset.append(jawopenVerts-basicVerts)
offset.append(closesmileVerts-basicVerts)
offset.append(smileleftVerts-basicVerts)
offset.append(smilerightVerts-basicVerts)
offset.append(mouthfrownVerts-basicVerts)
offset.append(lipfunnelVerts-basicVerts)
offset.append(lippuckerVerts-basicVerts)offset = np.array(offset,dtype="float32")

然后再去组合得到结果:

# 根据系数组合BS
newVert = basicVerts
for i in range(offset.shape[0]):newVert = newVert + coeffs[0,i]*offset[i]
writeResult(newVert)

把结果写入到OBJ并与测试表情模型做对比,结果如下:

在这里插入图片描述

可以发现上下表情几乎一模一样,所以验证成功,使用稀疏编码计算表情系数是可行的。

后记

稀疏编码看起来貌似是挺强大的,后续也可以尝试将整个表情关键点都用系数编码计算一下试试,不要手动计算了,虽然靠谱,但是有点low啊。

还有通常BS是被约束到(0,1)(0,1)(0,1)范围内的,这个库貌似无法保证最终表情系数在此范围,后续再继续探索一下。

完整的python实现放在微信公众号的简介中描述的github中,有兴趣可以去找找。同时文章也同步到微信公众号中,有疑问或者兴趣欢迎公众号私信。
在这里插入图片描述

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

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

相关文章

opencv相机标定和人头姿态估计案例

前言 头部驱动除了之前关注的表情驱动外&#xff0c;还有眼球驱动和头部方向驱动。本博客基于opencv官方文档和部分开源代码来研究如何基于人脸关键点获取头部的朝向。 国际惯例&#xff0c;参考博客&#xff1a; opencv:Camera Calibration and 3D Reconstruction opencv:…

卡通角色表情驱动系列二

前言 之前介绍了使用传统算法求解BS系数的表情驱动方法&#xff0c;其中提到过的三种方法之一是基于网格形变迁移做的&#xff0c;那么这篇文章就是对《Deformation Transfer for Triangle Meshes》做表情驱动的解析。 国际惯例&#xff0c;参考博客&#xff1a; 论文原文《…

UE自带重定向原理

UE自带重定向方法验证 核心源码在VS的解决方案中的位置&#xff1a; UE4\Source\Developer\AssetTools\Private\AssetTypeActions\AnimSequence.cpp中第3237行RemapTracksToNewSkeleton函数 跳转方法 AssetTypeActions_AnimationAsset.cpp的RetargetNonSkeletonAnimationHa…

【caffe-Windows】caffe+VS2013+Windows无GPU快速配置教程

前言 首先来一波地址&#xff1a; happynear大神的第三方caffe&#xff1a;http://blog.csdn.net/happynear/article/details/45372231 Neil Z大神的第三方caffe&#xff1a;https://initialneil.wordpress.com/2015/01/11/build-caffe-in-windows-with-visual-studio-2013-…

【caffe-Windows】caffe+VS2013+Windows+GPU配置+cifar使用

前言 国际惯例&#xff0c;先来波地址&#xff1a; CUDA WIN7&#xff1a;链接&#xff1a;http://pan.baidu.com/s/1nvyA3Qp 密码&#xff1a;h0f3 官方网址&#xff1a;https://developer.nvidia.com/cuda-toolkit CUDA WIN10:链接&#xff1a;http://pan.baidu.com/s/1…

【一些网站的收集】包含机器学习深度学习大牛主页等

数学概念部分 旋转矩阵、欧拉角、四元数的比较 欧拉角和四元数的表示 四元数与旋转 B样条曲线 非常好的概率统计学习的主页 误差方差偏差 编程语言学习 C#编程视频 OpenGL编程NeHe OpenGL官网 OpenGL“我叫MT“纯手工3D动画制作之1——基础介绍 【强大】非常好的Op…

Eureka源码分析

Eureka源码分析 Eureka server入口: Spring.factories PS: 意味着如果加载EurekaServerAutoConfiguration成功,需要 ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)需加载成功. 通过Bean注入了很多类 本质上, eureka-server包含很多事件: EurekaInstanceC…

matlab程序中,如何解决矢量长度必须相同的问题

主要原因就是画图的x和y长度不一样&#xff0c;我用一个例子说明。 问题代码&#xff1a; clear all;close all;clc;x 0 : 1: 9;y sin(x);n 2*length(x);yi interpft(y, n);xi 0 : 0.5 : 10;hold on ;plot(x, y ,ro);plot(xi, yi, b.-);plot(x, sin(x),m--);legend(原始…

matlab 功率谱分析函数psd用法

psd简介 PSD(power spectrum analysis)功率谱分析&#xff0c;PSD在给定频带上的积分计算信号在该频带上的平均功率。与均值-平方谱相反&#xff0c;这个光谱中的峰值并没有反映出给定频率的能量。 单边PSD包含了信号的总功率在频率间隔从DC到一半的奈奎斯特速率。双侧PSD包含…

linux tar (打包、压缩、解压)命令

打包程序&#xff1a;tar c: 创建文档t&#xff1a; 列出存档内容x&#xff1a;提取存档f&#xff1a; filename 要操作的文档名v&#xff1a;详细信息 一&#xff1a;打包 打包&#xff1a;是指把文件整合在一起&#xff0c;不压缩 1.将文件打包&#xff1a;tar cf a.tar…

虚拟机添加硬盘扩容

1.设置→添加→硬盘 2.选择磁盘类型 3.开启虚拟机 4.用ls 命令查看&#xff1a;ls /dev/sd* 5.最后就可以对sdb进行分区操作 这里好麻烦&#xff0c;等我有空&#xff0c;在补上&#xff01; . . .

利用matlab将三维数据画成三维立体图

首先先分析对象。将数据利用matlab画出图&#xff0c;最开始是导入数据&#xff0c;然后处理数据&#xff0c;最后将处理的数据画出来。 所以我将它分为三个步骤。 第一步&#xff1a;导入数据 如果是mat数据。可以直接load如果是txt数据。可以用txtread如果是excel数据。可…

世界坐标、相机坐标、图像坐标、像素坐标的原理、关系,并用matlab仿真

世界坐标、相机坐标、图像坐标、像素坐标的原理、关系&#xff0c;并用matlab仿真 照相机是日常生活中最常见的。它能把三维的空间图片等比例缩小投影在照片上&#xff0c;称为一个二维图像。 以下我们就讲一讲原理&#xff0c;并相应的进行matlab仿真。 在学之前&#xff0…

matlab 三维高程根据图片颜色给对应点赋予颜色

目录 1. 问题分析 2. 技术分析 3. 程序代码 4. 代码运行结果 1. 问题分析 日常工作尤其是测绘、地质、遥感行业&#xff0c;需要画DEM模型&#xff0c;并在这个模型的基础上&#xff0c;进行着色、渲染。比如&#xff0c;地质分析地面三维地表形变之时&#xff0c;需要根据D…

matlab 计算N天前(后)的日期

注意时间的格式&#xff1a;是字符串、数字还是日期&#xff1f; 下面是计算明天、今天、昨天的日期。 day1 datetime(datestr(now,yyyy-mm-dd))caldays(1)%tomorrowday0 datetime(datestr(now,yyyy-mm-dd))%todayday_1 datetime(datestr(now,yyyy-mm-dd))-caldays(1)%yest…

CAT arguments dimensions are not consistent.CAT参数的维度不一致。

错误实例&#xff1a; 在写符号矩阵的时候常常会出现下面错误&#xff1a; 错误&#xff1a;CAT arguments dimensions are not consistent. CAT参数的维度不一致。 举个栗子&#xff1a; clear; close all; clc; syms A_0 B_0 B C D E F G H ;T_3 [2*A_0 C-D*1i H G*1i;C…

传感器尺寸、像素、DPI分辨率、英寸、毫米的关系

虽然网上有很多这种资料&#xff0c;但是太过于复杂&#xff0c;每个人的说法都不一样&#xff0c;看的让人云里雾里的&#xff0c;我总结了一下&#xff0c;不知道对不对&#xff01; 1. 1英寸25.4mm 2. 传感器尺寸&#xff1a;传感器的尺寸是指传感器的大小&#xff0c;一般…

利用PS将n张图制作成动态GIF图

第一步&#xff1a;打开PS,导入图片&#xff0c;文件→脚本→将文件载入堆栈… 数据量大的话&#xff0c;就耐心等待一下。 第二步&#xff1a; 创建祯动画 如果没有这个&#xff0c;可以点击窗口→时间轴 如果祯排列顺序反了&#xff0c;这样 最后按照自己要求设置祯动画时间&…

matlab padarray函数详解

本文来自于matlab帮助页面&#xff0c;命令&#xff1a;help padarray 语法&#xff1a; B padarray(A,padsize) B padarray(A,padsize,padval) B padarray(A,padsize,padval,direction) gpuarrayB padarray(gpuarrayA,___) 描述&#xff1a; B padarray(A,padsize…

matlab 三维画图函数错误提示:数据维度必须一致

用三维画图软件经常会出现下面错误 以mesh(x,y,z)为例&#xff1a; 主要原因是因为没有注意Z数据格式&#xff0c;Z必须是矩阵形式。而且Z矩阵的m*n必须与y,x相关&#xff0c; mesh(X,Y,Z) 使用 Z 确定的颜色绘制线框网格&#xff0c;因此其颜色与曲面高度成比例。如果 X 和 …