The scripts which have been used to try and figure out a license plate from some IR over-illuminated shots. Full blog post on https://corstianboerman.com.
void Main() | |
{ | |
StreamReader csvreader = new StreamReader(@"C:\Documents\subset.csv"); | |
var font = new Font("kenteken", 300, FontStyle.Regular, GraphicsUnit.Pixel, 0x00); | |
Dictionary<String, double[]> results = new Dictionary<String, double[]>(); | |
var reference = new Bitmap(@"C:\Documents\reference.bmp"); | |
var normalizedRef = Normalize(reference); | |
var lines = csvreader.ReadToEnd().Split('\r', '\n').Where(q => !String.IsNullOrWhiteSpace(q)); | |
foreach (var line in lines) | |
{ | |
var license = line.Split(',')[0]; | |
var image = DrawText(license, font, Color.Black, Color.FromArgb(209, 178, 36)); | |
results.Add(license, Normalize(ResizeImage(image, 13, 3))); | |
} | |
List<double[]> nextCluster = new List<double[]>(results.Select(q => q.Value)); | |
var resultingClusterSize = 5000; | |
KMeans cluster = null; | |
int labelToLookFor = 0; | |
while (resultingClusterSize > 10) | |
{ | |
var clusterData = nextCluster.ToArray(); | |
cluster = new KMeans(2) | |
{ | |
// MaxIterations = resultingClusterSize | |
}; | |
KMeansClusterCollection clusters = cluster.Learn(clusterData); | |
int[] labels = clusters.Decide(clusterData); | |
var d1 = Distance.SquareEuclidean(cluster.Centroids[0], normalizedRef); | |
var d2 = Distance.SquareEuclidean(cluster.Centroids[1], normalizedRef); | |
labelToLookFor = labels[d1 > d2 ? 0 : 1]; | |
nextCluster.Clear(); | |
for (var label = 0; label < labels.Length; label++) | |
{ | |
if (labels[label] == labelToLookFor) | |
{ | |
nextCluster.Add(clusterData[label]); | |
} | |
} | |
resultingClusterSize = nextCluster.Count(); | |
} | |
nextCluster.Dump(); | |
foreach (var c in nextCluster) { | |
var dictItem = results.FirstOrDefault(q => q.Value == c); | |
var distance = Distance.SquareEuclidean(dictItem.Value, cluster.Centroids[labelToLookFor]); | |
var origin = Distance.SquareEuclidean(dictItem.Value, normalizedRef); | |
$"lic: {dictItem.Key}, dstC: {distance}, dstN: {origin}".Dump(); | |
dictItem.Value.Dump(); | |
} | |
} | |
public double[] Normalize(Bitmap bmp) | |
{ | |
var array = new byte[bmp.Width * bmp.Height]; | |
for (var y = 0; y < bmp.Height; y++) | |
{ | |
for (var x = 0; x < bmp.Width; x++) | |
{ | |
array[(y * bmp.Width) + x] = bmp.GetPixel(x, y).B; | |
} | |
} | |
var min = array.Min(); | |
var max = array.Max(); | |
double[] result = new double[array.Length]; | |
for (var i = 0; i < array.Length; i++) | |
{ | |
result[i] = MinMax(array[i], max, min, 0x00, 0xFF); | |
} | |
return result; | |
} | |
public double MinMax(byte x, byte max, byte min, byte newMax, byte newMin) | |
{ | |
return ((x - min) * (newMax - newMin) / (max - min) + newMin); | |
} | |
public static byte[] ImageToByte(Image img) | |
{ | |
ImageConverter converter = new ImageConverter(); | |
return (byte[])converter.ConvertTo(img, typeof(byte[])); | |
} | |
private Image DrawText(String text, Font font, Color textColor, Color backColor) | |
{ | |
//first, create a dummy bitmap just to get a graphics object | |
Image img = new Bitmap(1, 1); | |
Graphics drawing = Graphics.FromImage(img); | |
//measure the string to see how big the image needs to be | |
SizeF textSize = drawing.MeasureString(text, font); | |
//free up the dummy image and old graphics object | |
img.Dispose(); | |
drawing.Dispose(); | |
//create a new image of the right size | |
img = new Bitmap((int)textSize.Width, (int)textSize.Height); | |
drawing = Graphics.FromImage(img); | |
//paint the background | |
drawing.Clear(backColor); | |
//create a brush for the text | |
Brush textBrush = new SolidBrush(textColor); | |
drawing.DrawString(text, font, textBrush, 0, 0); | |
drawing.Save(); | |
textBrush.Dispose(); | |
drawing.Dispose(); | |
return img; | |
} | |
/// <summary> | |
/// Resize the image to the specified width and height. | |
/// </summary> | |
/// <param name="image">The image to resize.</param> | |
/// <param name="width">The width to resize to.</param> | |
/// <param name="height">The height to resize to.</param> | |
/// <returns>The resized image.</returns> | |
public static Bitmap ResizeImage(Image image, int width, int height) | |
{ | |
var destRect = new Rectangle(0, 0, width, height); | |
var destImage = new Bitmap(width, height); | |
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); | |
using (var graphics = Graphics.FromImage(destImage)) | |
{ | |
graphics.CompositingMode = CompositingMode.SourceCopy; | |
graphics.CompositingQuality = CompositingQuality.HighQuality; | |
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; | |
graphics.SmoothingMode = SmoothingMode.HighQuality; | |
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; | |
using (var wrapMode = new ImageAttributes()) | |
{ | |
wrapMode.SetWrapMode(WrapMode.TileFlipXY); | |
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); | |
} | |
} | |
return destImage; | |
} |
// First a script to filter the list containing all license plates | |
StreamReader csvreader = new StreamReader(@"C:\Downloads\Open_Data_RDW__Gekentekende_voertuigen.csv"); | |
string inputLine = ""; | |
List<string> results = new List<string>(); | |
var lowerDate = DateTime.Parse("01-01-2010"); | |
var upperDate = DateTime.Parse("01-01-2016"); | |
csvreader.ReadLine(); | |
while ((inputLine = csvreader.ReadLine()) != null) | |
{ | |
try | |
{ | |
string[] row = inputLine.Split(new char[] { ',' }); | |
var license = row[0]; | |
var carType = row[1]; | |
if (carType != "Personenauto") continue; | |
var brand = row[2]; | |
if (brand != "CITROEN") continue; | |
var brandType = row[3]; | |
if (brandType != "C4") continue; | |
var APK = DateTime.Parse(row[4]); | |
if (APK < DateTime.UtcNow) continue; | |
var doorCount = Int32.Parse(row[32]); | |
if (doorCount != 4) continue; | |
var firstDateAccepted = DateTime.Parse(row[20]); | |
if (firstDateAccepted > lowerDate && firstDateAccepted < upperDate) | |
{ | |
results.Add(inputLine); | |
} | |
} catch { | |
} | |
} | |
results.Dump(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment