Untitled
unknown
csharp
5 years ago
22 kB
79
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...