因为项目中需要完成对手部的摄像头识别,识别过程中,需要将指尖识别为五个点,并且映射到VR环境中去。需要对摄像头欧拍到的内容进行图像处理。
主要用到的方法是 grabCut方法。
GrabCut函数说明
void grabCut(InputArray img, InputOutputArray mask, Rect rect, InputOutputArraybgdModel, InputOutputArrayfgdModel, intiterCount, intmode=GC_EVAL)
Parameters: |
|
---|
函数原型:
void cv::grabCut( const Mat& img, Mat& mask, Rect rect,
Mat& bgdModel, Mat& fgdModel,
int iterCount, int mode )
其中:
img——待分割的源图像,必须是8位3通道(CV_8UC3)图像,在处理的过程中不会被修改;
mask——掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果。mask只能取以下四种值:
GCD_BGD(=0),背景;
GCD_FGD(=1),前景;
GCD_PR_BGD(=2),可能的背景;
GCD_PR_FGD(=3),可能的前景。
如果没有手工标记GCD_BGD或者GCD_FGD,那么结果只会有GCD_PR_BGD或GCD_PR_FGD;
rect——用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;
bgdModel——背景模型,如果为null,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
fgdModel——前景模型,如果为null,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
iterCount——迭代次数,必须大于0;
mode——用于指示grabCut函数进行什么操作,可选的值有:
GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut;
GC_INIT_WITH_MASK(=1),用掩码图像初始化GrabCut;
GC_EVAL(=2),执行分割。
具体代码:
- using UnityEngine;
- using OpenCVForUnity;
- public class TextureCutOut : MonoBehaviour {
- private Mat image ;
- private Mat mask, binMask, dstMat;
- private OpenCVForUnity.Rect rect;
- private Mat bgModel, fgModel;
- byte[] maskPixels;
- // Use this for initialization
- void Start () {
- Texture2D inputTexture = Resources.Load("inputTexture") as Texture2D;
- image = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC3);
- Utils.texture2DToMat(inputTexture, image);
- mask = new Mat(inputTexture.height, inputTexture.width, CvType.CV_8UC1);
- mask.setTo(new Scalar(Imgproc.GC_BGD));
- rect = new OpenCVForUnity.Rect(45,25, 175, 210);
- //掩码空间mask对应矩形空间内的掩码设置为GC_PR_FGD(预设为前景)
- Mat matRectCol = mask.colRange(rect.x, rect.x + rect.width);
- Mat matRectRow = mask.rowRange(rect.y, rect.y + rect.height);
- matRectCol.setTo(new Scalar(Imgproc.GC_PR_FGD));
- matRectRow.setTo(new Scalar(Imgproc.GC_PR_FGD));
- //框出预设前景
- Imgproc.rectangle(image,new Point(rect.x, rect.y),new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 0, 255, 255), 2);
- //Texture2D outputTexture = new Texture2D(image.cols(), image.rows(), TextureFormat.RGBA32, false);
- //Utils.matToTexture2D(image, outputTexture);
- //重新读取原始图片 切割
- Utils.texture2DToMat(inputTexture, image);
- bgModel = new Mat();
- fgModel = new Mat();
- Imgproc.grabCut(image, mask, rect, bgModel, fgModel, 1);
- GetBinMask(ref mask, ref binMask);
- dstMat = new Mat(mask.size(), CvType.CV_8UC1);
- image.copyTo(dstMat, binMask);
- Texture2D outputTexture = new Texture2D(dstMat.cols(), dstMat.rows(), TextureFormat.RGBA32, false);
- Utils.matToTexture2D(dstMat, outputTexture);
- gameObject.GetComponent<Renderer>().material.mainTexture = outputTexture;
- }
- // Update is called once per frame
- void Update () {
- }
- void GetBinMask(ref Mat comMask,ref Mat binMask)
- {
- binMask = new Mat(comMask.size(), CvType.CV_8UC1);
- //commask中有0,1,2,3四种取值,这句就是取值为0,2的在binmask都为0,取值1,3的在binmask中为1
- //binMask = comMask & 1;
- maskPixels = new byte[comMask.cols() * comMask.rows()*comMask.channels()];
- comMask.get(0,0,maskPixels);
- for (int i = 0; i < maskPixels.Length; i++)
- {
- if (maskPixels[i] == 0 || maskPixels[i] == 2)
- {
- maskPixels[i] = 0;
- }
- if (maskPixels[i] == 1 || maskPixels[i] == 3)
- {
- maskPixels[i] = 1;
- }
- }
- binMask.put(0,0, maskPixels);
- }
- }