/// <summary>Compute distance maps</summary> public void ComputeDistanceMaps() { //for (int j=0;j<_strokes.Count;j++) Parallel.For(0, _strokes.Count, j => { ColorStroke cs = _strokes[j]; if (cs.DistanceMap == null) { cs.DistanceMap = GetPixelDistances(cs.StrokeCoords, _edges, ImageWidth, ImageHeight, MAXITER); } }); }
/// <summary>Clones this object</summary> public ColorStroke Clone() { List <int[]> newc = new List <int[]>(); foreach (int[] k in this.StrokeCoords) { newc.Add(new int[] { k[0], k[1] }); } ColorStroke cs = new ColorStroke(newc, this.StrokeColor); if (DistanceMap != null) { cs.DistanceMap = (float[])this.DistanceMap.Clone(); } return(cs); }
/// <summary> /// Sirve como la función hash predeterminada. /// </summary> /// <returns>Código hash para el objeto actual.</returns> public override int GetHashCode() { int hash = 17; // Un número primo int prime = 31; // Otro número primo. hash = hash * prime + MetadataItemName.GetHashCode(); hash = hash * prime + PdfPageN.GetHashCode(); hash = hash * prime + IsLastPage.GetHashCode(); hash = hash * prime + ((PdfRectangle == null) ? 0 : PdfRectangle.GetHashCode()); hash = hash * prime + (RegexPattern ?? "").GetHashCode(); hash = hash * prime + Position.GetHashCode(); hash = hash * prime + (SourceTypeName ?? "").GetHashCode(); hash = hash * prime + ((ColorFill == null) ? 0 : ColorFill.GetHashCode()); hash = hash * prime + ((ColorStroke == null) ? 0 : ColorStroke.GetHashCode()); hash = hash * prime + ((FontSize == null) ? 0 : FontSize.GetHashCode()); hash = hash * prime + ((FontType == null) ? 0 : FontType.GetHashCode()); return(hash); }
/// <summary>Save strokes to a file</summary> /// <param name="curFile">File to save to</param> public void SaveStrokes(string curFile) { if (curFile == "") { return; } using (StreamWriter sw = new StreamWriter(curFile + ".strokes")) { for (int i = 0; i < _strokes.Count; i++) { ColorStroke cs = _strokes[i]; sw.WriteLine("Color " + cs.StrokeColor.R.ToString() + " " + cs.StrokeColor.G.ToString() + " " + cs.StrokeColor.B.ToString() + " " + cs.StrokeCoords.Count); foreach (int[] p in cs.StrokeCoords) { sw.WriteLine(p[0] + " " + p[1]); } } } }
/// <summary>Retrieves stroke closest to XY position</summary> public ColorStroke getClosestStroke(int x, int y, out float dist) { if (x < 0 || y < 0 || x >= ImageWidth || y >= ImageHeight || _strokes.Count == 0) { dist = float.PositiveInfinity; return(null); } ColorStroke closest = _strokes[0]; float smallestDist = float.MaxValue; for (int k = 0; k < _strokes.Count; k++) { ColorStroke cs = _strokes[k]; if (cs.DistanceMap != null && smallestDist > cs.DistanceMap[x + ImageWidth * y]) { smallestDist = cs.DistanceMap[x + ImageWidth * y]; closest = cs; } } dist = smallestDist; return(closest); }
/// <summary> /// Determina si el objeto especificado es igual al objeto actual. /// </summary> /// <param name="obj">Objeto que se va a comparar con el objeto actual.</param> /// <returns>Es true si el objeto especificado es igual al objeto actual; /// en caso contrario, es false.</returns> public override bool Equals(object obj) { PdfTagPattern input = (obj as PdfTagPattern); if (input == null) { throw new ArgumentException("Parámetro de tipo incorrecto."); } bool equalsTextString = false; bool equalsRectangle = false; if (input.SourceTypeName.Equals("TextStringInfos")) // Comprobamos si las propiedades de los textString coinciden { if (FontSize != null && input.FontSize != null && ColorFill != null && input.ColorFill != null && ColorStroke != null && input.ColorStroke != null && FontType != null && input.FontType != null && TsType != null && input.TsType != null) { if (ColorFill.Equals(input.ColorFill) && ColorStroke.Equals(input.ColorStroke) && FontSize.Equals(input.FontSize) && FontType.Equals(input.FontType) && TsType.Equals(input.TsType)) { if ((TsType.Equals("X") || TsType.Equals("Y")) && TsCoordinate.Equals(input.TsCoordinate)) { equalsTextString = true; } else if (TsType.Equals("NA")) { equalsTextString = true; } } } } else { equalsTextString = true; } if (PdfRectangle != null && input.PdfRectangle != null) // Comprobamos si el rectángulo coincide && FontType==null { equalsRectangle = PdfRectangle.Equals(input.PdfRectangle); } else { equalsRectangle = true; } return((MetadataItemName == input.MetadataItemName && PdfPageN == input.PdfPageN && IsLastPage == input.IsLastPage && equalsRectangle && RegexPattern == input.RegexPattern && Position == input.Position && SourceTypeName == input.SourceTypeName) && equalsTextString); }
/// <summary>Retrieve color strokes from an image. Remove color strokes from image.</summary> /// <param name="bmpSource">Source bitmap</param> /// <param name="colorDifThresh">Color difference threshold to consider as not Black and White</param> /// <returns></returns> public static List <ColorStroke> GetColorStrokes(Bitmap bmpSource, int colorDifThresh) { //Step 1: identify regions in the image that are not B&W //{X, Y, R,G,B} of pixel List <int[]> colorPixels = new List <int[]>(); int W = bmpSource.Width; BitmapData bitmapData = bmpSource.LockBits(new Rectangle(0, 0, bmpSource.Width, bmpSource.Height), ImageLockMode.ReadWrite, bmpSource.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmpSource.PixelFormat) / 8; int byteCount = bitmapData.Stride * bmpSource.Height; byte[] pixels = new byte[byteCount]; IntPtr ptrFirstPixel = bitmapData.Scan0; Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length); int heightInPixels = bitmapData.Height; int widthInBytes = bitmapData.Width * bytesPerPixel; int xx, yy; yy = 0; for (int y = 0; y < heightInPixels; y++) { int currentLine = y * bitmapData.Stride; xx = 0; for (int x = 0; x < widthInBytes; x = x + bytesPerPixel) { int vB = pixels[currentLine + x]; int vG = pixels[currentLine + x + 1]; int vR = pixels[currentLine + x + 2]; if (Math.Abs(vR - vG) > colorDifThresh || Math.Abs(vR - vB) > colorDifThresh || Math.Abs(vB - vG) > colorDifThresh) { //deserves attention colorPixels.Add(new int[] { xx, yy, vR, vG, vB }); pixels[currentLine + x] = 255; pixels[currentLine + x + 1] = 255; pixels[currentLine + x + 2] = 255; } xx++; } yy++; } // copy modified bytes back Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length); bmpSource.UnlockBits(bitmapData); List <ColorStroke> ans = new List <ColorStroke>(); //Step 2: group regions correctly while (colorPixels.Count > 0) { List <int[]> regionPixels = new List <int[]>(); regionPixels.Add(colorPixels[colorPixels.Count - 1]); colorPixels.RemoveAt(colorPixels.Count - 1); bool foundCandidates = true; while (foundCandidates) { foundCandidates = false; for (int k = 0; k < regionPixels.Count; k++) { List <int[]> regionCandidates = colorPixels.Where(p => Math.Abs(p[0] - regionPixels[k][0]) < 3 && Math.Abs(p[1] - regionPixels[k][1]) < 3 && //pixel is near Math.Abs(p[2] - regionPixels[k][2]) + Math.Abs(p[3] - regionPixels[k][3]) + Math.Abs(p[4] - regionPixels[k][4]) < 3 * colorDifThresh //color is similar ).ToList <int[]>(); if (regionCandidates.Count > 0) { foundCandidates = true; foreach (int[] pt in regionCandidates) { regionPixels.Add(pt); colorPixels.Remove(pt); } } } } if (regionPixels.Count > 20) { //average color int[] avgColor = new int[] { 0, 0, 0 }; List <int[]> coords = new List <int[]>(); foreach (int[] pt in regionPixels) { for (int k = 0; k < 3; k++) { avgColor[k] += pt[k + 2]; } coords.Add(new int[] { pt[0], pt[1] }); } for (int k = 0; k < 3; k++) { avgColor[k] /= regionPixels.Count; } ColorStroke cs = new ColorStroke(coords, Color.FromArgb(avgColor[0], avgColor[1], avgColor[2])); ans.Add(cs); } } return(ans); }
/// <summary>Compose image from current strokes</summary> /// <returns></returns> public Bitmap ComposeImage() { Bitmap bmpSource = new Bitmap(ImageWidth, ImageHeight); BitmapData bitmapData = bmpSource.LockBits(new Rectangle(0, 0, bmpSource.Width, bmpSource.Height), ImageLockMode.ReadWrite, bmpSource.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmpSource.PixelFormat) / 8; int byteCount = bitmapData.Stride * bmpSource.Height; byte[] pixels = new byte[byteCount]; IntPtr ptrFirstPixel = bitmapData.Scan0; Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length); int heightInPixels = bitmapData.Height; int widthInBytes = bitmapData.Width * bytesPerPixel; //int xx, yy; //yy = 0; Parallel.For(0, heightInPixels, y => //for (int y = 0; y < heightInPixels; y++) { int yy = y; int currentLine = y * bitmapData.Stride; int xx = 0; for (int x = 0; x < widthInBytes; x = x + bytesPerPixel) { float rC = 255, gC = 255, bC = 255; if (_edges.BinarySearch(xx + ImageWidth * yy) >= 0) { rC = 0; gC = 0; bC = 0; } float totWeight = 0; for (int j = 0; j < _strokes.Count; j++) { ColorStroke cs = _strokes[j]; if (cs.DistanceMap != null) { float myWeight = 1.0f / (1e-5f + cs.DistanceMap[xx + ImageWidth * yy]); float rN = cs.StrokeColor.R; float gN = cs.StrokeColor.G; float bN = cs.StrokeColor.B; if (myWeight > 1E-4f * totWeight) { myWeight = (float)Math.Pow(myWeight, 1.7f); if (myWeight + totWeight > 0) { float temp = 1.0f / (myWeight + totWeight); rC = (rN * myWeight + rC * totWeight) * temp; gC = (gN * myWeight + gC * totWeight) * temp; bC = (bN * myWeight + bC * totWeight) * temp; totWeight += myWeight; } if (float.IsNaN(rC)) { } } } } pixels[currentLine + x] = (byte)bC; pixels[currentLine + x + 1] = (byte)gC; pixels[currentLine + x + 2] = (byte)rC; pixels[currentLine + x + 3] = 255; xx++; } yy++; }); // copy modified bytes back Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length); bmpSource.UnlockBits(bitmapData); return(bmpSource); }
/// <summary>Adds a new stroke to this drawing</summary> /// <param name="coords">Coordinates of the stroke</param> /// <param name="c">Stroke color</param> public void AddStroke(List <int[]> coords, Color c) { ColorStroke cs = new ColorStroke(coords, c); _strokes.Add(cs); }