Exemplo n.º 1
0
    /// <summary>
    /// Uses the parameters to reposition the images on the screen.
    /// </summary>
    /// <param name="skinObject"> Blob of skin </param>
    /// <param name="fingertipPositions"> fingertip coordinates </param>
    /// <param name="scale"> screen scale </param>
    public void ModelHand(SkinBlob skinObject, List <Vector2> fingertipPositions, float scale)
    {
        // Set palm position.
        palmImageRect.anchoredPosition = skinObject.GetMeanPoint() * scale;
        palmImageRect.sizeDelta        = new Vector2((skinObject.GetWidth() / 2) * scale, (skinObject.GetWidth() / 2) * scale);

        palmImageCollider.radius = skinObject.GetWidth() / 2;

        // Add new fingertips if neccesary.
        if (fingertips.Count < fingertipPositions.Count)
        {
            var numberOfNewFingetips = fingertipPositions.Count - fingertips.Count;
            for (var i = 0; i < numberOfNewFingetips; i++)
            {
                fingertips.Add(Instantiate(fingertipPrefab, transform));
            }
        }

        // Set location of fingertips.
        for (var i = 0; i < fingertips.Count; i++)
        {
            if (i < fingertipPositions.Count)
            {
                fingertips[i].gameObject.SetActive(true);
                fingertips[i].GetComponent <RectTransform>().anchoredPosition =
                    fingertipPositions[i] * scale;
            }
            else
            {
                fingertips[i].gameObject.SetActive(false);
            }
        }

        CountFingers(fingertipPositions.Count);
    }
    /// <summary>
    /// Tests if the point is within the threshold of being in another object.
    /// If not then create a new object. Also prunes skinblobs with tiny areas.
    /// </summary>
    /// <param name="point"> Location of pixel to check. </param>
    private void CheckSkinObjects(Vector2 point)
    {
        bool isObject = false;

        for (var i = 0; i < skinObjects.Count; i++)
        {
            if (skinObjects[i].TestPoint(point))
            {
                isObject = true;
                if (skinObjects[i].GetArea() >= largestSkinObject.GetArea() &&
                    skinObjects[i].GetSize() >= largestSkinObject.GetSize())
                {
                    largestSkinObject = skinObjects[i];
                }
                break;
            }
            else if (skinObjects[i].GetArea() <= 1.0f)
            {
                skinObjects.Remove(skinObjects[i]);
                i--;
            }
        }

        if (!isObject)
        {
            skinObjects.Add(new SkinBlob(point));
        }
    }
    /// <summary>
    /// Main segmentation loop. Loops through the entire set of pixels to
    /// detect skin-like pixels. Then Removes noise and enhances the skin
    /// pixels using skinblobs and gets the contourPointss of the skin. Finally
    /// calculating the convex hull.
    /// Also changes colors of pixels in the texture for debug / visualisation
    /// purposes.
    /// </summary>
    /// <param name="texture"> Contains all the pixels of the image. </param>
    /// <param name="threshold">
    /// Contains the color threshold to be considered a skin candidate.
    /// </param>
    /// <returns> Edited texture. </returns>
    public Color[] SegmentColors(WebCamTexture texture, float threshold, DisplayOptions OPTIONS)
    {
        // Get an array of pixels from the texture.
        var pixels = texture.GetPixels();

        // First Loop : Segment and identify skin blobs.
        skinObjects       = new List <SkinBlob>();
        largestSkinObject = new SkinBlob(new Vector2());
        int close = 0;

        for (var i = 0; i < pixels.Length; i++)
        {
            // Identify skin coloured pixels and add them to an object.
            // Threshold for skin color lowers if the pixel is close to a definite skin pixel.
            if (PixelThreshold(pixels[i], threshold) || (close > 0 && PixelThreshold(pixels[i], threshold / 2)))
            {
                CheckSkinObjects(Utility.IndexToPoint(texture.width, i));
                close = closeThreshold;
                // Display options - Sets initital segmentation pixels to white
                if (OPTIONS.SHOW_SEGMENTATION_FIRST)
                {
                    pixels[i] = Color.white;
                }
            }
            else
            {
                close--;
                // Display options - Sets other pixels to black
                if (OPTIONS.SHOW_SEGMENTATION_FIRST)
                {
                    pixels[i] = Color.black;
                }
            }
        }

        // Second Loop : focus on largest skin blob, removing noise. Get contour list.

        // Contour list creates candidates for the convex hull.
        var contourPoints = new List <Vector2>();
        // Linewidth dictates the longest uninterrupted line of skin pixels.
        var lineWidth = 0;
        var thisPixel = 0; // 0 black / 1 white.
        var lastPixel = 0; // 0 black / 1 white.

        for (var i = 0; i < pixels.Length; i++)
        {
            var pixelCoords = Utility.IndexToPoint(texture.width, i);
            // If within the skin objects min max boundries.
            // Also within an even more lenient threshold.
            if (pixelCoords.y < largestSkinObject.GetMaxPoint().y&&
                pixelCoords.y > largestSkinObject.GetMinPoint().y&&
                pixelCoords.x < largestSkinObject.GetMaxPoint().x&&
                pixelCoords.x > largestSkinObject.GetMinPoint().x&&
                PixelThreshold(pixels[i], threshold / 3))
            {
                lineWidth++;
                thisPixel = 1; // Skin pixel
                // Calculates 'center of mass'.
                largestSkinObject.AddToMean(pixelCoords);
                // Display Options - Show pixels after second segmentaiton.
                if (OPTIONS.SHOW_SEGMENTATION_SECOND)
                {
                    pixels[i] = Color.grey;
                }
            }
            else
            {
                // Send linewidth to the skin object and reset linewidth as
                // black pixel has been reached.
                largestSkinObject.TestWidth(lineWidth);
                lineWidth = 0;
                thisPixel = 0; // Black pixel.
                // Display Options - Show pixels after second segmentaiton.
                if (OPTIONS.SHOW_SEGMENTATION_SECOND)
                {
                    pixels[i] = Color.black;
                }
            }

            // Get a "good enough" contour point list for convex hull calculations.
            // Checks if the previous pixel was classed differently, then if true,
            // adds the current pixel to a list of contour points.
            if (thisPixel != lastPixel)
            {
                contourPoints.Add(pixelCoords);
            }

            lastPixel = thisPixel;
        }


        // Calculate convex hull using contour points.
        var hullPoints = ConvexHull.GetConvexHull(contourPoints);

        fingertipPoints = GetFingertips(hullPoints);



        // Display Options - Set contour pixels to green
        if (OPTIONS.SHOW_CONTOUR)
        {
            contourPoints.ForEach(point =>
            {
                pixels[Utility.PointToIndex(texture.width, point)] = Color.green;
            });
        }

        // Return array of edited pixels for display.
        return(pixels);
    }