void Save()
    {
        SlotScript ss = (SlotScript)target;

        // Create subfolder if it doesn't exist yet
        if (!Directory.Exists(subFolder))
        {
            Directory.CreateDirectory(Application.dataPath + "/" + subFolder);
        }

        isOverWriteOperation = File.Exists(filename);

        using (StreamWriter sw = new StreamWriter(filename))
        {
            for (int iRow = 0; iRow < ss.slotData.numberOfRows; ++iRow)
            {
                // Write row title
                sw.WriteLine("Row " + (iRow + 1));
                SlotData.Row row = ss.slotData.rows[iRow];
                for (int iSlot = 0; iSlot < row.numberOfSlots; ++iSlot)
                {
                    // Write slot title
                    sw.WriteLine("  Slot " + (iSlot + 1));
                    SlotData.Slot slot = row.slots[iSlot];
                    // Write pixel threshold level
                    sw.WriteLine("    " + slot.pxThresholdLevel);
                    foreach (SlotData.Cornerpoint cp in slot.areaCornerpoints)
                    {
                        // Write cornerpoint coordinates
                        sw.WriteLine("    " + cp.x + " " + cp.y);
                    }
                }
            } // for
        }     // using
    }
Ejemplo n.º 2
0
    public int GetTotalSlotCount()
    {
        int slotCount = 0;

        // Go through slot data for each processing camera and retrieve
        // the total number of slots the cameras have been setup to track
        for (int iCam = 0; iCam < numCams; ++iCam)
        {
            for (int iRow = 0; iRow < slotData[iCam].numberOfRows; ++iRow)
            {
                SlotData.Row row = slotData[iCam].rows[iRow];
                for (int iSlot = 0; iSlot < row.numberOfSlots; ++iSlot)
                {
                    SlotData.Slot slot = row.slots[iSlot];
                    if (!slot.IsUndefined())
                    {
                        ++slotCount;
                    }
                }
            }
        }
        return(slotCount);
    }
Ejemplo n.º 3
0
    public void ExtractSlots()
    {
        // Take snapshots of binary edge detection image and
        // read pixels and their colors from areas of interest
        ////////////////////////////////////////////////////////

        // Go through processing cameras
        for (int iCam = 0; iCam < numCams; ++iCam)
        {
            if (showDebugInfo)
            {
                Debug.Log("=========== " + transform.GetChild(iCam).name + " ===========");
            }

            // Mark renderTexture active so that Texture2D.ReadPixels()
            // will get pixels from it instead of the entire viewport.
            Transform tShaderPlanes = transform.GetChild(iCam).GetChild(1);
            RenderTexture.active = (RenderTexture)tShaderPlanes.
                                   GetChild(tShaderPlanes.childCount - 3).GetChild(0).
                                   GetComponent <Renderer>().material.mainTexture;

            for (int iRow = 0; iRow < slotData[iCam].numberOfRows; ++iRow)
            {
                SlotData.Row row = slotData[iCam].rows[iRow];
                for (int iSlot = 0; iSlot < row.numberOfSlots; ++iSlot)
                {
                    SlotData.Slot slot = row.slots[iSlot];

                    if (slot.IsUndefined())
                    {
                        // Slot corner points unassigned -> stop
                        continue;
                    }
                    // Get a bounding rect to define the target texture dimension
                    Rect boundingRect = slot.GetBoundingRect();
                    // Create a texture matching bounding rect dimensions
                    slot.colorTexture =
                        new Texture2D((int)boundingRect.width, (int)boundingRect.height);
                    // Turn user-provided cornerpoint rect Y coordinates (texture top edge
                    // Y == 0) into OpenGL coordinate space (texture bottom edge Y == 0)
                    SwapY(ref boundingRect, transform.GetChild(iCam).GetSiblingIndex());
                    // Read pixels into texture memory
                    slot.colorTexture.ReadPixels(boundingRect, 0, 0);
                    // Retrieve pixel RGBA components
                    Color32[] colorData = slot.colorTexture.GetPixels32();

                    /*
                     * Pixel In Polygon algorithm:
                     * - Search the bounding rectangle of the detection area quadrilateral.
                     *  In each Y position, traverse horizontally across the width of the
                     *  rectangle, a line at a time. If at any point the pixel under scrutiny
                     *  has crossed - from left to right - an uneven number of detection
                     *  area edge lines, it must be within the detection area. In such case,
                     *  if the color in that location is white, consider a hittest a success.
                     */

                    // Construct line data from detection area corner points
                    List <Line> lines = new List <Line>();
                    for (int iCp = 0; iCp < slot.areaCornerpoints.Length; ++iCp)
                    {
                        // Get each adjacent corner point pair
                        SlotData.Cornerpoint cp     = slot.areaCornerpoints[iCp];
                        SlotData.Cornerpoint nextCp =
                            slot.areaCornerpoints[(iCp + 1) % slot.areaCornerpoints.Length];
                        // Do OpenGL Y coord swapping
                        SwapY(ref cp.y, transform.GetChild(iCam).GetSiblingIndex());
                        SwapY(ref nextCp.y, transform.GetChild(iCam).GetSiblingIndex());
                        // Use the bounding rect lower (OpenGL) left corner coordinate as the
                        // (0, 0) reference point to create a line from a pair of corner points
                        lines.Add(new Line(
                                      cp.x - (int)boundingRect.x,
                                      cp.y - (int)boundingRect.y,
                                      nextCp.x - (int)boundingRect.x,
                                      nextCp.y - (int)boundingRect.y));
                    }

                    // Start counting the total and relative amount of white pixels
                    ///////////////////////////////////////////////////////////////

                    int numTotalPx = 0;
                    // int numTotalPx = Mathf.RoundToInt(boundingRect.width * boundingRect.height);
                    int numWhiteFound = 0;
                    // Go through a black/white binary-processed source image pixel at a time
                    for (int iColor = 0; iColor < colorData.Length; ++iColor)
                    {
                        int crossedLineCount = 0;

                        // Get X and Y coordinates being checked
                        int textureX = iColor % (int)boundingRect.width;
                        int textureY = Mathf.FloorToInt(iColor / boundingRect.width);

                        // Go through detection area edge lines, looking for line crossings.
                        // Order of scanning will be according to OpenGL coordinate space,
                        // from bottom (y == 0) to top (Y == texture height).
                        foreach (Line line in lines)
                        {
                            if (line.IsPointYInRange(textureY))
                            {
                                // The coordinate is within the Y axis range of the edge line.
                                // Get the X position on the line in the Y coordinate.
                                float lineCrossingX = line.GetXFromY(textureY);
                                // Compare line X with the X of the location being checked
                                if (System.Single.IsNaN(lineCrossingX))
                                {
                                    // Y coordinate matches horizontal detection area edge line
                                    // => pixel is to be considered to be inside the area and
                                    // taken into account.
                                    crossedLineCount = 1;
                                    break;
                                }
                                else if (lineCrossingX <= textureX)
                                {
                                    // Texture X coordinate is to the right of a line crossing
                                    ++crossedLineCount;
                                }
                            }
                        }

                        if (IsOddLineCount(crossedLineCount))
                        {
                            // Increase total found amount
                            ++numTotalPx;
                            if (IsWhiteColor(colorData[iColor]))
                            {
                                ++numWhiteFound;
                            }
                        }
                    }

                    // Pixel color count done -> calculate results
                    int thresholdPixelCount = (int)(slot.pxThresholdLevel * numTotalPx);
                    if (showDebugInfo)
                    {
                        Debug.Log("Parking row # " + (iRow + 1) + ", parking slot # " + (iSlot + 1) + ": " +
                                  "White pixel / total area pixel count & percentage: " + numWhiteFound + "/" +
                                  numTotalPx + ", " + ((float)numWhiteFound / numTotalPx * 100f).ToString("0.00") + "%" +
                                  "\nFree-to-reserved white pixel threshold count & percentage: " +
                                  thresholdPixelCount + ", " + (slot.pxThresholdLevel * 100).ToString("0.00") + "%  " +
                                  (numWhiteFound > thresholdPixelCount ? "RESERVED" : "FREE"));
                    }

                    // Inform scene maintenance script about slot reservation state
                    driveLineController.rows[iRow][iSlot] = numWhiteFound > thresholdPixelCount;
                } // for (int iSlot = 0; iSlot < row.numberOfSlots; ++iSlot)
            }     // for (int iRow = 0; iRow < slotData.numberOfRows; ++iRow)
        }         // for (int iCam = 0; iCam < numCams - 1; ++iCam)
    }
Ejemplo n.º 4
0
    public void SetCornerpointDisplayData(Material shaderMaterial)
    {
        cpList    = new List <SlotData.Cornerpoint>();
        colorList = new List <Color>();

        if (displayEdgeDetectionAreas)
        {
            // Edge detection cornerpoints have been selected to show up in the inspector

            if (slotScript.slotData.numberOfRows == 0)
            {
                if (!hasWarningBeenIssued)
                {
                    Debug.LogWarning("No detection area rows defined for " +
                                     transform.parent.parent.name + ".");
                    // Limit warnings to one per each playback
                    hasWarningBeenIssued = true;
                }
                return;
            }

            // Get corner points for each area
            for (int iRow = 0; iRow < slotScript.slotData.numberOfRows; ++iRow)
            {
                SlotData.Row row = slotScript.slotData.rows[iRow];
                for (int iSlot = 0; iSlot < row.numberOfSlots; ++iSlot)
                {
                    if (row.slots[iSlot].IsUndefined())
                    {
                        // Unset slot coordinates => skip
                        continue;
                    }
                    cpList.AddRange(row.slots[iSlot].areaCornerpoints);
                }
            }

            // Use texture to pass corner point data to the shader
            //////////////////////////////////////////////////////

            // 4 corner points for each defined slot
            // Each pixel value in texture can hold data for two points,
            // (== half a slot), i.e., sizeof(RGBA) == 2 * sizeof(XY).
            // Therefore, each slot will consume two pixels.

            // Slot N (Tex line N)  Tex px N  Px cpnts  Slot cornerpoints
            // 0                    0         RG        (X, Y)
            // 0                    0         BA        (X, Y)
            // 0                    1         RG        (X, Y)
            // 0                    1         BA        (X, Y)
            // -----------------------------------------------
            // 1                    2         RG        (X, Y)
            // 1                    2         BA        (X, Y)
            // 1                    3         RG        (X, Y)
            // 1                    3         BA        (X, Y)
            // -----------------------------------------------

            // etc.

            // Total number of slots in all parking rows
            int numSlotsTotal = cpList.Count / 4;
            // Number of required texture pixels to represent
            // coordinate points for every slot detection area
            // (one RGBA covers 2 out of 4 cornerpoints for a slot)
            int texturePixelCount = numSlotsTotal * 2;

            // Create texture that can hold corner pixel location data
            tex = new Texture2D(texturePixelsPerLine, numSlotsTotal);
            Color color = new Color(0f, 0f, 0f, 0f);
            for (int iPixel = 0; iPixel < texturePixelCount; ++iPixel)
            {
                // Two cornerpoints fit in the RGBA structure
                for (int iCp = 0; iCp < 2; ++iCp)
                {
                    SlotData.Cornerpoint cp = cpList[iPixel * 2 + iCp];
                    // Swap Y coordinate and interpolate pixel values
                    imageSlotExtractor.SwapY(ref cp.y, transform.parent.parent.GetSiblingIndex());
                    Vector2 interpCp = new Vector2(
                        (float)cp.x / planeManager.GetSourceWidth(),
                        (float)cp.y / planeManager.GetSourceHeight());
                    // Store interpolated [0...1] values.
                    if (iCp % 2 == 0)
                    {
                        // First coordinate pair that populates RG of RGBA
                        color.r = interpCp.x;
                        color.g = interpCp.y;
                    }
                    else
                    {
                        // Second coordinate pair that populates BA of RGBA
                        color.b = interpCp.x;
                        color.a = interpCp.y;
                        colorList.Add(color);
                    }
                }
            }

            // Setting filter mode to Point is a MUST! With default setting,
            // there's a LOT of pixel averaging and/or blending. We want
            // pure blocky content!
            tex.filterMode = FilterMode.Point;
            // Apply color data to the texture
            tex.SetPixels(colorList.ToArray());
            tex.Apply();

            // Pass texture data to the shader
            ///////////////////////////////////
            // Texture
            shaderMaterial.SetTexture("_ColorTex", tex);
            // Texture dimensions
            shaderMaterial.SetInt("_ColorTexWidth", texturePixelsPerLine);
            shaderMaterial.SetInt("_ColorTexHeight", numSlotsTotal);
            // Alternating colors for adjacent sets of four cornerpoints
            shaderMaterial.SetColor("_CornerColor0", cornerPointColorA);
            shaderMaterial.SetColor("_CornerColor1", cornerPointColorB);
            // Source image aspect ratio
            shaderMaterial.SetFloat("_MainTexAspectRatio",
                                    (float)planeManager.GetSourceWidth() / planeManager.GetSourceHeight());
            // Radius of colored cornerpoint square in the screen
            shaderMaterial.SetFloat("_CornerpointRadius", edgeCornerPointDisplayRadius);
        }
        // Enable variable needs to be passed outside of conditional block to ensure once enabled
        // borders are erased during playback if the user unselects the option in the inspector
        shaderMaterial.SetFloat("_DisplayCornerpoints", displayEdgeDetectionAreas ? 1.0f : 0.0f);
    }