卡通角色表情驱动系列一

前言

分析完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…

c#将像素转换为页面单位

转自&#xff1a;http://blog.csdn.net/zhuzhao/article/details/3553100 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Drawing…

世界坐标和页面坐标

在进行绘图时必须考虑这两种坐标。 世界坐标是整个区域的坐标&#xff0c;而页面坐标是可视区的坐标。这两种坐标是通过滚动条来体现出来的。 页面坐标的原点始终是窗口可视区的坐上角&#xff0c;世界坐标的原点始终不变&#xff0c;这两种坐标和VC中的屏幕坐标和客户坐标很…

常用坐标系统

1. 设备坐标系与屏幕坐标系设备坐标&#xff08;Device Coordinate&#xff09;又称为物理坐标&#xff08;Physical Coordinate&#xff09;&#xff0c;是指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标。设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对…

华为2014校园招聘的机试题目

华为2014校园招聘的机试题目和2013年的完全一样。 一、题目描述&#xff08;60分&#xff09;&#xff1a; 通过键盘输入一串小写字母(a~z)组成的字符串。请编写一个字符串过滤程序&#xff0c;若字符串中出现多个相同的字符&#xff0c;将非首次出现的字符过滤掉。 比如字符串…

C++ 命名空间

1. 什么是命名空间 在编程语言中&#xff0c;命名空间是一种特殊的作用域&#xff0c;它包含了处于该作用域中的所有标示符&#xff0c;而且其本身也是由标示符表示的。命名空间的使用目的是为了将逻辑相关的标示符限定在一起&#xff0c;组成相应的命名空间&#xff0c;可使整…

安装好hadoop集群后,报错如下n org.apache.hadoop.ipc.RemoteException(java.io.IOException): File /data/hadoop-roo

master错误&#xff1a; n org.apache.hadoop.ipc.RemoteException(java.io.IOException): File /data/hadoop-root-namenode-master.log._COPYING_ could only be replicated to 0 nodes instead of minReplication (1). There are 0 datanode(s) running and no node(s) ar…

hadoop学习1 java操作HDFS

1、创建目录 package hdfs.operation;import java.io.IOException;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;public class MakeDir {public static void main(String[] args) throws IOExceptio…

hadoop学习2 记录配置hadoop环境的那些坑

1、在你的学习阶段&#xff0c;记住先关闭防火墙。 centos&#xff1a; systemctl stop firewalled.service2、windows本地配置eclipse&#xff0c;远程调测阶段&#xff1a;第一&#xff1a; 还是先关闭防火墙第二&#xff1a; 本地配置文件位置放对第三&#xff1a; 配置的时…

hadoop学习3 查找块的位置

1、hadoop会以块的形式存储在HDFS系统。通过命令可以查看所在节点和块的位置&#xff1a; [rootmaster softpackage]# hadoop fs -put scala-2.10.4.tgz /[rootmaster softpackage]# hadoop fsck /scala-2.10.4.tgz -files -locations -blocksDEPRECATED: Use of this script …

hadoop学习4 调测错误备案

0、An internal error occurred during: "Map/Reduce location status updater". java.lang.NullPointerException解决方法&#xff1a; 关闭防火墙1、Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/yarn/util/Apps解决方…

hadoop学习5 搭建storm集群

参阅&#xff1a; http://www.cnblogs.com/freeweb/p/5179410.html 非常感谢 注意集群的启动顺序以及概念。 [rootmaster bin]# ./storm ui >> /dev/null & [4] 8076 [rootmaster bin]# jps 7930 nimbus 8076 core 3667 SecondaryNameNode 3480 NameNode 7626 Qu…

hadoop学习6 运行map reduce出错

1、一直处理running状态 2、 at com.sun.proxy.$Proxy14.submitApplication(Unknown Source) at org.apache.hadoop.yarn.client.api.impl.YarnClientImpl.submitApplication(YarnClientImpl.java:253) at org.apache.hadoop.mapred.ResourceMgrDelegate.submitApplication(Re…

kafka学习-环境搭建

1、几行命令 ./kafka-console-consumer.sh --zookeeper 192.168.86.133:2181,192.168.86.132:2181,192.168.86.134:2181 --topic shuaige --from-beginning ./kafka-console-producer.sh --broker-list 192.168.86.133:9092,192.168.86.132:9092,192.168.86.134:9092 --topic…

java基础之HashTable和HashMap的区别

1、类继承关系 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, java.io.Serializable …