插眼:2020/11/14 16:08 更新: 毛边处理 , 追踪物体使用插值运动代码
代码在后面
2020/11/14 13:07 插眼 :毛边处理 , 追踪物体使用插值运动需要处理
效果预览:
1080*673 显示
1920*1080 显示:
磨刀不误砍材工
1. 新建一个物体,挂载FaceUGUIPos脚本,会自动帮你添加KinectManager和FacetrackingManager脚本
2.Camera 设置为透视图
3. 场景预览图,我的分辨率是1080*1920
Gif图:
4.需要注意的是 我是以左上为(0,0)坐标计算的,所以你的锚点也应该是这样的
5.
6.FaceUGUIPos脚本设置
插眼:2020/11/14 16:08
更新: 毛边处理 , 追踪物体使用插值运动代码
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using UnityEngine;
using UnityEngine.UI;
namespace QFramework.Example
{
[RequireComponent(typeof(KinectManager))]
[RequireComponent(typeof(FacetrackingManager))]
public class FaceUGUIPos : MonoBehaviour
{
public Vector2 _vNewPos;
public RawImage UserTexRawImage; // 用户图显示
public Vector2 m_vUserTexRawImageSize = new Vector2(1080f, 673f); // 用户图显示大小
public RawImage m_FaceTrackRaw; // 覆盖脸部显示的图
public Vector2 m_vFaceTrackRawSize = new Vector2(100f, 100f); // 覆盖脸部显示的图 大小
public Vector2 m_vFaceRectDepthMinMax = new Vector2(170f, 1700f);
public float m_fSpeed = 20f; // 移动速度 防止抖动太厉害
private RectTransform m_FaceTrackRawRect;
private KinectManager _manager; // KinectManager
private FacetrackingManager _facetrackingManager;
// Start is called before the first frame update
private void Start()
{
_manager = KinectManager.Instance;
_facetrackingManager = FacetrackingManager.Instance;
// 以下参数需要在 面板上设置 重要的事说三遍
// 以下参数需要在 面板上设置 重要的事说三遍
// 以下参数需要在 面板上设置 重要的事说三遍
//_manager.computeUserMap = KinectManager.UserMapType.CutOutTexture;
//_manager.computeColorMap = true;
//_manager.maxTrackedUsers = 1;
//_facetrackingManager.foregroundCamera = Camera.main;
是否显示 脸部 方框
//_facetrackingManager.displayFaceRect = true;
//_facetrackingManager.faceTrackingTolerance = 0.1f;
_vNewPos = new Vector2();
m_FaceTrackRawRect = m_FaceTrackRaw.GetComponent<RectTransform>();
UserTexRawImage.GetComponent<RectTransform>().sizeDelta = m_vUserTexRawImageSize;
m_FaceTrackRaw.GetComponent<RectTransform>().sizeDelta = m_vFaceTrackRawSize;
InitGetBodyColorMat();
}
// Update is called once per frame
private void Update()
{
if (_manager && _manager.IsInitialized() && _manager.IsUserDetected())
{
//如果只需要扣人的身体原图 请 return,不要运行GetComicMat(),否则算法会延迟;
UserTexRawImage.texture = GetBodyColorMat();
// 未经过Opencv处理过的抠图
//UserTexRawImage.texture = _manager.GetUsersLblTex();
GetFacePos();
}
}
/// <summary>
/// Face坐标转换
/// </summary>
private void GetFacePos()
{
long item = _manager.GetPrimaryUserID();
// 追踪当前用户骨骼
if (_facetrackingManager.IsTrackingFace(item))
{
UnityEngine.Rect rect = _facetrackingManager.GetFaceColorRect(item);
Debug.Log(rect.x + " " + rect.y);
求出脸部中心坐标
//_vNewPos.x = rect.x + rect.width / 2;
//_vNewPos.y = rect.y + rect.height / 2;
// map映射 将 Kinect深度摄像头坐标和 彩色摄像头坐标映射
// 200f,1700f 要实际看你的rect.x到屏幕左右边缘的位置,1920是深度摄像头的分辨率.x
_vNewPos.x = ValueMap(rect.x, m_vFaceRectDepthMinMax.x, m_vFaceRectDepthMinMax.y, 0f, 1920f);
_vNewPos.y = rect.y;
Debug.Log(" -----------" + _vNewPos);
// kinect 彩色分辨率是1920*1080的, 1080 * 673 是你的显示的区域大小,自己更改
_vNewPos.x = (m_vUserTexRawImageSize.x * _vNewPos.x / 1920) + m_vFaceTrackRawSize.x / 2;
_vNewPos.y = -(m_vUserTexRawImageSize.y * rect.y / 1080) - m_vFaceTrackRawSize.y / 2;
//m_FaceTrackRawRect.anchoredPosition = _vNewPos;
m_FaceTrackRawRect.anchoredPosition = Vector2.Lerp(m_FaceTrackRawRect.anchoredPosition,
_vNewPos, m_fSpeed * Time.deltaTime);
// 需要追踪多物体的时候使用的示例
//if (GameObject.Find(item.ToString()) != null)
//{
// Transform tran = GameObject.Find(item.ToString()).transform;
// tran.localPosition = Vector3.Lerp(tran.localPosition,
// new Vector3(rect.x - 1020, 480 - rect.y, -1200f), speed * Time.deltaTime);
//}
}
}
private int kinectDepthWidth = 512;
private int kinectDepthHeight = 424;
private Mat rgbaMat;
private Mat lineMat2;
private Mat bodyColorMat;
public Texture2D BodyColorTex;
/// <summary>
/// 初始化OpenCV数据
/// </summary>
private void InitGetBodyColorMat()
{
rgbaMat = new Mat(kinectDepthHeight, kinectDepthWidth, CvType.CV_8UC4);
lineMat2 = new Mat(kinectDepthHeight, kinectDepthWidth, CvType.CV_8UC1);
bodyColorMat = new Mat(kinectDepthHeight, kinectDepthWidth, CvType.CV_8UC4);
BodyColorTex = new Texture2D(kinectDepthWidth, kinectDepthHeight, TextureFormat.RGBA32, false);
}
/// <summary>
/// 只显示人的颜色图
/// </summary>
/// <returns></returns>
private Texture2D GetBodyColorMat()
{
// bodyTexture 转 mat GetUsersClrTex(); GetUsersLblTex();
Utils.texture2DToMat(_manager.GetUsersLblTex(), rgbaMat);
// ----------------对深度图降噪-------------
Imgproc.medianBlur(rgbaMat, lineMat2, 13); // 中值过滤
Imgproc.Canny(lineMat2, lineMat2, 20, 120); // 线平滑
Core.bitwise_not(lineMat2, lineMat2); // 反转
for (int i = 0; i < lineMat2.cols(); i++)
{
for (int j = 0; j < lineMat2.rows(); j++)
{
//这个150是阈值,你可以自己定义来试试效果
if (lineMat2.get(j, i)[0] > 250)
{
// 根据 mask 图 对原图相应位置的点设置
rgbaMat.put(j, i, 255, 255, 255, 0);
}
}
}
rgbaMat.copyTo(bodyColorMat);
Utils.matToTexture2D(bodyColorMat, BodyColorTex);
return BodyColorTex;
}
/// <summary>
/// 在给定数据类型的限制内,将一个值从一个任意范围映射到另一个范围
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private float ValueMap(float input, float inputMin, float inputMax, float outputMin, float outputMax)
{
//通常,您可以使用以下公式将值input从一个范围[inputMin, inputMax]转换为另一个范围[outputMin, outputMax]:
float output;
// 因为 C# 的特性,所有要使用 Float数值 不然会给你整除掉
//output = (value - 200f) * ((1920f - 0f) / (1700f - 200f)) + 0f;
output = (input - inputMin) * ((outputMax - outputMin) / (inputMax - inputMin)) + outputMin;
return output;
}
}
}
2020/11/14 15:07 代码:
using UnityEngine;
using UnityEngine.UI;
namespace QFramework.Example
{
[RequireComponent(typeof(KinectManager))]
[RequireComponent(typeof(FacetrackingManager))]
public class FaceUGUIPos : MonoBehaviour
{
public Vector2 _vNewPos;
public RawImage UserTexRawImage; // 用户图显示
public Vector2 m_vUserTexRawImageSize = new Vector2(1080f, 673f); // 用户图显示大小
public RawImage m_FaceTrackRaw; // 覆盖脸部显示的图
public Vector2 m_vFaceTrackRawSize = new Vector2(100f, 100f); // 覆盖脸部显示的图 大小
public Vector2 m_vFaceRectDepthMinMax = new Vector2(170f, 1700f);
private KinectManager _manager; // KinectManager
private FacetrackingManager _facetrackingManager;
// Start is called before the first frame update
private void Start()
{
_manager = KinectManager.Instance;
_facetrackingManager = FacetrackingManager.Instance;
// 以下参数需要在 面板上设置 重要的事说三遍
// 以下参数需要在 面板上设置 重要的事说三遍
// 以下参数需要在 面板上设置 重要的事说三遍
//_manager.computeUserMap = KinectManager.UserMapType.CutOutTexture;
//_manager.computeColorMap = true;
//_manager.maxTrackedUsers = 1;
//_facetrackingManager.foregroundCamera = Camera.main;
是否显示 脸部 方框
//_facetrackingManager.displayFaceRect = true;
//_facetrackingManager.faceTrackingTolerance = 0.1f;
_vNewPos = new Vector2();
UserTexRawImage.GetComponent<RectTransform>().sizeDelta = m_vUserTexRawImageSize;
m_FaceTrackRaw.GetComponent<RectTransform>().sizeDelta = m_vFaceTrackRawSize;
}
// Update is called once per frame
private void Update()
{
UserTexRawImage.texture = _manager.GetUsersLblTex();
if (_manager && _manager.IsInitialized() && _manager.IsUserDetected())
{
long item = _manager.GetPrimaryUserID();
// 追踪当前用户骨骼
if (_facetrackingManager.IsTrackingFace(item))
{
Rect rect = _facetrackingManager.GetFaceColorRect(item);
Debug.Log(rect.x + " " + rect.y);
求出脸部中心坐标
//_vNewPos.x = rect.x + rect.width / 2;
//_vNewPos.y = rect.y + rect.height / 2;
// map映射 将 Kinect深度摄像头坐标和 彩色摄像头坐标映射
// 200f,1700f 要实际看你的rect.x到屏幕左右边缘的位置,1920是深度摄像头的分辨率.x
_vNewPos.x = ValueMap(rect.x, m_vFaceRectDepthMinMax.x, m_vFaceRectDepthMinMax.y, 0f, 1920f);
_vNewPos.y = rect.y;
Debug.Log(" -----------" + _vNewPos);
// kinect 彩色分辨率是1920*1080的, 1080 * 673 是你的显示的区域大小,自己更改
_vNewPos.x = (m_vUserTexRawImageSize.x * _vNewPos.x / 1920) + m_vFaceTrackRawSize.x / 2;
_vNewPos.y = -(m_vUserTexRawImageSize.y * rect.y / 1080) - m_vFaceTrackRawSize.y / 2;
m_FaceTrackRaw.GetComponent<RectTransform>().anchoredPosition = _vNewPos;
// 需要追踪多物体的时候使用的示例
//if (GameObject.Find(item.ToString()) != null)
//{
// Transform tran = GameObject.Find(item.ToString()).transform;
// tran.localPosition = Vector3.Lerp(tran.localPosition,
// new Vector3(rect.x - 1020, 480 - rect.y, -1200f), speed * Time.deltaTime);
//}
}
}
}
/// <summary>
/// 在给定数据类型的限制内,将一个值从一个任意范围映射到另一个范围
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private float ValueMap(float input, float inputMin, float inputMax, float outputMin, float outputMax)
{
//通常,您可以使用以下公式将值input从一个范围[inputMin, inputMax]转换为另一个范围[outputMin, outputMax]:
float output;
// 因为 C# 的特性,所有要使用 Float数值 不然会给你整除掉
//output = (value - 200f) * ((1920f - 0f) / (1700f - 200f)) + 0f;
output = (input - inputMin) * ((outputMax - outputMin) / (inputMax - inputMin)) + outputMin;
return output;
}
}
}