public void Scale(TemplateBuilder template)
 {
     float dpiFactor = 500 / (float)DpiScaling;
     foreach (var minutia in template.Minutiae)
         minutia.Position = Calc.Round(Calc.Multiply(dpiFactor, minutia.Position));
     Logger.Log(template);
 }
Example #2
0
 public void Shuffle(TemplateBuilder template)
 {
     int seed = 0;
     foreach (var minutia in template.Minutiae)
         seed += minutia.Direction + minutia.Position.X + minutia.Position.Y + (int)minutia.Type;
     template.Minutiae = Calc.Shuffle(template.Minutiae, new Random(seed)).ToList();
 }
 public void Filter(TemplateBuilder template)
 {
     var radiusSq = Calc.Sq(NeighborhoodRadius);
     template.Minutiae = template.Minutiae.Except(
         (from minutia in template.Minutiae
          where template.Minutiae.Count(neighbor => Calc.DistanceSq(neighbor.Position, minutia.Position) <= radiusSq) - 1 > MaxNeighbors
          select minutia).ToList()).ToList();
     Logger.Log(template);
 }
Example #4
0
        public TemplateBuilder ToTemplateBuilder()
        {
            TemplateBuilder builder = new TemplateBuilder();

            builder.OriginalDpi = OriginalDpi;
            builder.OriginalWidth = OriginalWidth;
            builder.OriginalHeight = OriginalHeight;

            foreach (Minutia minutia in Minutiae)
                builder.Minutiae.Add(minutia.ToBuilderMinutia());
            return builder;
        }
Example #5
0
        public Template(TemplateBuilder builder)
        {
            OriginalDpi = builder.OriginalDpi;
            OriginalWidth = builder.OriginalWidth;
            OriginalHeight = builder.OriginalHeight;
            StandardDpiWidth = builder.StandardDpiWidth;
            StandardDpiHeight = builder.StandardDpiHeight;

            Minutiae = new Minutia[builder.Minutiae.Count];
            for (int i = 0; i < builder.Minutiae.Count; ++i)
                Minutiae[i] = new Minutia(builder.Minutiae[i]);
        }
Example #6
0
 public Minutia(TemplateBuilder.Minutia builderMinutia)
 {
     Position = new PointS(builderMinutia.Position);
     Direction = builderMinutia.Direction;
     switch (builderMinutia.Type)
     {
         case TemplateBuilder.MinutiaType.Ending: Type = MinutiaType.Ending; break;
         case TemplateBuilder.MinutiaType.Bifurcation: Type = MinutiaType.Bifurcation; break;
         case TemplateBuilder.MinutiaType.Other: Type = MinutiaType.Other; break;
         default: throw new ApplicationException();
     }
 }
 public void Filter(TemplateBuilder template)
 {
     if (template.Minutiae.Count > MaxMinutiae)
     {
         template.Minutiae =
             (from minutia in template.Minutiae
              let radiusSq = (from neighbor in template.Minutiae
                              let distanceSq = Calc.DistanceSq(minutia.Position, neighbor.Position)
                              orderby distanceSq
                              select distanceSq).Skip(NeighborhoodSize).First()
              orderby radiusSq descending
              select minutia).Take(MaxMinutiae).ToList();
     }
     Logger.Log(template);
 }
Example #8
0
        public override TemplateBuilder Import(XElement template)
        {
            int version = (int)template.Attribute("Version");

            if (version < 1 || version > 2)
            {
                throw new ApplicationException("Unknown template version.");
            }
            TemplateBuilder builder = new TemplateBuilder()
            {
                Minutiae = (from minutia in template.Elements("Minutia")
                            select new TemplateBuilder.Minutia()
                {
                    Position = new Point(
                        (int)minutia.Attribute("X"),
                        (int)minutia.Attribute("Y")),
                    Direction = (byte)(uint)minutia.Attribute("Direction"),
                    Type = (TemplateBuilder.MinutiaType)Enum.Parse(
                        typeof(TemplateBuilder.MinutiaType),
                        (string)minutia.Attribute("Type"),
                        false)
                }).ToList()
            };

            if (version >= 2)
            {
                builder.OriginalDpi    = (int)template.Attribute("OriginalDpi");
                builder.OriginalWidth  = (int)template.Attribute("OriginalWidth");
                builder.OriginalHeight = (int)template.Attribute("OriginalHeight");
            }
            else
            {
                builder.OriginalDpi       = 500;
                builder.StandardDpiWidth  = template.Elements("Minutia").Max(e => (int)e.Attribute("X")) + 1;
                builder.StandardDpiHeight = template.Elements("Minutia").Max(e => (int)e.Attribute("Y")) + 1;
            }
            return(builder);
        }
Example #9
0
 public abstract T Export(TemplateBuilder builder);
Example #10
0
 public byte[] SerializeBuilder(TemplateBuilder builder)
 {
     return(Serialize(Export(builder)));
 }
Example #11
0
 public override Template Export(TemplateBuilder builder)
 {
     return(new Template(builder));
 }
Example #12
0
        public TemplateBuilder Extract(byte[,] invertedImage, int dpi)
        {
            TemplateBuilder template = null;
            DpiAdjuster.Adjust(this, dpi, delegate()
            {
                byte[,] image = ImageInverter.GetInverted(invertedImage);

                BlockMap blocks = new BlockMap(new Size(image.GetLength(1), image.GetLength(0)), BlockSize);
                Logger.Log("BlockMap", blocks);

                short[, ,] histogram = Histogram.Analyze(blocks, image);
                short[, ,] smoothHistogram = Histogram.SmoothAroundCorners(blocks, histogram);
                BinaryMap mask = Mask.ComputeMask(blocks, histogram);
                float[,] equalized = Equalizer.Equalize(blocks, image, smoothHistogram, mask);

                byte[,] orientation = Orientation.Detect(equalized, mask, blocks);
                float[,] smoothed = RidgeSmoother.Smooth(equalized, orientation, mask, blocks);
                float[,] orthogonal = OrthogonalSmoother.Smooth(smoothed, orientation, mask, blocks);

                BinaryMap binary = Binarizer.Binarize(smoothed, orthogonal, mask, blocks);
                binary.AndNot(BinarySmoother.Filter(binary.GetInverted()));
                binary.Or(BinarySmoother.Filter(binary));
                Logger.Log("BinarySmoothingResult", binary);
                CrossRemover.Remove(binary);

                BinaryMap pixelMask = mask.FillBlocks(blocks);
                BinaryMap innerMask = InnerMask.Compute(pixelMask);

                BinaryMap inverted = binary.GetInverted();
                inverted.And(pixelMask);

                SkeletonBuilder ridges = null;
                SkeletonBuilder valleys = null;
                Parallel.Invoke(
                    () => { ridges = ProcessSkeleton("Ridges", binary); },
                    () => { valleys = ProcessSkeleton("Valleys", inverted); });

                template = new TemplateBuilder();
                template.OriginalDpi = dpi;
                template.OriginalWidth = invertedImage.GetLength(1);
                template.OriginalHeight = invertedImage.GetLength(0);

                MinutiaCollector.Collect(ridges, TemplateBuilder.MinutiaType.Ending, template);
                MinutiaCollector.Collect(valleys, TemplateBuilder.MinutiaType.Bifurcation, template);
                MinutiaMask.Filter(template, innerMask);
                StandardDpiScaling.Scale(template);
                MinutiaCloudRemover.Filter(template);
                UniqueMinutiaSorter.Filter(template);
                MinutiaSorter.Shuffle(template);
                Logger.Log("FinalTemplate", template);
            });
            return template;
        }
Example #13
0
        // References:
        // http://www.italdata-roma.com/PDF/Norme%20ISO-IEC%20Minutiae%20Data%20Format%2019794-2.pdf
        // https://biolab.csr.unibo.it/fvcongoing/UI/Form/Download.aspx (ISO section, sample ZIP, ISOTemplate.pdf)
        //
        // Format (all numbers are big-endian):
        // 4B magic "FMR\0"
        // 4B version (ignored, set to " 20\0"
        // 4B total length (including header)
        // 2B rubbish (zeroed)
        // 2B image size in pixels X
        // 2B image size in pixels Y
        // 2B rubbish (pixels per cm X, set to 196 = 500dpi)
        // 2B rubbish (pixels per cm Y, set to 196 = 500dpi)
        // 1B rubbish (number of fingerprints, set to 1)
        // 1B rubbish (zeroed)
        // 1B rubbish (finger position, zeroed)
        // 1B rubbish (zeroed)
        // 1B rubbish (fingerprint quality, set to 100)
        // 1B minutia count
        // N*6B minutiae
        //      2B minutia position X in pixels
        //          2b (upper) minutia type (01 ending, 10 bifurcation, 00 other)
        //      2B minutia position Y in pixels (upper 2b ignored, zeroed)
        //      1B direction, compatible with SourceAFIS angles
        //      1B quality (ignored, zeroed)
        // 2B rubbish (extra data length, zeroed)
        // N*1B rubbish (extra data)

        public override byte[] Export(TemplateBuilder builder)
        {
            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8);

            checked
            {
                // 4B magic "FMR\0"
                writer.Write("FMR\0".ToCharArray());

                // 4B version (ignored, set to " 20\0"
                writer.Write(" 20\0".ToCharArray());

                // 4B total length (including header, will be updated later)
                writer.Write(0);

                // 2B rubbish (zeroed)
                writer.Write((short)0);

                // 2B image size in pixels X
                writer.Write(IPAddress.HostToNetworkOrder((short)builder.StandardDpiWidth));

                // 2B image size in pixels Y
                writer.Write(IPAddress.HostToNetworkOrder((short)builder.StandardDpiHeight));

                // 2B rubbish (pixels per cm X, set to 196 = 500dpi)
                writer.Write(IPAddress.HostToNetworkOrder((short)196));

                // 2B rubbish (pixels per cm Y, set to 196 = 500dpi)
                writer.Write(IPAddress.HostToNetworkOrder((short)196));

                // 1B rubbish (number of fingerprints, set to 1)
                writer.Write((byte)1);

                // 1B rubbish (zeroed)
                writer.Write((byte)0);

                // 1B rubbish (finger position, zeroed)
                writer.Write((byte)0);

                // 1B rubbish (zeroed)
                writer.Write((byte)0);

                // 1B rubbish (fingerprint quality, set to 100)
                writer.Write((byte)100);

                // 1B minutia count
                writer.Write((byte)builder.Minutiae.Count);

                // N*6B minutiae
                foreach (var minutia in builder.Minutiae)
                {
                    //      2B minutia position X in pixels
                    //          2b (upper) minutia type (01 ending, 10 bifurcation, 00 other (considered ending))
                    int x = minutia.Position.X;
                    AssertException.Check(x <= 0x3fff, "X position is out of range");
                    int type;
                    switch (minutia.Type)
                    {
                    case TemplateBuilder.MinutiaType.Ending: type = 0x4000; break;

                    case TemplateBuilder.MinutiaType.Bifurcation: type = 0x8000; break;

                    case TemplateBuilder.MinutiaType.Other: type = 0; break;

                    default: throw new ApplicationException();
                    }
                    writer.Write(IPAddress.HostToNetworkOrder(unchecked ((short)(x | type))));

                    //      2B minutia position Y in pixels (upper 2b ignored, zeroed)
                    int y = builder.StandardDpiHeight - minutia.Position.Y - 1;
                    AssertException.Check(y <= 0x3fff, "Y position is out of range");
                    writer.Write(IPAddress.HostToNetworkOrder((short)y));

                    //      1B direction, compatible with SourceAFIS angles
                    writer.Write(minutia.Direction);

                    //      1B quality (ignored, zeroed)
                    writer.Write((byte)0);
                }

                // 2B rubbish (extra data length, zeroed)
                // N*1B rubbish (extra data)
                writer.Write((short)0);
            }

            writer.Dispose();

            // update length
            byte[] template = stream.ToArray();
            BitConverter.GetBytes(IPAddress.HostToNetworkOrder(template.Length)).CopyTo(template, 8);

            return(template);
        }
Example #14
0
        public override TemplateBuilder Import(byte[] template)
        {
            TemplateBuilder builder = new TemplateBuilder();

            builder.OriginalDpi = 500;

            MemoryStream stream = new MemoryStream(template);
            BinaryReader reader = new BinaryReader(stream, Encoding.UTF8);

            // 4B magic "FMR\0"
            AssertException.Check(new String(reader.ReadChars(4)) == "FMR\0", "This is not an ISO template.");

            // 4B version (ignored, set to " 20\0"
            reader.ReadChars(4);

            // 4B total length (including header)
            AssertException.Check(IPAddress.NetworkToHostOrder(reader.ReadInt32()) == template.Length, "Invalid template length.");

            // 2B rubbish (zeroed)
            reader.ReadInt16();

            // 2B image size in pixels X
            builder.StandardDpiWidth = IPAddress.NetworkToHostOrder(reader.ReadInt16());

            // 2B image size in pixels Y
            builder.StandardDpiHeight = IPAddress.NetworkToHostOrder(reader.ReadInt16());

            // 2B rubbish (pixels per cm X, set to 196 = 500dpi)
            reader.ReadInt16();

            // 2B rubbish (pixels per cm Y, set to 196 = 500dpi)
            reader.ReadInt16();

            // 1B rubbish (number of fingerprints, set to 1)
            AssertException.Check(reader.ReadByte() == 1, "Only single-fingerprint ISO templates are supported.");

            // 1B rubbish (zeroed)
            reader.ReadByte();

            // 1B rubbish (finger position, zeroed)
            reader.ReadByte();

            // 1B rubbish (zeroed)
            reader.ReadByte();

            // 1B rubbish (fingerprint quality, set to 100)
            reader.ReadByte();

            // 1B minutia count
            int minutiaCount = reader.ReadByte();

            // N*6B minutiae
            for (int i = 0; i < minutiaCount; ++i)
            {
                TemplateBuilder.Minutia minutia = new TemplateBuilder.Minutia();

                //      2B minutia position X in pixels
                //          2b (upper) minutia type (01 ending, 10 bifurcation, 00 other (considered ending))
                ushort xPacked = (ushort)IPAddress.NetworkToHostOrder(reader.ReadInt16());
                minutia.Position.X = xPacked & (ushort)0x3fff;
                switch (xPacked & (ushort)0xc000)
                {
                case 0x4000: minutia.Type = TemplateBuilder.MinutiaType.Ending; break;

                case 0x8000: minutia.Type = TemplateBuilder.MinutiaType.Bifurcation; break;

                case 0: minutia.Type = TemplateBuilder.MinutiaType.Other; break;

                default: throw new ApplicationException();
                }

                //      2B minutia position Y in pixels (upper 2b ignored, zeroed)
                minutia.Position.Y = builder.StandardDpiHeight - 1 - ((ushort)IPAddress.NetworkToHostOrder(reader.ReadInt16()) & (ushort)0x3fff);

                //      1B direction, compatible with SourceAFIS angles
                minutia.Direction = reader.ReadByte();

                //      1B quality (ignored, zeroed)
                reader.ReadByte();

                builder.Minutiae.Add(minutia);
            }

            // 2B rubbish (extra data length, zeroed)
            // N*1B rubbish (extra data)

            return(builder);
        }
Example #15
0
        public TemplateBuilder Extract(byte[,] invertedImage, int dpi)
        {
            TemplateBuilder template = null;
            DpiAdjuster.Adjust(this, dpi, delegate ()
            {
                byte[,] image = ImageInverter.GetInverted(invertedImage);

                BlockMap blocks = new BlockMap(new Size(image.GetLength(1), image.GetLength(0)), BlockSize);
                Logger.Log("BlockMap", blocks);
                //Testing Start
                var outFileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "bloackMapOut" + DateTime.Now.Second + ".bin");
                var outFileText = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
                    "blockMapTextOut" + DateTime.Now.Second + ".txt");
                var file = new FileStream(outFileDir, FileMode.CreateNew);
                var binWrite = new BinaryWriter(file);
                TextWriter tw = new StreamWriter(outFileText);
                LogSize(blocks.PixelCount, binWrite, tw, "PixelCount");
                LogSize(blocks.BlockCount, binWrite, tw, "BlockCount");
                LogSize(blocks.CornerCount, binWrite, tw, "CornerCount");
                LogRectangleC(blocks.AllBlocks, binWrite, tw, "AllBlocks");
                LogRectangleC(blocks.AllCorners, binWrite, tw, "AllCorners");
                LogPointGrid(blocks.Corners, binWrite, tw, "Corners");
                LogRectangleGrid(blocks.BlockAreas, binWrite, tw, "BlockAreas");
                LogPointGrid(blocks.BlockCenters, binWrite, tw, "BlockCenters");
                LogRectangleGrid(blocks.CornerAreas, binWrite, tw, "CornerAreas");
                binWrite.Close();
                tw.Close();
                //Testing End

                short[,,] histogram = Histogram.Analyze(blocks, image);
                ////testing
                //var outFileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "histogramImageInput" + ".bin");
                //var file = new FileStream(outFileDir, FileMode.CreateNew);
                //var binWrite = new BinaryWriter(file);
                //binWrite.Write(image.GetLength(0));
                //binWrite.Write(image.GetLength(1));
                //for (var i = 0; i < image.GetLength(0); i++)
                //{
                //    for (var j = 0; j < image.GetLength(1); j++)
                //    {
                //        binWrite.Write(image[i, j]);
                //    }
                //}
                //binWrite.Close();
                ////End testing

                ////Testing Start
                //Count++;
                //var outFileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "histogramOut" + Count + ".bin");
                //var outFileText = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
                //    "histogramTextOut" + Count + ".txt");
                //var file = new FileStream(outFileDir, FileMode.CreateNew);
                //var binWrite = new BinaryWriter(file);
                //TextWriter tw = new StreamWriter(outFileText);
                //binWrite.Write(histogram.GetLength(0));
                //tw.WriteLine(histogram.GetLength(0));
                //binWrite.Write(histogram.GetLength(1));
                //tw.WriteLine(histogram.GetLength(1));
                //binWrite.Write(histogram.GetLength(2));
                //tw.WriteLine(histogram.GetLength(2));
                //for (var i = 0; i < histogram.GetLength(0); i++)
                //{
                //    for (var j = 0; j < histogram.GetLength(1); j++)
                //    {
                //        for (var k = 0; k < histogram.GetLength(2); k++)
                //        {
                //            binWrite.Write(histogram[i, j, k]);
                //            tw.WriteLine(histogram[i, j, k]);
                //        }
                //    }
                //}
                //binWrite.Close();
                //file.Close();
                //tw.Close();
                //Testing Finish

                //Testing Start
                //outFileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "bloackMapOutPostHis" + DateTime.Now.Second + ".bin");
                //outFileText = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
                //   "blockMapTextOutPostHis" + DateTime.Now.Second + ".txt");
                //file = new FileStream(outFileDir, FileMode.CreateNew);
                //binWrite = new BinaryWriter(file);
                //tw = new StreamWriter(outFileText);
                //LogSize(blocks.PixelCount, binWrite, tw);
                //LogSize(blocks.BlockCount, binWrite, tw);
                //LogSize(blocks.CornerCount, binWrite, tw);
                //LogRectangleC(blocks.AllBlocks, binWrite, tw);
                //LogRectangleC(blocks.AllCorners, binWrite, tw);
                //LogPointGrid(blocks.Corners, binWrite, tw);
                //LogRectangleGrid(blocks.BlockAreas, binWrite, tw);
                //LogPointGrid(blocks.BlockCenters, binWrite, tw);
                //LogRectangleGrid(blocks.CornerAreas, binWrite, tw);
                //binWrite.Close();
                //tw.Close();
                //Testing End

                short[,,] smoothHistogram = Histogram.SmoothAroundCorners(blocks, histogram);
                BinaryMap mask = Mask.ComputeMask(blocks, histogram);
                float[,] equalized = Equalizer.Equalize(blocks, image, smoothHistogram, mask);

                byte[,] orientation = Orientation.Detect(equalized, mask, blocks);
                float[,] smoothed = RidgeSmoother.Smooth(equalized, orientation, mask, blocks);
                float[,] orthogonal = OrthogonalSmoother.Smooth(smoothed, orientation, mask, blocks);

                BinaryMap binary = Binarizer.Binarize(smoothed, orthogonal, mask, blocks);
                binary.AndNot(BinarySmoother.Filter(binary.GetInverted()));
                binary.Or(BinarySmoother.Filter(binary));
                Logger.Log("BinarySmoothingResult", binary);
                CrossRemover.Remove(binary);

                BinaryMap pixelMask = mask.FillBlocks(blocks);
                BinaryMap innerMask = InnerMask.Compute(pixelMask);

                BinaryMap inverted = binary.GetInverted();
                inverted.And(pixelMask);

                SkeletonBuilder ridges = null;
                SkeletonBuilder valleys = null;

                Parallel.Invoke(
                    () => { ridges = ProcessSkeleton("Ridges", binary); },
                    () => { valleys = ProcessSkeleton("Valleys", inverted); });

                template = new TemplateBuilder();
                template.OriginalDpi = dpi;
                template.OriginalWidth = invertedImage.GetLength(1);
                template.OriginalHeight = invertedImage.GetLength(0);

                MinutiaCollector.Collect(ridges, TemplateBuilder.MinutiaType.Ending, template);
                MinutiaCollector.Collect(valleys, TemplateBuilder.MinutiaType.Bifurcation, template);
                MinutiaMask.Filter(template, innerMask);
                StandardDpiScaling.Scale(template);
                MinutiaCloudRemover.Filter(template);
                UniqueMinutiaSorter.Filter(template);
                MinutiaSorter.Shuffle(template);
                Logger.Log("FinalTemplate", template);
            });
            return template;
        }