// Double the width and height of a binarized image public static BinarizedImage ResizeImage( BinarizedImage a_rBinarizedImage ) { int iImageHeight = a_rBinarizedImage.Height; int iImageWidth = a_rBinarizedImage.Width; int iResizedImageHeight = 2 * iImageHeight; int iResizedImageWidth = 2 * iImageWidth; BinarizedImage oResizedBinarizedImage = new BinarizedImage( iResizedImageWidth, iResizedImageHeight, false ); // Upsampling // Copy original pixels to resized sprite pixels array for( int iResizedY = 0; iResizedY < iResizedImageHeight; ++iResizedY ) { for( int iResizedX = 0; iResizedX < iResizedImageWidth; ++iResizedX ) { // Euclidian div int iOriginalX = iResizedX / 2; int iOriginalY = iResizedY / 2; int iOriginalIndex = a_rBinarizedImage.Coords2PixelIndex( iOriginalX, iOriginalY ); int iResizedIndex = oResizedBinarizedImage.Coords2PixelIndex( iResizedX, iResizedY ); // Pixel copy oResizedBinarizedImage[ iResizedIndex ] = a_rBinarizedImage[ iOriginalIndex ]; } } return oResizedBinarizedImage; }
// Double the width and height of a binarized image public static BinarizedImage ResizeImage(BinarizedImage a_rBinarizedImage) { int iImageHeight = a_rBinarizedImage.Height; int iImageWidth = a_rBinarizedImage.Width; int iResizedImageHeight = 2 * iImageHeight; int iResizedImageWidth = 2 * iImageWidth; BinarizedImage oResizedBinarizedImage = new BinarizedImage(iResizedImageWidth, iResizedImageHeight, false); // Upsampling // Copy original pixels to resized sprite pixels array for (int iResizedY = 0; iResizedY < iResizedImageHeight; ++iResizedY) { for (int iResizedX = 0; iResizedX < iResizedImageWidth; ++iResizedX) { // Euclidian div int iOriginalX = iResizedX / 2; int iOriginalY = iResizedY / 2; int iOriginalIndex = a_rBinarizedImage.Coords2PixelIndex(iOriginalX, iOriginalY); int iResizedIndex = oResizedBinarizedImage.Coords2PixelIndex(iResizedX, iResizedY); // Pixel copy oResizedBinarizedImage[iResizedIndex] = a_rBinarizedImage[iOriginalIndex]; } } return(oResizedBinarizedImage); }
public static BinarizedImage DownScaleImage(BinarizedImage a_rBinarizedImage, int a_iHorizontalSubDivs, int a_iVerticalSubDivs) { int iImageWidth = a_rBinarizedImage.Width; int iImageHeight = a_rBinarizedImage.Height; int iGridSubDivPerRow = (a_iVerticalSubDivs + 1); int iGridSubDivPerColumn = (a_iHorizontalSubDivs + 1); int iGridSubDivCount = iGridSubDivPerRow * iGridSubDivPerColumn; // Grid div dimensions float fGridSubDivPixelWidth = ((float)iImageWidth) / (float)iGridSubDivPerRow; float fGridSubDivPixelHeight = ((float)iImageHeight) / (float)iGridSubDivPerColumn; BinarizedImage oResizedBinarizedImage = new BinarizedImage(iGridSubDivPerRow, iGridSubDivPerColumn, false); // Iterate grid divs for (int iGridSubDivIndex = 0; iGridSubDivIndex < iGridSubDivCount; ++iGridSubDivIndex) { // ( X, Y ) grid div pos from grid div index (in grid div space) int iGridSubDivX = iGridSubDivIndex % iGridSubDivPerRow; int iGridSubDivY = iGridSubDivIndex / iGridSubDivPerRow; // Compute the pixel bounds for this subdivision int iStartX = Mathf.FloorToInt(iGridSubDivX * fGridSubDivPixelWidth); int iStartY = Mathf.FloorToInt(iGridSubDivY * fGridSubDivPixelHeight); int iEndX = Mathf.CeilToInt((iGridSubDivX + 1) * fGridSubDivPixelWidth); int iEndY = Mathf.CeilToInt((iGridSubDivY + 1) * fGridSubDivPixelHeight); int iWidth = iEndX - iStartX; int iHeight = iEndY - iStartY; // Set grid sub div as empty while no significant pixel found bool bEmptyGridSubDiv = true; float fGridSubDivAlphaMean = 0.0f; for (int iY = 0; iY < iHeight; ++iY) { for (int iX = 0; iX < iWidth; ++iX) { int iPixelIndex = a_rBinarizedImage.Coords2PixelIndex(iX + iStartX, iY + iStartY); // At least one pixel is significant => need to create the whole grid div if (a_rBinarizedImage[iPixelIndex]) { bEmptyGridSubDiv = false; } fGridSubDivAlphaMean += a_rBinarizedImage.GetAlphaValue(iPixelIndex); } } fGridSubDivAlphaMean /= iHeight * iWidth; int iResizedIndex = oResizedBinarizedImage.Coords2PixelIndex(iGridSubDivX, iGridSubDivY); oResizedBinarizedImage.SetInternalPixel(iResizedIndex, !bEmptyGridSubDiv, fGridSubDivAlphaMean); } return(oResizedBinarizedImage); }
// Polygonizes a flat parametrized grid mesh from a binarized image public static Mesh PolygonizeGrid(BinarizedImage a_rBinarizedImage, Vector2 a_f2Scale, Vector3 a_f3PivotPoint, int a_iHorizontalSubDivs, int a_iVerticalSubDivs, bool a_bExtrude = false, float a_fExtrusionDepth = 0.0f) { BinarizedImage oDownScaledBinarizedImage = Uni2DEditorShapeExtractionUtils.DownScaleImage(a_rBinarizedImage, a_iHorizontalSubDivs, a_iVerticalSubDivs); Mesh oGridPlaneMesh = new Mesh( ); // Texture dimensions int iTextureWidth = a_rBinarizedImage.Width; int iTextureHeight = a_rBinarizedImage.Height; int iGridSubDivPerRow = (a_iVerticalSubDivs + 1); int iGridSubDivPerColumn = (a_iHorizontalSubDivs + 1); int iGridSubDivCount = iGridSubDivPerRow * iGridSubDivPerColumn; int iGridVertexCount = (a_iHorizontalSubDivs + 2) * (a_iVerticalSubDivs + 2); // Grid div dimensions float fGridSubDivPixelWidth = ((float)iTextureWidth) / (float)iGridSubDivPerRow; float fGridSubDivPixelHeight = ((float)iTextureHeight) / (float)iGridSubDivPerColumn; // Vertex pos -> index dictionary: stores the index associated to a given vertex int iCurrentVertexIndex = 0; Dictionary <Vector3, int> oVertexPosIndexDict = new Dictionary <Vector3, int>(iGridVertexCount); // Mesh data List <int> oGridPlaneTriangleList = new List <int>(6 * iGridVertexCount); // quad = 2 tris, 1 tri = 3 vertices => 2 * 3 //List<Vector2> oGridPlaneUVList = new List<Vector2>( iGridVertexCount ); List <int> oOutlineSides = new List <int>(); for (int iGridSubDivIndex = 0; iGridSubDivIndex < iGridSubDivCount; ++iGridSubDivIndex) { int iGridSubDivX = iGridSubDivIndex % iGridSubDivPerRow; int iGridSubDivY = iGridSubDivIndex / iGridSubDivPerRow; int iIndex = oDownScaledBinarizedImage.Coords2PixelIndex(iGridSubDivX, iGridSubDivY); if (oDownScaledBinarizedImage[iIndex]) { // ( X, Y ) grid div pos from grid div index (in grid div space) /* * Grid div * * ... ... * | | * ... --- TL ------- TR --- ... * | T2 / | * | / | * | / | * | / T1 | * ... --- BL ------- BR --- ... * | | * ... ... */ Vector3 f3BottomLeftVertex = new Vector3(iGridSubDivX * fGridSubDivPixelWidth, iGridSubDivY * fGridSubDivPixelHeight, 0.0f); // BL Vector3 f3BottomRightVertex = new Vector3((iGridSubDivX + 1) * fGridSubDivPixelWidth, iGridSubDivY * fGridSubDivPixelHeight, 0.0f); // BR Vector3 f3TopRightVertex = new Vector3((iGridSubDivX + 1) * fGridSubDivPixelWidth, (iGridSubDivY + 1) * fGridSubDivPixelHeight, 0.0f); // TR Vector3 f3TopLeftVertex = new Vector3(iGridSubDivX * fGridSubDivPixelWidth, (iGridSubDivY + 1) * fGridSubDivPixelHeight, 0.0f); // TL int iBottomLeftVertexIndex; int iBottomRightVertexIndex; int iTopRightVertexIndex; int iTopLeftVertexIndex; // For each grid div vertex, query its index if already created (the vertex might be shared with other grid divs). // If not, create it. if (oVertexPosIndexDict.TryGetValue(f3BottomLeftVertex, out iBottomLeftVertexIndex) == false) { iBottomLeftVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3BottomLeftVertex, iBottomLeftVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3BottomLeftVertex.x / (float) iTextureWidth, f3BottomLeftVertex.y / (float) iTextureHeight ) ); } if (oVertexPosIndexDict.TryGetValue(f3BottomRightVertex, out iBottomRightVertexIndex) == false) { iBottomRightVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3BottomRightVertex, iBottomRightVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3BottomRightVertex.x / (float) iTextureWidth, f3BottomRightVertex.y / (float) iTextureHeight ) ); } if (oVertexPosIndexDict.TryGetValue(f3TopRightVertex, out iTopRightVertexIndex) == false) { iTopRightVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3TopRightVertex, iTopRightVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3TopRightVertex.x / (float) iTextureWidth, f3TopRightVertex.y / (float) iTextureHeight ) ); } if (oVertexPosIndexDict.TryGetValue(f3TopLeftVertex, out iTopLeftVertexIndex) == false) { iTopLeftVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3TopLeftVertex, iTopLeftVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3TopLeftVertex.x / (float) iTextureWidth, f3TopLeftVertex.y / (float) iTextureHeight ) ); } // Create grid div triangles // First triangle (T1) oGridPlaneTriangleList.Add(iBottomRightVertexIndex); // BR oGridPlaneTriangleList.Add(iBottomLeftVertexIndex); // BL oGridPlaneTriangleList.Add(iTopRightVertexIndex); // TR // Second triangle (T2) oGridPlaneTriangleList.Add(iBottomLeftVertexIndex); // BL oGridPlaneTriangleList.Add(iTopLeftVertexIndex); // TL oGridPlaneTriangleList.Add(iTopRightVertexIndex); // TR // If we extrude check the sides to see if there are parts of the outline if (a_bExtrude) { // Up if (IsBinarizedImageCellEmpty(iGridSubDivX, iGridSubDivY + 1, iGridSubDivPerRow, iGridSubDivPerColumn, oDownScaledBinarizedImage)) { oOutlineSides.Add(iTopLeftVertexIndex); oOutlineSides.Add(iTopRightVertexIndex); } // Right if (IsBinarizedImageCellEmpty(iGridSubDivX + 1, iGridSubDivY, iGridSubDivPerRow, iGridSubDivPerColumn, oDownScaledBinarizedImage)) { oOutlineSides.Add(iTopRightVertexIndex); oOutlineSides.Add(iBottomRightVertexIndex); } // Bottom if (IsBinarizedImageCellEmpty(iGridSubDivX, iGridSubDivY - 1, iGridSubDivPerRow, iGridSubDivPerColumn, oDownScaledBinarizedImage)) { oOutlineSides.Add(iBottomRightVertexIndex); oOutlineSides.Add(iBottomLeftVertexIndex); } // Left if (IsBinarizedImageCellEmpty(iGridSubDivX - 1, iGridSubDivY, iGridSubDivPerRow, iGridSubDivPerColumn, oDownScaledBinarizedImage)) { oOutlineSides.Add(iBottomLeftVertexIndex); oOutlineSides.Add(iTopLeftVertexIndex); } } } } // Apply pivot + compute UVs int i2DVertexCount = oVertexPosIndexDict.Count; int iVertexCount = i2DVertexCount; Vector3 f3ExtrudeOffset = Vector3.zero; if (a_bExtrude) { iVertexCount = 2 * iVertexCount; f3ExtrudeOffset = Vector3.forward * a_fExtrusionDepth * 0.5f; } Vector2[] oGridPlaneUVs = new Vector2[iVertexCount]; Vector3[] oGridPlaneVertices = new Vector3[iVertexCount]; Vector2 f2Dimensions = new Vector2(1.0f / (float)iTextureWidth, 1.0f / (float)iTextureHeight); foreach (KeyValuePair <Vector3, int> rVertexPosIndexPair in oVertexPosIndexDict) { Vector3 f3VertexPos = rVertexPosIndexPair.Key; int iIndex = rVertexPosIndexPair.Value; Vector2 f2UV = new Vector2(f3VertexPos.x * f2Dimensions.x, f3VertexPos.y * f2Dimensions.y); Vector3 f3Vertex = (f3VertexPos - a_f3PivotPoint); f3Vertex.x *= a_f2Scale.x; f3Vertex.y *= a_f2Scale.y; if (a_bExtrude) { oGridPlaneUVs[iIndex] = f2UV; oGridPlaneVertices[iIndex] = f3Vertex - f3ExtrudeOffset; oGridPlaneUVs[iIndex + i2DVertexCount] = f2UV; oGridPlaneVertices[iIndex + i2DVertexCount] = f3Vertex + f3ExtrudeOffset; } else { oGridPlaneUVs[iIndex] = f2UV; oGridPlaneVertices[iIndex] = f3Vertex; } } // Surface Triangles int i2DTriangleIndicesCount = oGridPlaneTriangleList.Count; int iSurfaceTriangleIndicesCount = oGridPlaneTriangleList.Count; int iTriangleIndicesCount = oGridPlaneTriangleList.Count; if (a_bExtrude) { iSurfaceTriangleIndicesCount *= 2; iTriangleIndicesCount = 2 * iTriangleIndicesCount + oOutlineSides.Count * 3; } int[] oGridPlaneTriangleIndices = new int[iTriangleIndicesCount]; for (int i = 0; i < i2DTriangleIndicesCount; ++i) { int iIndex = oGridPlaneTriangleList[i]; oGridPlaneTriangleIndices[i] = iIndex; if (a_bExtrude) { oGridPlaneTriangleIndices[iSurfaceTriangleIndicesCount - 1 - i] = iIndex + i2DVertexCount; } } // Side Triangles if (a_bExtrude) { int iStartSideTriangle = iSurfaceTriangleIndicesCount; int iOutlineSideCount = oOutlineSides.Count / 2; for (int i = 0; i < iOutlineSideCount; ++i) { int iSideFrontBegin = oOutlineSides[i * 2]; int iSideFrontEnd = oOutlineSides[i * 2 + 1]; int iSideBackEnd = iSideFrontEnd + i2DVertexCount; int iSideBackBegin = iSideFrontBegin + i2DVertexCount; int iSideQuadStartIndex = iStartSideTriangle + i * 6; oGridPlaneTriangleIndices[iSideQuadStartIndex + 0] = iSideFrontBegin; oGridPlaneTriangleIndices[iSideQuadStartIndex + 1] = iSideBackBegin; oGridPlaneTriangleIndices[iSideQuadStartIndex + 2] = iSideBackEnd; oGridPlaneTriangleIndices[iSideQuadStartIndex + 3] = iSideFrontBegin; oGridPlaneTriangleIndices[iSideQuadStartIndex + 4] = iSideBackEnd; oGridPlaneTriangleIndices[iSideQuadStartIndex + 5] = iSideFrontEnd; } } oGridPlaneMesh.vertices = oGridPlaneVertices; oGridPlaneMesh.uv = oGridPlaneUVs; oGridPlaneMesh.triangles = oGridPlaneTriangleIndices; // LINQ return(oGridPlaneMesh); }
// Polygonizes a flat parametrized grid mesh from a binarized image public static Mesh PolygonizeGrid(BinarizedImage a_rBinarizedImage, float a_fScale, Vector3 a_f3PivotPoint, int a_iHorizontalSubDivs, int a_iVerticalSubDivs) { Mesh oGridPlaneMesh = new Mesh( ); // Texture dimensions int iTextureWidth = a_rBinarizedImage.Width; int iTextureHeight = a_rBinarizedImage.Height; int iGridSubDivPerRow = (a_iVerticalSubDivs + 1); int iGridSubDivPerColumn = (a_iHorizontalSubDivs + 1); int iGridSubDivCount = iGridSubDivPerRow * iGridSubDivPerColumn; int iGridVertexCount = (a_iHorizontalSubDivs + 2) * (a_iVerticalSubDivs + 2); // Grid div dimensions float fGridSubDivPixelWidth = ((float)iTextureWidth) / (float)iGridSubDivPerRow; float fGridSubDivPixelHeight = ((float)iTextureHeight) / (float)iGridSubDivPerColumn; // Also store these values as ints int iGridSubDivPixelWidth = Mathf.FloorToInt(fGridSubDivPixelWidth); int iGridSubDivPixelHeight = Mathf.FloorToInt(fGridSubDivPixelHeight); // Vertex pos -> index dictionary: stores the index associated to a given vertex int iCurrentVertexIndex = 0; Dictionary <Vector3, int> oVertexPosIndexDict = new Dictionary <Vector3, int>(iGridVertexCount); // Mesh data List <int> oGridPlaneTriangleList = new List <int>(6 * iGridVertexCount); // quad = 2 tris, 1 tri = 3 vertices => 2 * 3 //List<Vector2> oGridPlaneUVList = new List<Vector2>( iGridVertexCount ); // Iterate grid divs for (int iGridSubDivIndex = 0; iGridSubDivIndex < iGridSubDivCount; ++iGridSubDivIndex) { // ( X, Y ) grid div pos from grid div index (in grid div space) int iGridSubDivX = iGridSubDivIndex % iGridSubDivPerRow; int iGridSubDivY = iGridSubDivIndex / iGridSubDivPerRow; // Set grid sub div as empty while no significant pixel found bool bEmptyGridSubDiv = true; for (int iY = 0, iYLimit = iGridSubDivPixelHeight; bEmptyGridSubDiv && iY < iYLimit; ++iY) { for (int iX = 0, iXLimit = iGridSubDivPixelWidth; bEmptyGridSubDiv && iX < iXLimit; ++iX) { int iPixelIndex = a_rBinarizedImage.Coords2PixelIndex(iX + Mathf.FloorToInt(iGridSubDivX * fGridSubDivPixelWidth), iY + Mathf.FloorToInt(iGridSubDivY * fGridSubDivPixelHeight)); //int iPixelIndex = Mathf.FloorToInt( iGridSubDivY * fGridSubDivPixelHeight ) * iTextureWidth + Mathf.FloorToInt( iGridSubDivX * fGridSubDivPixelWidth ) + iY * iTextureWidth + iX; //bEmptyGridSubDiv = a_rBinarizedImage[ iPixelIndex ]; // At least one pixel is significant => need to create the whole grid div if (a_rBinarizedImage[iPixelIndex]) { /* * Grid div * * ... ... * | | * ... --- TL ------- TR --- ... * | T2 / | * | / | * | / | * | / T1 | * ... --- BL ------- BR --- ... * | | * ... ... */ Vector3 f3BottomLeftVertex = new Vector3(iGridSubDivX * fGridSubDivPixelWidth, iGridSubDivY * fGridSubDivPixelHeight, 0.0f); // BL Vector3 f3BottomRightVertex = new Vector3((iGridSubDivX + 1) * fGridSubDivPixelWidth, iGridSubDivY * fGridSubDivPixelHeight, 0.0f); // BR Vector3 f3TopRightVertex = new Vector3((iGridSubDivX + 1) * fGridSubDivPixelWidth, (iGridSubDivY + 1) * fGridSubDivPixelHeight, 0.0f); // TR Vector3 f3TopLeftVertex = new Vector3(iGridSubDivX * fGridSubDivPixelWidth, (iGridSubDivY + 1) * fGridSubDivPixelHeight, 0.0f); // TL int iBottomLeftVertexIndex; int iBottomRightVertexIndex; int iTopRightVertexIndex; int iTopLeftVertexIndex; // For each grid div vertex, query its index if already created (the vertex might be shared with other grid divs). // If not, create it. if (oVertexPosIndexDict.TryGetValue(f3BottomLeftVertex, out iBottomLeftVertexIndex) == false) { iBottomLeftVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3BottomLeftVertex, iBottomLeftVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3BottomLeftVertex.x / (float) iTextureWidth, f3BottomLeftVertex.y / (float) iTextureHeight ) ); } if (oVertexPosIndexDict.TryGetValue(f3BottomRightVertex, out iBottomRightVertexIndex) == false) { iBottomRightVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3BottomRightVertex, iBottomRightVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3BottomRightVertex.x / (float) iTextureWidth, f3BottomRightVertex.y / (float) iTextureHeight ) ); } if (oVertexPosIndexDict.TryGetValue(f3TopRightVertex, out iTopRightVertexIndex) == false) { iTopRightVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3TopRightVertex, iTopRightVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3TopRightVertex.x / (float) iTextureWidth, f3TopRightVertex.y / (float) iTextureHeight ) ); } if (oVertexPosIndexDict.TryGetValue(f3TopLeftVertex, out iTopLeftVertexIndex) == false) { iTopLeftVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add(f3TopLeftVertex, iTopLeftVertexIndex); //oGridPlaneUVList.Add( new Vector2( f3TopLeftVertex.x / (float) iTextureWidth, f3TopLeftVertex.y / (float) iTextureHeight ) ); } // Create grid div triangles // First triangle (T1) oGridPlaneTriangleList.Add(iBottomRightVertexIndex); // BR oGridPlaneTriangleList.Add(iBottomLeftVertexIndex); // BL oGridPlaneTriangleList.Add(iTopRightVertexIndex); // TR // Second triangle (T2) oGridPlaneTriangleList.Add(iBottomLeftVertexIndex); // BL oGridPlaneTriangleList.Add(iTopLeftVertexIndex); // TL oGridPlaneTriangleList.Add(iTopRightVertexIndex); // TR // Set grid sub div as not empty bEmptyGridSubDiv = false; } } } } // Apply pivot + compute UVs int iVertexCount = oVertexPosIndexDict.Count; Vector2[] oGridPlaneUVs = new Vector2[iVertexCount]; Vector3[] oGridPlaneVertices = new Vector3[iVertexCount]; Vector2 f2Dimensions = new Vector2(1.0f / (float)iTextureWidth, 1.0f / (float)iTextureHeight); foreach (KeyValuePair <Vector3, int> rVertexPosIndexPair in oVertexPosIndexDict) { Vector3 f3VertexPos = rVertexPosIndexPair.Key; int iIndex = rVertexPosIndexPair.Value; oGridPlaneUVs[iIndex] = new Vector2(f3VertexPos.x * f2Dimensions.x, f3VertexPos.y * f2Dimensions.y); oGridPlaneVertices[iIndex] = (f3VertexPos - a_f3PivotPoint) * a_fScale; } oGridPlaneMesh.vertices = oGridPlaneVertices; oGridPlaneMesh.uv = oGridPlaneUVs; oGridPlaneMesh.triangles = oGridPlaneTriangleList.ToArray( ); // LINQ return(oGridPlaneMesh); }
// Polygonizes a flat parametrized grid mesh from a binarized image public static Mesh PolygonizeGrid( BinarizedImage a_rBinarizedImage, float a_fScale, Vector3 a_f3PivotPoint, int a_iHorizontalSubDivs, int a_iVerticalSubDivs ) { Mesh oGridPlaneMesh = new Mesh( ); // Texture dimensions int iTextureWidth = a_rBinarizedImage.Width; int iTextureHeight = a_rBinarizedImage.Height; int iGridSubDivPerRow = ( a_iVerticalSubDivs + 1 ); int iGridSubDivPerColumn = ( a_iHorizontalSubDivs + 1 ); int iGridSubDivCount = iGridSubDivPerRow * iGridSubDivPerColumn; int iGridVertexCount = ( a_iHorizontalSubDivs + 2 ) * ( a_iVerticalSubDivs + 2 ); // Grid div dimensions float fGridSubDivPixelWidth = ( (float) iTextureWidth ) / (float) iGridSubDivPerRow; float fGridSubDivPixelHeight = ( (float) iTextureHeight ) / (float) iGridSubDivPerColumn; // Vertex pos -> index dictionary: stores the index associated to a given vertex int iCurrentVertexIndex = 0; Dictionary<Vector3,int> oVertexPosIndexDict = new Dictionary<Vector3, int>( iGridVertexCount ); // Mesh data List<int> oGridPlaneTriangleList = new List<int>( 6 * iGridVertexCount ); // quad = 2 tris, 1 tri = 3 vertices => 2 * 3 //List<Vector2> oGridPlaneUVList = new List<Vector2>( iGridVertexCount ); // Iterate grid divs for( int iGridSubDivIndex = 0; iGridSubDivIndex < iGridSubDivCount; ++iGridSubDivIndex ) { // ( X, Y ) grid div pos from grid div index (in grid div space) int iGridSubDivX = iGridSubDivIndex % iGridSubDivPerRow; int iGridSubDivY = iGridSubDivIndex / iGridSubDivPerRow; // Compute the pixel bounds for this subdivision int iStartX = Mathf.FloorToInt(iGridSubDivX * fGridSubDivPixelWidth); int iStartY = Mathf.FloorToInt(iGridSubDivY * fGridSubDivPixelHeight); int iEndX = Mathf.CeilToInt((iGridSubDivX + 1) * fGridSubDivPixelWidth); int iEndY = Mathf.CeilToInt((iGridSubDivY + 1) * fGridSubDivPixelHeight); int iWidth = iEndX - iStartX; int iHeight = iEndY - iStartY; // Set grid sub div as empty while no significant pixel found bool bEmptyGridSubDiv = true; for( int iY = 0; bEmptyGridSubDiv && iY < iHeight; ++iY ) { for( int iX = 0; bEmptyGridSubDiv && iX < iWidth; ++iX ) { int iPixelIndex = a_rBinarizedImage.Coords2PixelIndex( iX + iStartX, iY + iStartY ); //int iPixelIndex = Mathf.FloorToInt( iGridSubDivY * fGridSubDivPixelHeight ) * iTextureWidth + Mathf.FloorToInt( iGridSubDivX * fGridSubDivPixelWidth ) + iY * iTextureWidth + iX; //bEmptyGridSubDiv = a_rBinarizedImage[ iPixelIndex ]; // At least one pixel is significant => need to create the whole grid div if( a_rBinarizedImage[ iPixelIndex ] ) { /* * Grid div * * ... ... * | | * ... --- TL ------- TR --- ... * | T2 / | * | / | * | / | * | / T1 | * ... --- BL ------- BR --- ... * | | * ... ... */ Vector3 f3BottomLeftVertex = new Vector3( iGridSubDivX * fGridSubDivPixelWidth, iGridSubDivY * fGridSubDivPixelHeight, 0.0f ); // BL Vector3 f3BottomRightVertex = new Vector3( ( iGridSubDivX + 1 ) * fGridSubDivPixelWidth, iGridSubDivY * fGridSubDivPixelHeight, 0.0f ); // BR Vector3 f3TopRightVertex = new Vector3( ( iGridSubDivX + 1 ) * fGridSubDivPixelWidth, ( iGridSubDivY + 1 ) * fGridSubDivPixelHeight, 0.0f ); // TR Vector3 f3TopLeftVertex = new Vector3( iGridSubDivX * fGridSubDivPixelWidth, ( iGridSubDivY + 1 ) * fGridSubDivPixelHeight, 0.0f ); // TL int iBottomLeftVertexIndex; int iBottomRightVertexIndex; int iTopRightVertexIndex; int iTopLeftVertexIndex; // For each grid div vertex, query its index if already created (the vertex might be shared with other grid divs). // If not, create it. if( oVertexPosIndexDict.TryGetValue( f3BottomLeftVertex, out iBottomLeftVertexIndex ) == false ) { iBottomLeftVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add( f3BottomLeftVertex, iBottomLeftVertexIndex ); //oGridPlaneUVList.Add( new Vector2( f3BottomLeftVertex.x / (float) iTextureWidth, f3BottomLeftVertex.y / (float) iTextureHeight ) ); } if( oVertexPosIndexDict.TryGetValue( f3BottomRightVertex, out iBottomRightVertexIndex ) == false ) { iBottomRightVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add( f3BottomRightVertex, iBottomRightVertexIndex ); //oGridPlaneUVList.Add( new Vector2( f3BottomRightVertex.x / (float) iTextureWidth, f3BottomRightVertex.y / (float) iTextureHeight ) ); } if( oVertexPosIndexDict.TryGetValue( f3TopRightVertex, out iTopRightVertexIndex ) == false ) { iTopRightVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add( f3TopRightVertex, iTopRightVertexIndex ); //oGridPlaneUVList.Add( new Vector2( f3TopRightVertex.x / (float) iTextureWidth, f3TopRightVertex.y / (float) iTextureHeight ) ); } if( oVertexPosIndexDict.TryGetValue( f3TopLeftVertex, out iTopLeftVertexIndex ) == false ) { iTopLeftVertexIndex = iCurrentVertexIndex++; oVertexPosIndexDict.Add( f3TopLeftVertex, iTopLeftVertexIndex ); //oGridPlaneUVList.Add( new Vector2( f3TopLeftVertex.x / (float) iTextureWidth, f3TopLeftVertex.y / (float) iTextureHeight ) ); } // Create grid div triangles // First triangle (T1) oGridPlaneTriangleList.Add( iBottomRightVertexIndex ); // BR oGridPlaneTriangleList.Add( iBottomLeftVertexIndex ); // BL oGridPlaneTriangleList.Add( iTopRightVertexIndex ); // TR // Second triangle (T2) oGridPlaneTriangleList.Add( iBottomLeftVertexIndex ); // BL oGridPlaneTriangleList.Add( iTopLeftVertexIndex ); // TL oGridPlaneTriangleList.Add( iTopRightVertexIndex ); // TR // Set grid sub div as not empty bEmptyGridSubDiv = false; } } } } // Apply pivot + compute UVs int iVertexCount = oVertexPosIndexDict.Count; Vector2[ ] oGridPlaneUVs = new Vector2[ iVertexCount ]; Vector3[ ] oGridPlaneVertices = new Vector3[ iVertexCount ]; Vector2 f2Dimensions = new Vector2( 1.0f / (float) iTextureWidth, 1.0f / (float) iTextureHeight ); foreach( KeyValuePair<Vector3,int> rVertexPosIndexPair in oVertexPosIndexDict ) { Vector3 f3VertexPos = rVertexPosIndexPair.Key; int iIndex = rVertexPosIndexPair.Value; oGridPlaneUVs[ iIndex ] = new Vector2( f3VertexPos.x * f2Dimensions.x, f3VertexPos.y * f2Dimensions.y ); oGridPlaneVertices[ iIndex ] = ( f3VertexPos - a_f3PivotPoint ) * a_fScale; } oGridPlaneMesh.vertices = oGridPlaneVertices; oGridPlaneMesh.uv = oGridPlaneUVs; oGridPlaneMesh.triangles = oGridPlaneTriangleList.ToArray( ); // LINQ return oGridPlaneMesh; }
public static void CombinedContourLabeling( BinarizedImage a_rBinarizedImage, bool a_bPolygonizeHoles, out List<Contour> a_rOuterContours, out List<Contour> a_rInnerContours ) { a_rOuterContours = new List<Contour>( ); a_rInnerContours = new List<Contour>( ); int[ ] oLabelMap = new int[ a_rBinarizedImage.PixelCount ]; // init as 0 int iRegionCounter = 0; for( int iY = 0; iY < a_rBinarizedImage.Height; ++iY ) { int iLabel = 0; for( int iX = 0; iX < a_rBinarizedImage.Width; ++iX ) { int iPixelIndex = a_rBinarizedImage.Coords2PixelIndex( iX, iY ); if( a_rBinarizedImage[ iPixelIndex ] == true ) // Foreground { if( iLabel != 0 ) // Continue inside region { oLabelMap[ iPixelIndex ] = iLabel; } else { iLabel = oLabelMap[ iPixelIndex ]; if( iLabel == 0 ) // New outer contour { ++iRegionCounter; iLabel = iRegionCounter; Contour rOuterContour = TraceContour( iPixelIndex, NeighborDirection.DirectionRight, iLabel, a_rBinarizedImage, oLabelMap ); a_rOuterContours.Add( rOuterContour ); oLabelMap[ iPixelIndex ] = iLabel; } } } else // Background { if( iLabel != 0 ) { if( a_bPolygonizeHoles == true ) { if( oLabelMap[ iPixelIndex ] == 0 ) // New inner contour { iPixelIndex = a_rBinarizedImage.Coords2PixelIndex( iX - 1, iY ); Contour rInnerContour = TraceContour( iPixelIndex, NeighborDirection.DirectionUpRight, iLabel, a_rBinarizedImage, oLabelMap ); a_rInnerContours.Add( rInnerContour ); } iLabel = 0; } else if( oLabelMap[ iPixelIndex ] != -1 ) { oLabelMap[ iPixelIndex ] = iLabel; } else { iLabel = 0; } } } } } }
public static BinarizedImage DownScaleImage(BinarizedImage a_rBinarizedImage, int a_iHorizontalSubDivs, int a_iVerticalSubDivs) { int iImageWidth = a_rBinarizedImage.Width; int iImageHeight = a_rBinarizedImage.Height; int iGridSubDivPerRow = ( a_iVerticalSubDivs + 1 ); int iGridSubDivPerColumn = ( a_iHorizontalSubDivs + 1 ); int iGridSubDivCount = iGridSubDivPerRow * iGridSubDivPerColumn; // Grid div dimensions float fGridSubDivPixelWidth = ( (float) iImageWidth ) / (float) iGridSubDivPerRow; float fGridSubDivPixelHeight = ( (float) iImageHeight ) / (float) iGridSubDivPerColumn; BinarizedImage oResizedBinarizedImage = new BinarizedImage( iGridSubDivPerRow, iGridSubDivPerColumn, false ); // Iterate grid divs for( int iGridSubDivIndex = 0; iGridSubDivIndex < iGridSubDivCount; ++iGridSubDivIndex ) { // ( X, Y ) grid div pos from grid div index (in grid div space) int iGridSubDivX = iGridSubDivIndex % iGridSubDivPerRow; int iGridSubDivY = iGridSubDivIndex / iGridSubDivPerRow; // Compute the pixel bounds for this subdivision int iStartX = Mathf.FloorToInt(iGridSubDivX * fGridSubDivPixelWidth); int iStartY = Mathf.FloorToInt(iGridSubDivY * fGridSubDivPixelHeight); int iEndX = Mathf.CeilToInt((iGridSubDivX + 1) * fGridSubDivPixelWidth); int iEndY = Mathf.CeilToInt((iGridSubDivY + 1) * fGridSubDivPixelHeight); int iWidth = iEndX - iStartX; int iHeight = iEndY - iStartY; // Set grid sub div as empty while no significant pixel found bool bEmptyGridSubDiv = true; float fGridSubDivAlphaMean = 0.0f; for( int iY = 0; iY < iHeight; ++iY ) { for( int iX = 0; iX < iWidth; ++iX ) { int iPixelIndex = a_rBinarizedImage.Coords2PixelIndex( iX + iStartX, iY + iStartY ); // At least one pixel is significant => need to create the whole grid div if( a_rBinarizedImage[ iPixelIndex ] ) { bEmptyGridSubDiv = false; } fGridSubDivAlphaMean += a_rBinarizedImage.GetAlphaValue(iPixelIndex); } } fGridSubDivAlphaMean /= iHeight * iWidth; int iResizedIndex = oResizedBinarizedImage.Coords2PixelIndex( iGridSubDivX, iGridSubDivY ); oResizedBinarizedImage.SetInternalPixel(iResizedIndex, !bEmptyGridSubDiv, fGridSubDivAlphaMean); } return oResizedBinarizedImage; }
public static void CombinedContourLabeling(BinarizedImage a_rBinarizedImage, bool a_bPolygonizeHoles, out List <Contour> a_rOuterContours, out List <Contour> a_rInnerContours) { a_rOuterContours = new List <Contour>( ); a_rInnerContours = new List <Contour>( ); int[] oLabelMap = new int[a_rBinarizedImage.PixelCount]; // init as 0 int iRegionCounter = 0; for (int iY = 0; iY < a_rBinarizedImage.Height; ++iY) { int iLabel = 0; for (int iX = 0; iX < a_rBinarizedImage.Width; ++iX) { int iPixelIndex = a_rBinarizedImage.Coords2PixelIndex(iX, iY); if (a_rBinarizedImage[iPixelIndex] == true) // Foreground { if (iLabel != 0) // Continue inside region { oLabelMap[iPixelIndex] = iLabel; } else { iLabel = oLabelMap[iPixelIndex]; if (iLabel == 0) // New outer contour { ++iRegionCounter; iLabel = iRegionCounter; Contour rOuterContour = TraceContour(iPixelIndex, NeighborDirection.DirectionRight, iLabel, a_rBinarizedImage, oLabelMap); a_rOuterContours.Add(rOuterContour); oLabelMap[iPixelIndex] = iLabel; } } } else // Background { if (iLabel != 0) { if (a_bPolygonizeHoles == true) { if (oLabelMap[iPixelIndex] == 0) // New inner contour { iPixelIndex = a_rBinarizedImage.Coords2PixelIndex(iX - 1, iY); Contour rInnerContour = TraceContour(iPixelIndex, NeighborDirection.DirectionUpRight, iLabel, a_rBinarizedImage, oLabelMap); a_rInnerContours.Add(rInnerContour); } iLabel = 0; } else if (oLabelMap[iPixelIndex] != -1) { oLabelMap[iPixelIndex] = iLabel; } else { iLabel = 0; } } } } } }