public bool Adjacent(Letter l) { foreach (Point p in l.Pixels) { if (Adjacent(p)) { return true; } } return false; }
public bool MergePixels(Letter l, Bitmap image) { // find out resulting width, if too great abort merge int min = MinX < l.MinX ? MinX : l.MinX; int max = MaxX > l.MaxX ? MaxX : l.MaxX; if (max - min + 1 > MAX_LETTER_WIDTH) { return false; } MinX = min; MaxX = max; MinY = MinY < l.MinY ? MinY : l.MinY; MaxY = MaxY > l.MaxY ? MaxY : l.MaxY; // add all of the pixels of the merged letter pixels.AddRange(l.Pixels); // change their color /*foreach (Point p in l.Pixels) { image.SetPixel(p.X, p.Y, Color); }*/ return true; }
private Bitmap Captcha() { Bitmap image = new Bitmap(Image.FromFile(file)); List<Letter> toRemove = new List<Letter>(); for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width; x++) { Color c = image.GetPixel(x, y); if (c.R < 70 && c.G < 70 && c.B < 70) { image.SetPixel(x, y, Color.FromArgb(255, 255, 0, 0)); } else if (c.R < 163 && c.G < 163 && c.B < 163) { //image.SetPixel(x, y, Color.FromArgb(255, 0, 255, 0)); // check if point is adjacent to any of the points in the existing letters Point p = new Point(x, y); int letter = -1; List<int> close = new List<int>(); for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) continue; string key = (x + i) + "," + (y + j); if (dic.ContainsKey(key)) { if (letter != -1 && letter != dic[key]) { close.Add(dic[key]); continue; } letter = dic[key]; } } } if (letter == -1) { // add new letter Letter l = new Letter(); l.MinX = p.X; l.MaxX = p.X; l.MinY = p.Y; l.MaxY = p.Y; l.Pixels.Add(p); dic[p.X + "," + p.Y] = letters.Count; //l.Color = cols[letters.Count % cols.Length]; //image.SetPixel(x, y, l.Color); letters.Add(l); continue; } if (p.X < letters[letter].MinX) letters[letter].MinX = p.X; if (p.Y < letters[letter].MinY) letters[letter].MinY = p.Y; if (p.X > letters[letter].MaxX) letters[letter].MaxX = p.X; if (p.Y > letters[letter].MaxY) letters[letter].MaxY = p.Y; letters[letter].Pixels.Add(p); dic[p.X + "," + p.Y] = letter; // merge all other nearby letters with this one foreach (int l in close) { if (letters[letter].MergePixels(letters[l], image)) { toRemove.Add(letters[l]); foreach (Point pp in letters[l].Pixels) { dic[pp.X + "," + pp.Y] = letter; } } } } } } foreach (Letter l in toRemove) { letters.Remove(l); } // complexity: O(n) // min: 151ms, max: 245ms, avg: 177.147058823529ms Random r = new Random((int)(DateTime.Now.Ticks / 1000)); // highlight each individual letter by assigning a separate color for (int i = 0; i < letters.Count; i++) { letters[i].Color = Color.FromArgb(255, (r.Next(0, 255) + i * 2) % 255, (r.Next(0, 255) + i * 3) % 255, (r.Next(0, 255) + i * 5) % 255); //cols[i%cols.Length]; foreach (Point p in letters[i].Pixels) { image.SetPixel(p.X, p.Y, letters[i].Color); } } // draw the whole text image Invoke(new MethodInvoker(delegate { Graphics g = Graphics.FromHwnd(Handle); // real graphics g.DrawImage(image, 540, 80); g.Dispose(); })); /* for (int i = 0; i < letters.Count; i++) { // create new image containing just this letter, white on black Image single = letters[i].CreateImage(); // prompt user to read letter, if 'bad' is inputted, letter was not properly recognized Invoke(new MethodInvoker(delegate { Graphics g = Graphics.FromHwnd(Handle); // real graphics g.DrawImage(new Bitmap(100, 40, PixelFormat.Format24bppRgb), 540, 30); g.DrawImage(single, 540, 30); g.Dispose(); textBox2.Text = ""; textBox2.Enabled = true; textBox2.Focus(); })); while (textBox2.Enabled) { Thread.Sleep(100); } // save individual letter to jpg file if (textBox2.Text.ToLower() != "bad") { if (!Directory.Exists(LETTER_PATH + textBox2.Text)) { Directory.CreateDirectory(LETTER_PATH + textBox2.Text); } for (int j = 0; ; j++) { if (File.Exists(LETTER_PATH + textBox2.Text + "\\" + j + ".jpg")) continue; single.Save(LETTER_PATH + textBox2.Text + "\\" + j + ".jpg"); break; } } } */ return image; }