Untitled
unknown
csharp
4 years ago
22 kB
65
Indexable
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO; using System.Drawing.Imaging; namespace EDMarker_Generator { public unsafe class MarkerGenerator { // number of bits in a marker int noOfBits = 48; // following values are in ratios, where a marker edge length is 1 // border width //float border = 0.125f; float border = 0.0f; // radius of the circle border float outerCircleRadius = 0.4f; // radius of the circle that encloses code bits float innerCircleRadius = 0.35f; // radius of the code circles (in ratio to innerCircleRadius) float codeRadius = 0.062482177287080f; // radius of the filler code circles (in ratio to codeRadius) float fillerCodeRadius = 0.7f; // following values are in pixels int fileSize = 1000; float markerSize; float borderSize; float outerCircleDiameterSize; float innerCircleDiameterSize; float outerCircleTopLeft; float innerCircleTopLeft; float codeCircleDiameterSize; float fillerCircleDiameterSize; bool drawSteps = true; // code related stuff int HD; List<List<Byte>> codes; List<doublePoint> codeLocs; List<List<int>> nearbyCodes; Font largeFont, smallFont; // Pen grayPen; static void Main() { new MarkerGenerator(); } public MarkerGenerator() { // InitializeComponent(); markerSize = fileSize / (1 + border * 2); borderSize = markerSize * border; outerCircleDiameterSize = 2 * markerSize * outerCircleRadius; innerCircleDiameterSize = 2 * markerSize * innerCircleRadius; outerCircleTopLeft = (fileSize - outerCircleDiameterSize) / 2; innerCircleTopLeft = (fileSize - innerCircleDiameterSize) / 2; codeCircleDiameterSize = 2 * innerCircleDiameterSize * codeRadius; fillerCircleDiameterSize = codeCircleDiameterSize * fillerCodeRadius; largeFont = new Font("Century Gothic", 72); smallFont = new Font("Century Gothic", 20); // grayPen = new Pen(Color.Gray, 3); fillLocs(); List<Point> po = generateBallMask(12); foreach (Point p in po){ Console.WriteLine(p.X + " " + p.Y); } // for (HD = 11; HD <= 23; HD += 2) //{ HD = 23; readCodeList(); /* foreach (List<Byte> c in codes){ foreach (Byte b in c){ Console.Write(b); } Console.WriteLine(); }*/ drawMarkers(); //} } public void fillLocs() { codeLocs = new List<doublePoint>(); for (int i = 0; i < 4; i++) { codeLocs.Add(polarToCart(0.088363142525988, 0.785398163397448 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.206935928182607, 0.459275804122858 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.206935928182607, (Math.PI / 2) - 0.459275804122858 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.313672146827381, 0.200579720495241 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.327493143484516, 0.591687617505840 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.327493143484516, (Math.PI / 2) - 0.591687617505840 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.313672146827381, (Math.PI / 2) - 0.200579720495241 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.437421957035861, 0.145724938287167 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.437226762361658, 0.433363129825345 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.430628029742607, 0.785398163397448 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.437226762361658, (Math.PI / 2) - 0.433363129825345 + i * (Math.PI / 2))); codeLocs.Add(polarToCart(0.437421957035861, (Math.PI / 2) - 0.145724938287167 + i * (Math.PI / 2))); } nearbyCodes = new List<List<int>>(); for (int i = 0; i < noOfBits; i++) { nearbyCodes.Add(new List<int>()); for (int j = 0; j < noOfBits; j++) { if (i == j) continue; if (distanceBetweenDoublePoints(codeLocs[i], codeLocs[j]) < codeRadius * 4) nearbyCodes[i].Add(j); } } } public void drawMarkers() { String dirName = "HD" + HD.ToString(); System.IO.Directory.CreateDirectory(dirName); Bitmap img = new Bitmap(fileSize, fileSize); Graphics g = Graphics.FromImage(img); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; for (int i = 0; i < codes.Count; i++) { // we are working with the same bitmap, so clear it g.Clear(Color.White); displayBitmap(ref img, "After clear bitmap"); // draw the outer rectangle g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; g.FillRectangle(Brushes.Black, borderSize, borderSize, markerSize, markerSize); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; displayBitmap(ref img, "After draw the outer rectangle"); // draw the outer circle g.FillEllipse(Brushes.White, outerCircleTopLeft, outerCircleTopLeft, outerCircleDiameterSize, outerCircleDiameterSize); displayBitmap(ref img, "After draw the outer circle"); // turn off antialiasing to apply morphological operations g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; // apply black code circles for (int j = 0; j < noOfBits; j++) if (codes[i][j] == 1) g.FillEllipse(Brushes.Black, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].x - codeCircleDiameterSize / 2, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].y - codeCircleDiameterSize / 2, codeCircleDiameterSize, codeCircleDiameterSize); displayBitmap(ref img, "After apply black code circles"); // apply filler circles for (int j = 0; j < noOfBits; j++) for (int k = j + 1; k < noOfBits; k++) if ((codes[i][j] == 1) && (codes[i][k] == 1)) if (nearbyCodes[j].Contains(k)) g.FillEllipse(Brushes.Black, innerCircleTopLeft + innerCircleDiameterSize * (float)((codeLocs[j].x + codeLocs[k].x) / 2) - fillerCircleDiameterSize / 2, innerCircleTopLeft + innerCircleDiameterSize * (float)((codeLocs[j].y + codeLocs[k].y) / 2) - fillerCircleDiameterSize / 2, fillerCircleDiameterSize, fillerCircleDiameterSize); displayBitmap(ref img, "After apply filler circles"); // apply white code circles for (int j = 0; j < noOfBits; j++) if (codes[i][j] == 0) g.FillEllipse(Brushes.White, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].x - codeCircleDiameterSize / 2, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].y - codeCircleDiameterSize / 2, codeCircleDiameterSize, codeCircleDiameterSize); displayBitmap(ref img, "After apply white code circles"); img.Save(dirName + "/preErodeAndDilate.png", System.Drawing.Imaging.ImageFormat.Png); //erode, dilate int rad = 12; for (int j = 0; j < 5; j++) { dilateBitmap(ref img, 5, rad); erodeBitmap(ref img, 5, rad); } img.Save(dirName + "/afterErodeAndDilate.png", System.Drawing.Imaging.ImageFormat.Png); displayBitmap(ref img, "After erode and dilate"); // smooth and recode smoothBitmap(ref img); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; displayBitmap(ref img, "After smooth"); /* // apply black code circles for (int j = 0; j < noOfBits; j++) if (codes[i][j] == 1) g.FillEllipse(Brushes.Black, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].x - codeCircleDiameterSize / 2, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].y - codeCircleDiameterSize / 2, codeCircleDiameterSize, codeCircleDiameterSize); displayBitmap(ref img, "after apply black code circles"); // apply white code circles for (int j = 0; j < noOfBits; j++) if (codes[i][j] == 0) g.FillEllipse(Brushes.White, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].x - codeCircleDiameterSize / 2, innerCircleTopLeft + innerCircleDiameterSize * (float)codeLocs[j].y - codeCircleDiameterSize / 2, codeCircleDiameterSize, codeCircleDiameterSize); displayBitmap(ref img, "after apply white code circles"); // clear the space between the inner and outer circle Bitmap ringImg = new Bitmap(fileSize, fileSize); Graphics gRing = Graphics.FromImage(ringImg); gRing.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; gRing.FillRectangle(Brushes.Black, 0, 0, fileSize, fileSize); gRing.FillEllipse(Brushes.White, outerCircleTopLeft, outerCircleTopLeft, outerCircleDiameterSize, outerCircleDiameterSize); gRing.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; gRing.FillEllipse(Brushes.Black, innerCircleTopLeft - 1, innerCircleTopLeft - 1, innerCircleDiameterSize + 2, innerCircleDiameterSize + 2); gRing.Dispose(); ringImg.MakeTransparent(Color.Black); g.DrawImage(ringImg, 0, 0); displayBitmap(ref img, "after clear the space between the inner and outer circle"); */ // In case we want crosshair //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; //g.FillEllipse(Brushes.White, (float)(outputSize / 2 - 8), (float)(outputSize / 2 - 8), 16, 16); //g.DrawLine(pen, (float)(outputSize / 2 - 7), (float)(outputSize / 2 ), (float)(outputSize / 2 + 8), (float)(outputSize / 2 )); //g.DrawLine(pen, (float)(outputSize / 2), (float)(outputSize / 2 - 7 ), (float)(outputSize / 2), (float)(outputSize / 2 + 8 )); //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; // // write the strings SizeF sz = g.VisibleClipBounds.Size; float centerString = (float)(2.375 * borderSize); g.TranslateTransform(centerString, centerString); g.RotateTransform(315); sz = g.MeasureString(createIndexString(i), largeFont); g.DrawString(createIndexString(i), largeFont, Brushes.White, -(sz.Width / 2), -(sz.Height / 2)); g.ResetTransform(); centerString = (float)(1.875 * borderSize); g.TranslateTransform(centerString, centerString); g.RotateTransform(315); sz = g.MeasureString("HD" + HD.ToString(), smallFont); g.DrawString("HD" + HD.ToString(), smallFont, Brushes.White, -(sz.Width / 2), -(sz.Height / 2)); g.ResetTransform(); displayBitmap(ref img, "after write the strings"); // save image String idStr = createIndexString(i); while (idStr.Length < 5) idStr = "0" + idStr; img.Save(dirName + "/" + idStr + ".png", System.Drawing.Imaging.ImageFormat.Png); } } public double distanceBetweenDoublePoints(doublePoint p1, doublePoint p2) { return Math.Sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } public String createIndexString(int index) { String s = index.ToString(); while (s.Length != codes.Count.ToString().Length) s = "0" + s; return s; } public doublePoint polarToCart(double radius, double radians) { return new doublePoint(0.5 + Math.Cos(radians) * radius, 0.5 - Math.Sin(radians) * radius); } public void erodeBitmap(ref Bitmap b, int thres, int radius) { Rectangle rect = new Rectangle(0, 0, fileSize, fileSize); BitmapData imgData = b.LockBits(rect, ImageLockMode.WriteOnly, b.PixelFormat); Bitmap refImage = (Bitmap)b.Clone(); BitmapData refData = refImage.LockBits(rect, ImageLockMode.ReadOnly, refImage.PixelFormat); List<Point> list = generateBallMask(radius); int border = (int)outerCircleTopLeft; for (int j = border; j < fileSize - border; j++) { for (int k = border; k < fileSize - border; k++) { if (!isWhite(refData, j, k)) { int tot = countNonPixels(refData, j, k, true, list); if (tot > list.Count / 2) { *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4)) = 255; *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 1) = 255; *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 2) = 255; *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 3) = 255; } } } } refImage.UnlockBits(refData); refImage.Dispose(); b.UnlockBits(imgData); } public void dilateBitmap(ref Bitmap b, int thres, int radius) { Rectangle rect = new Rectangle(0, 0, fileSize, fileSize); BitmapData imgData = b.LockBits(rect, ImageLockMode.WriteOnly, b.PixelFormat); Bitmap refImage = (Bitmap)b.Clone(); BitmapData refData = refImage.LockBits(rect, ImageLockMode.ReadOnly, refImage.PixelFormat); List<Point> list = generateBallMask(radius); int border = (int)outerCircleTopLeft; for (int j = border; j < fileSize - border; j++) { for (int k = border; k < fileSize - border; k++) { if (!isBlack(refData, j, k)) { int tot = countNonPixels(refData, j, k, false, list); if (tot > list.Count / 2) { *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4)) = 0; *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 1) = 0; *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 2) = 0; *((byte*)(imgData.Scan0 + k * imgData.Stride + j * 4) + 3) = 255; } } } } refImage.UnlockBits(refData); refImage.Dispose(); b.UnlockBits(imgData); } public void smoothBitmap(ref Bitmap b) { Rectangle rect = new Rectangle(0, 0, fileSize, fileSize); BitmapData imgData = b.LockBits(rect, ImageLockMode.WriteOnly, b.PixelFormat); Bitmap refImage = (Bitmap)b.Clone(); BitmapData refData = refImage.LockBits(rect, ImageLockMode.ReadOnly, refImage.PixelFormat); for (int i = 0; i < b.Width; i++) { for (int j = 0; j < b.Height; j++) { if (Math.Sqrt((i - b.Width / 2) * (i - b.Width / 2) + (j - b.Height / 2) * (j - b.Height / 2)) < b.Width / 2 - outerCircleTopLeft - 10) { if (isBlack(refData, i, j)) { bool hasWhite = false; int total = 0; int maskRad = 1; for (int n1 = -maskRad; n1 < maskRad + 1; n1++) { for (int n2 = -maskRad; n2 < maskRad + 1; n2++) { if ((isWhite(refData, i + n1, j + n2)) && (Math.Abs(n1 + n2) <2)) hasWhite = true; total += readPix(refData, i + n1, j + n2); } } if (hasWhite) { *((byte*)(imgData.Scan0 + j * imgData.Stride + i * 4)) = (byte)((double)total / ((maskRad * 2 + 1) * (maskRad * 2 + 1))); *((byte*)(imgData.Scan0 + j * imgData.Stride + i * 4) + 1) = (byte)((double)total / ((maskRad * 2 + 1) * (maskRad * 2 + 1))); *((byte*)(imgData.Scan0 + j * imgData.Stride + i * 4) + 2) = (byte)((double)total / ((maskRad * 2 + 1) * (maskRad * 2 + 1))); *((byte*)(imgData.Scan0 + j * imgData.Stride + i * 4) + 3) = 255; } } } } } b.UnlockBits(imgData); refImage.UnlockBits(refData); refImage.Dispose(); } public int countNonPixels(BitmapData bd, int x, int y, bool nonBlack, List<Point> list) { int tot = 0; for (int i = 0; i < list.Count; i++) { if (nonBlack) // count non-black pixels { if (!isBlack(bd, x + list[i].X, y + list[i].Y)) tot++; } else { if (!isWhite(bd, x + list[i].X, y + list[i].Y)) tot++; } } return tot; } public List<Point> generateBallMask(int r) { List<Point> maskList = new List<Point>(); for (int i = -r; i <= r; i++) { for (int j = -r; j <= r; j++) { if ((i == 0) && (j == 0)) continue; if (i * i + j * j <= r * r) maskList.Add(new Point(i, j)); } } return maskList; } //BGRA public bool isWhite(BitmapData bd, int x, int y) { byte* b = (byte*)bd.Scan0 + y * bd.Stride + x * 4; if ((*(b) != 255) || (*(b + 1) != 255) || (*(b + 2) != 255)) return false; else return true; } public bool isBlack(BitmapData bd, int x, int y) { byte* b = (byte*)bd.Scan0 + y * bd.Stride + x * 4; if ((*(b) != 0) || (*(b + 1) != 0) || (*(b + 2) != 0)) return false; else return true; } public int readPix(BitmapData bd, int x, int y) { byte* b = (byte*)bd.Scan0 + y * bd.Stride + x * 4; return (int)(*(b)); } public void readCodeList() { codes = new List<List<byte>>(); StreamReader sr = new StreamReader("HD" + HD.ToString() + ".txt"); while(true) { String s = sr.ReadLine(); if (s == null) { break; } List<byte> line = new List<byte>(); for (int j = 0; j < noOfBits; j++) { line.Add((byte)(Convert.ToInt32(s[j]) - 48)); } codes.Add(line); } } public void displayBitmap(ref Bitmap b, String title){ if(drawSteps){ Form form = new Form(); form.Text = title; form.WindowState = FormWindowState.Maximized; PictureBox pictureBox = new PictureBox(); pictureBox.Image = b; pictureBox.Dock = DockStyle.Fill; form.Controls.Add(pictureBox); Application.Run(form); } } } public class doublePoint { public double x, y; public doublePoint(double inpX, double inpY) { x = inpX; y = inpY; } }; }
Editor is loading...