将多位数的图像分割成仅包含一位的单独图像

时间:2018-09-26 04:38:03

标签: c# image image-processing

我正在尝试将手写数字图像拆分为单独的数字。

考虑一下我有这张图片:

Image to split

我做了一个简单的逻辑就可以了,但是确实可以,但是确实遇到了问题:

private static void SplitImages()
{
    //We're going to use this code once.. to split our own images into seperate images.. can we do this somehow?
    Bitmap testSplitImage = (Bitmap)Bitmap.FromFile("TestSplitImage.jpg");
    int[][] imagePixels = new int[testSplitImage.Width][];
    for(int i=0;i<imagePixels.Length;i++)
    {
        imagePixels[i] = new int[testSplitImage.Height];
    }

    for(int i=0;i<imagePixels.Length;i++)
    {
        for(int j=0;j<imagePixels[i].Length;j++)
        {
            Color c = testSplitImage.GetPixel(i, j);
            imagePixels[i][j] = (c.R + c.G + c.B) / 3;
        }
    }

    //let's start by getting the first height vector... and count how many of them is white..dunno..
    int startColNumber = 0;
    int endColNumber = 0;
    bool isStart = false;
    int imageNumber = 1;

    for(int i=0;i<imagePixels.Length;i++)
    {
        int whiteNumbers = 0;
        for(int j=0;j<imagePixels[i].Length;j++)
        {
            if (imagePixels[i][j] > 200)
            {
                //consider it white or not really relevant
                whiteNumbers++;
            }
        }
        if (whiteNumbers > testSplitImage.Height*95.0/100.0)
        {
            //let's consider that if a height vector has more than 95% white pixels.. it means that we can start checking for an image
            //now if we started checking for the image.. we need to stop
            if (isStart)
            {
                //consider the end of image.. so the end column should be here or we make it +1 at least
                endColNumber = i + 1;
                isStart = false;
            }
        }
        else
        {
            if (!isStart)
            {
                isStart = true; //we will start checking for the image one row before that maybe?
                startColNumber = i == 0 ? i : i - 1;
            }
        }
        if (endColNumber > 0)
        {
            //we got a start and an end.. let's create a new image out of those pixels..hopefully this will work
            Bitmap splittedImage = new Bitmap(endColNumber - startColNumber + 1, testSplitImage.Height);
            int col = 0;
            for(int k=startColNumber;k<=endColNumber;k++)
            {
                for (int l=0;l<testSplitImage.Height;l++)
                {
                    int c = imagePixels[k][l];
                    splittedImage.SetPixel(col, l, Color.FromArgb(c, c, c));
                }
                col++;
            }
            splittedImage.Save($"Image{imageNumber++}.jpg");
            endColNumber = 0;
        }
        whiteNumbers = 0;
    }
}

我确实取得了不错的成绩:

2 1 9

我也得到了三个零:

0-1 0-2 0-3

但是,我也将其作为一张图像得到了:

37

这是一张需要分割的图像样本(主要在4,000张图像中),是最好,最简单的图像之一。我想知道是否有一种方法可以改善我的逻辑,还是应该放弃这种方法并找到其他方法?

1 个答案:

答案 0 :(得分:1)

此代码仅适用于单色(2色,黑白)图像。

 public static class Processor
    {
        public static byte[] ToArray(this Bitmap bmp) // bitmap to byte array using lockbits
        {
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
            BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
            IntPtr ptr = data.Scan0;
            int numBytes = data.Stride * bmp.Height;
            byte[] bytes = new byte[numBytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, numBytes);
            bmp.UnlockBits(data);
            return bytes;
        }


        public static int GetPixel(this byte[] array, int bpr, int x, int y) //find out if the given pixel is 0 or 1
        {
            int num = y * bpr + x / 8;
            return (array[num] >> 7- x%8) & 1;
        }

        public static List<Point> getDrawingPoints(this Point start, byte[] array, int width, int height) // get one 0 point (black point) and find all adjacent black points by traveling neighbors  
        {
            List<Point> points = new List<Point>();
            points.Add(start);
            int BytePerRow = array.Length / bmp.Height;
            int counter = 0;
            do
            {
                for (int i = Math.Max(0, points[counter].X - 1); i <= Math.Min(width - 1, points[counter].X + 1); i++)
                    for (int j = Math.Max(0, points[counter].Y - 1); j <= Math.Min(height - 1, points[counter].Y + 1); j++)
                        if (array.GetPixel(BytePerRow, i, j) == 0 && !points.Any(p => p.X == i && p.Y == j))
                            points.Add(new Point(i, j));
                counter++;
            } while (counter < points.Count);
            return points;
        }
        public static Bitmap ToBitmap(this List<Point> points) // convert points to bitmap
        {

            int startX = points.OrderBy(p => p.X).First().X,
                endX = points.OrderByDescending(p => p.X).First().X,
                startY = points.OrderBy(p => p.Y).First().Y,
                endY = points.OrderByDescending(p => p.Y).First().Y;
            Bitmap bmp = new Bitmap(endX - startX + 1, endY - startY + 1);
            Graphics g = Graphics.FromImage(bmp);
            g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0, 0, endX - startX - 1, endY - startY - 1));
            for (int i = startY; i <= endY; i++)
                for (int j = startX; j <= endX; j++)
                    if (points.Any(p => p.X == j && p.Y == i)) bmp.SetPixel(j - startX, i - startY, Color.Black); 
            return bmp;
        }
    }

并像这样使用它来获取主图像中的所有数字:

 List<Point> processed = new List<Point>();
 Bitmap bmp = ((Bitmap)Bitmap.FromFile(SourceBitmapPath));
 byte[] array = bmp.ToArray();
 int BytePerRow = array.Length / bmp.Height;
 int imgIndex = 1;
 for (int i = 0; i < bmp.Width; i++)
     for (int j = 0; j < bmp.Height; j++)
     {
          if (array.GetPixel(BytePerRow, i, j) == 0 && !processed.Any(p => p.X == i && p.Y == j))
          {
               List<Point> points = new Point(i, j).getDrawingPoints(array, bmp.Width, bmp.Height);
               processed.AddRange(points);
               Bitmap result = points.ToBitmap();
               result.Save($"{imgIndex++}.bmp");
           }

      }

我正在使用绘画和另存为单色bmp格式来生成源图像。

我还使用此图像对其进行了测试: enter image description here

将导致以下三个图像: enter image description here

enter image description here

enter image description here