Esempio n. 1
0
 public static void setText(ImagesRenderer renderer, String text)
 {
     if (renderer.IsHandleCreated)
     {
         renderer.BeginInvoke(new SetTextDelegate(renderer.setText), new object[] { text });
     }
 }
Esempio n. 2
0
 public static void repaint(ImagesRenderer renderer)
 {
     if (renderer.IsHandleCreated)
     {
         renderer.BeginInvoke(new Repaint(renderer.repaint), new object[] { });
     }
 }
Esempio n. 3
0
        public static ImagesRenderer newImageRenderer()
        {
            // lock
            EventWaitHandle wait = new AutoResetEvent(false);

            // ui
            ImagesRenderer renderer = null;
            Thread         threadUi = new Thread(delegate()
            {
                renderer = new ImagesRenderer();
                wait.Set();
                Application.Run(renderer);
            });

            threadUi.Start();
            wait.WaitOne();

            // updater
            Thread threadUpdate = new Thread(delegate()
            {
                while (true)
                {
                    Thread.Sleep(500);
                    repaint(renderer);
                }
            });

            threadUpdate.Start();

            return(renderer);
        }
Esempio n. 4
0
 public static void setImage(ImagesRenderer renderer, System.Drawing.Image image)
 {
     if (renderer.IsHandleCreated)
     {
         renderer.BeginInvoke(new SetImageDelegate(renderer.setImage), new object[] { image });
     }
 }
Esempio n. 5
0
        public static void Main(string[] args)
        {
            ImagesRenderer renderer = newImageRenderer();

            // screen + reduce + invert
            Iterator <Image> screenIter = new MockIterator(toImage(new Bitmap("player9.png")));
            //Iterator<Image> screenIter = new ScreenImageIterator(new Rectangle(100, 400, 80, 30));
            Iterator <Image> reduceIter  = new ReduceColorIterator(screenIter, new ColorReducers.TextBox());
            Iterator <Image> invertIter  = new InvertColorIterator(reduceIter, Color.White, Color.Black);
            Iterator <Image> replaceIter = new ReplaceColorIterator(invertIter, Color.White, Color.Transparent);

            // proxy
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(replaceIter);
            ColorReplacer         replacer  = new ColorReplacer(Color.Transparent, Color.Cyan);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(replacer.replace(next)));
            };

            // partition + decompose + crop
            Iterator <List <List <Image> > > patitionIter  = new ImageHoriPartitionIterator(proxyIter);
            Iterator <List <List <Image> > > decomposeIter = new DecomposeImageIterator(patitionIter);
            Iterator <List <List <Image> > > cropIter      = new CropImageIterator(decomposeIter);

            // hash
            HashSet <HashImage> hashImages = new HashSet <HashImage>();
            int count = 0;

            while (cropIter.hasNext())
            {
                List <List <Image> > images = cropIter.next();
                foreach (List <Image> line in images)
                {
                    foreach (Image image in line)
                    {
                        // dimensions
                        if (!hasDimensions(image))
                        {
                            continue;
                        }

                        // hash
                        HashImage hash = new HashImage(image);
                        if (!hashImages.Contains(hash))
                        {
                            hashImages.Add(hash);
                            System.Drawing.Image bitmap = toBitmap(image);
                            addImage(renderer, bitmap);
                            Console.WriteLine("Saving image " + count++);
                            saveBitmap("char", uniqueId(hash), bitmap);
                        }
                    }
                }
            }
        }
Esempio n. 6
0
        public static void Main(string[] args)
        {
            Log.SetLevel(Log.Level.FINEST);

            // patterns
            List <CardPattern> patterns = CardReader.readCardsFromResources();

            Console.WriteLine("read " + patterns.Count + " candidate patterns");

            // renderer
            ImagesRenderer renderer = newImageRenderer();

            // iterator
            Iterator <Image> wait;

            if (USE_SCREEN)
            {
                Thread.Sleep(10);
                TableContainer   table  = new BotAppLogic(new Win32Control()).LocateNewTable(new Settings());
                Rectangle        rect   = new Rectangle(table.Layout.Offset.X, table.Layout.Offset.Y, table.Layout.Size.Width, table.Layout.Size.Height);
                Iterator <Image> screen = new ScreenImageIterator(new Win32Control(), rect);
                wait = new WaitDeltaImageIterator(screen);
            }
            else
            {
                wait = new MockIterator(toImage(new Bitmap("test/table_no_middle_button.png")));
            }

            // proxy
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(wait);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(next));
            };
            Console.WriteLine("initialized iterator");

            // identifier
            CardStrategy           strategy   = new CardStrategyFast(patterns, new TableLayout9());
            CardIdentifierIterator identifier = new CardIdentifierIterator(proxyIter,
                                                                           strategy.identifyRegions,
                                                                           strategy.identifyCards);

            // go
            while (identifier.hasNext())
            {
                DateTime    start = DateTime.Now;
                List <Card> cards = identifier.next();
                setText(renderer, toText(cards));
                Console.WriteLine("iteration took " + DateTime.Now.Subtract(start).TotalSeconds + "s");
                Console.ReadKey();
            }
        }
Esempio n. 7
0
 private static bool ContainsJoinedColor(Image cell, ColorReducer reducer, ImagesRenderer renderer)
 {
     cell = reducer.reduceColors(cell);
     addImage(renderer, toBitmap(cell));
     foreach (int pixel in cell.pixels)
     {
         if (pixel == ColorReducers.LobbyCharsJoined.JOINED_COLOR.ToArgb())
         {
             return(true);
         }
     }
     return(false);
 }
Esempio n. 8
0
        public static void Main(string[] args)
        {
            Log.SetLevel(Log.Level.FINE);

            // patterns
            List <CardPattern> patterns = CardReader.readCardsFromResources();

            Console.WriteLine("read " + patterns.Count + " candidate patterns");

            // renderer
            ImagesRenderer renderer = newImageRenderer();

            // iterator
            Iterator <Image> wait;

            if (USE_SCREEN)
            {
                Iterator <Image> screen = new ScreenImageIterator(new Win32Control(), new Rectangle(400, 400, 300, 80));
                wait = new WaitDeltaImageIterator(screen);
            }
            else
            {
                wait = new MockIterator(toImage(new Bitmap("test/cards_56.png")));
            }

            Iterator <Image> low = new ReduceColorIterator(wait, new ColorReducers.Card());

            // proxy
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(low);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(next));
            };
            Console.WriteLine("initialized iterator");

            // identifier
            CardStrategy           strategy   = new CardStrategySlow(patterns);
            CardIdentifierIterator identifier = new CardIdentifierIterator(proxyIter,
                                                                           strategy.identifyRegions,
                                                                           strategy.identifyCards);

            // go
            while (identifier.hasNext())
            {
                DateTime    start = DateTime.Now;
                List <Card> cards = identifier.next();
                setText(renderer, toText(cards));
                Console.WriteLine("iteration took " + DateTime.Now.Subtract(start).TotalSeconds + "s");
            }
        }
        public static void Main(string[] args)
        {
            // screen + reduce + invert
            Iterator <Image> screenIter  = new MockOneImageIterator(toImage(new Bitmap("test/control_post_sb.bmp")));
            Iterator <Image> reduceIter  = new ReduceColorIterator(screenIter, new ColorReducers.ControlsChars());
            Iterator <Image> invertIter  = new InvertColorIterator(reduceIter, Color.WhiteSmoke, Color.Black);
            Iterator <Image> replaceIter = new ReplaceColorIterator(invertIter, Color.WhiteSmoke, Color.Transparent);

            // proxy
            ImagesRenderer        renderer  = newImageRenderer();
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(replaceIter);
            ColorReplacer         replacer  = new ColorReplacer(Color.Transparent, Color.Cyan);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(replacer.replace(next)));
            };

            // partition + decompose + crop
            Iterator <List <List <Image> > > patitionIter = new ImageHoriPartitionIterator(proxyIter);
            Iterator <List <List <Image> > > cropIter     = new CropImageIterator(patitionIter);

            // patterns
            List <CharPattern> patterns   = CharReader.readCharsFromResourcesControls();
            CharIdentifier     identifier = new CharIdentifier(patterns);

            // identify
            int count = 0;

            while (cropIter.hasNext())
            {
                List <List <Image> > lines = cropIter.next();
                // line
                foreach (List <Image> line in lines)
                {
                    // chars
                    String textLine = "";
                    foreach (Image chars in line)
                    {
                        List <Image> combos = CharDecomposer.decompose(chars, 0);
                        foreach (Image chr in combos)
                        {
                            Image character = ImageCropper.crop(chr);
                            textLine += identifyChars(identifier, character, ref count);
                        }
                    }
                    Console.WriteLine(textLine);
                }
            }
        }
Esempio n. 10
0
        public static void Main(string[] args)
        {
            // screen + reduce + invert
            Iterator <Image> screenIter = new MockIterator(toImage(new Bitmap("player10.png")));
            //Iterator<Image> screenIter = new ScreenImageIterator(new Rectangle(100, 400, 80, 30));
            Iterator <Image> reduceIter  = new ReduceColorIterator(screenIter, new ColorReducers.TextBox());
            Iterator <Image> invertIter  = new InvertColorIterator(reduceIter, Color.White, Color.Black);
            Iterator <Image> replaceIter = new ReplaceColorIterator(invertIter, Color.White, Color.Transparent);

            // proxy
            ImagesRenderer        renderer  = newImageRenderer();
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(replaceIter);
            ColorReplacer         replacer  = new ColorReplacer(Color.Transparent, Color.Cyan);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(replacer.replace(next)));
            };

            // partition + decompose + crop
            Iterator <List <List <Image> > > patitionIter  = new ImageHoriPartitionIterator(proxyIter);
            Iterator <List <List <Image> > > decomposeIter = new DecomposeImageIterator(patitionIter);
            Iterator <List <List <Image> > > cropIter      = new CropImageIterator(decomposeIter);

            // patterns
            List <CharPattern> patterns   = CharReader.readCharsFromResourcesPlayer();
            CharIdentifier     identifier = new CharIdentifier(patterns);

            // identify
            int count = 0;

            while (cropIter.hasNext())
            {
                List <List <Image> > images = cropIter.next();
                foreach (List <Image> line in images)
                {
                    foreach (Image chr in line)
                    {
                        String chars = identifyChars(identifier, chr, ref count);
                        Console.Write(chars);
                    }
                    Console.WriteLine();
                }
            }
        }
Esempio n. 11
0
        public static void Main(string[] args)
        {
            // screen + reduce + invert
            Iterator <Image> screenIter = new MockOneImageIterator(toImage(new Bitmap("test/table_no_middle_button.png")));
            Iterator <Image> reduceIter = new ReduceColorIterator(screenIter, new ColorPaletteReducer(new Color[] { Color.White, Color.Black }));

            // table
            ImagesRenderer renderer1 = newImageRenderer();

            setImage(renderer1, toBitmap(reduceIter.next()));

            // identifier
            TableIdentifier tableIdentifier = new TableIdentifier(new TableLayout9());

            // proxy
            ImagesRenderer renderer2 = newImageRenderer();

            tableIdentifier.RenderImageEvent += delegate(Image image, Point point)
            {
                setImage(renderer2, toBitmap(image));
            };

            // check
            Image    check1   = toImage(new Bitmap("test/table_no_middle_button.png"));
            Image    check2   = toImage(new Bitmap("test/table_with_mouse_fold.png"));
            Image    check3   = toImage(new Bitmap("test/table_seat_is_occupied.png"));
            DateTime start    = DateTime.Now;
            bool     controls = tableIdentifier.identifyMove(check1);
            double   time     = DateTime.Now.Subtract(start).TotalMilliseconds;

            Console.WriteLine(controls);
            DateTime start2 = DateTime.Now;

            controls = tableIdentifier.identifyMove(check2);
            Console.WriteLine(controls);
            double time2 = DateTime.Now.Subtract(start2).TotalMilliseconds;

            controls = tableIdentifier.identifyMove(check3);
            Console.WriteLine(controls);
            Console.WriteLine("took " + time + " ms and with boost " + time2 + " ms");
        }
Esempio n. 12
0
        public static void Main(string[] args)
        {
            // patterns
            List <CardPattern> patterns = CardReader.readCardsFromResources();

            Console.WriteLine("read " + patterns.Count + " candidate patterns");

            // renderer
            ImagesRenderer renderer = newImageRenderer();

            // iterator
            Iterator <Image> wait = new MockIterator(toImage(new Bitmap("hand.png")));

            //Iterator<Image> screen = new ScreenImageIterator(new Rectangle(400, 400, 300, 80));
            //Iterator<Image> wait = new WaitDeltaImageIterator(screen);
            Iterator <Image> low = new ReduceColorIterator(wait, new ColorReducers.Card());

            // proxy
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(low);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(next));
            };
            Console.WriteLine("initialized iterator");

            // identifier
            PocketIdentifier identifier = new PocketIdentifier(patterns);

            // go
            while (proxyIter.hasNext())
            {
                Image       screen = proxyIter.next();
                DateTime    start  = DateTime.Now;
                List <Card> hand   = identifier.identifyCards(screen);
                double      ms     = DateTime.Now.Subtract(start).TotalMilliseconds;
                Console.WriteLine("identification took " + ms + "ms");
                Console.WriteLine(toText(hand));
            }
        }
Esempio n. 13
0
        public static void Main(string[] args)
        {
            ImagesRenderer renderer = newImageRenderer();

            Iterator <Image>      imageIter      = new ScreenImageIterator(new Win32Control(), new Rectangle(100, 400, 80, 30));
            Image                 background     = imageIter.next();
            Iterator <Image>      deltaIter      = new DeltaImageAnalyzer(background, imageIter);
            IteratorProxy <Image> proxyDeltaIter = new IteratorProxy <Image>(deltaIter);

            proxyDeltaIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(next));
            };

            HashSet <HashImage>      hashImages   = new HashSet <HashImage>();
            Iterator <List <Image> > patitionIter = new ImageVerticalPartitioner(proxyDeltaIter);
            int count = 0;

            while (patitionIter.hasNext())
            {
                List <Image> images = patitionIter.next();
                foreach (Image image in images)
                {
                    if (!hasMinimumDimensions(image))
                    {
                        continue;
                    }
                    HashImage hash = new HashImage(image);
                    if (!hashImages.Contains(hash))
                    {
                        hashImages.Add(hash);
                        System.Drawing.Image bitmap = toBitmap(image);
                        addImage(renderer, bitmap);
                        saveBitmap("card", count++, bitmap);
                    }
                }
            }
        }
Esempio n. 14
0
        public static void Main(string[] args)
        {
            Iterator <Image> screen;

            if (USE_SCREEN)
            {
                // wait
                Log.Info("waiting ...");
                Thread.Sleep(5000);

                // full screen
                Console.WriteLine("## scanning for table ##");
                Image fullScreen = new ScreenImageIterator(new Win32Control()).next();
                Point offset     = PatternLocator.locateTable(fullScreen);
                Console.WriteLine("table found at x=" + offset.X + " y=" + offset.Y);

                // desk
                screen = new ScreenImageIterator(new Win32Control(), new Rectangle(offset.X, offset.Y, new TableLayout9().Size.Width, new TableLayout9().Size.Height));
                screen = new WaitDeltaImageIterator(screen);
            }
            else
            {
                screen = new MockOneImageIterator(toImage(new Bitmap("test/seatsopen_cropped.bmp")));
            }

            // renderer
            ImagesRenderer renderer = newImageRenderer();

            // identifier
            TableIdentifier tableIdentifier = new TableIdentifier(new TableLayout9());

            // pattern
            Log.Debug("reading seat pattern");
            Stream stream  = AssemblyTools.getAssemblyStream("open_seat.png");
            Bitmap bitmap  = Bitmap.FromStream(stream) as Bitmap;
            Image  pattern = toImage(bitmap);

            pattern = new ColorReducers.SeatOpen().reduceColors(pattern);
            stream.Close();

            // loop
            while (screen.hasNext())
            {
                // start
                Console.WriteLine("## iteration -> start ##");
                DateTime start = DateTime.Now;

                // table
                Console.WriteLine("# next table image #");
                Image tableImage = screen.next();

                // reduce
                ColorReducer reducer = new ColorReducers.SeatOpen();

                // rnder
                setImage(renderer, toBitmap(tableImage));

                // identify seats
                List <Point> seats = new List <Point>();
                Log.Fine("scanning lines ...");
                DateTime seatsStart = DateTime.Now;
                foreach (Rectangle seat in new TableLayout9().Seats)
                {
                    bool isOpen = IsOpen(reducer, seat, pattern, tableImage, 5);
                }
                Console.WriteLine("## seat scan -> " + DateTime.Now.Subtract(seatsStart).TotalMilliseconds + " ms ##");

                // print
                foreach (Point seat in seats)
                {
                    Console.WriteLine(seat);
                }

                // end
                double time = DateTime.Now.Subtract(start).TotalMilliseconds;
                Console.WriteLine("## iteration -> end -> " + time + " ms ##");
            }
        }
Esempio n. 15
0
        public static void Main(string[] args)
        {
            Log.SetLevel(Log.Level.FINEST);
            Iterator <Image> screenIter;

            if (USE_SCREEN)
            {
                // wait
                Log.Info("waiting ...");
                Thread.Sleep(5000);

                // full screen
                Console.WriteLine("## scanning for lobby ##");
                Image fullScreen = new ScreenImageIterator(new Win32Control()).next();
                Point offset     = PatternLocator.locateLobby(fullScreen);
                Console.WriteLine("lobby found at x=" + offset.X + " y=" + offset.Y);

                // desk
                LobbyLayout layout = new LobbyLayout();
                screenIter = new ScreenImageIterator(new Win32Control(), new Rectangle(offset.X + layout.TableList.X, offset.Y + layout.TableList.Y, layout.TableList.Width, layout.TableList.Height));
            }
            else
            {
                screenIter = new MockOneImageIterator(toImage(new Bitmap("test/lobby1.bmp")));
            }

            // screen + reduce + invert
            Iterator <Image> reduceIter  = new ReduceColorIterator(screenIter, new ColorReducers.LobbyChars());
            Iterator <Image> replaceIter = new ReplaceColorIterator(reduceIter, Color.White, Color.Transparent);

            // proxy
            ImagesRenderer        renderer  = newImageRenderer();
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(replaceIter);
            ColorReplacer         replacer  = new ColorReplacer(Color.Transparent, Color.Cyan);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(replacer.replace(next)));
            };

            // partition + decompose + crop
            Iterator <List <List <Image> > > patitionIter = new ImageHoriPartitionIterator(proxyIter);
            Iterator <List <List <Image> > > cropIter     = new CropImageIterator(patitionIter);

            // patterns
            List <CharPattern> patterns   = CharReader.readCharsFromResourcesLobby();
            CharIdentifier     identifier = new CharIdentifier(patterns);

            // identify
            int count = 0;

            while (cropIter.hasNext())
            {
                List <List <Image> > lines = cropIter.next();
                // line
                foreach (List <Image> line in lines)
                {
                    // chars
                    String textLine = "";
                    foreach (Image chars in line)
                    {
                        List <Image> combos = CharDecomposer.decompose(chars, 0);
                        foreach (Image chr in combos)
                        {
                            Image character = ImageCropper.crop(chr);
                            textLine += identifyChars(identifier, character, ref count);
                        }
                    }

                    Console.WriteLine(textLine);
                }
            }
        }
Esempio n. 16
0
        public static void Main(string[] args)
        {
            // screen + reduce + invert
            Iterator <Image> screenIter = new MockOneImageIterator(toImage(new Bitmap("test/bet.png")));
            //Iterator<Image> screenIter = new ScreenImageIterator(new Rectangle(100, 400, 80, 30));
            Iterator <Image> reduceIter  = new ReduceColorIterator(screenIter, new ColorReducers.Bets());
            Iterator <Image> invertIter  = new InvertColorIterator(reduceIter, Color.White, Color.Black);
            Iterator <Image> replaceIter = new ReplaceColorIterator(invertIter, Color.White, Color.Transparent);

            // proxy
            ImagesRenderer        renderer  = newImageRenderer();
            IteratorProxy <Image> proxyIter = new IteratorProxy <Image>(replaceIter);
            ColorReplacer         replacer  = new ColorReplacer(Color.Transparent, Color.Cyan);

            proxyIter.handler += delegate(Image next)
            {
                setImage(renderer, toBitmap(replacer.replace(next)));
            };

            // partition + decompose + crop
            Iterator <List <List <Image> > > patitionIter = new ImageHoriPartitionIterator(proxyIter);
            Iterator <List <List <Image> > > cropIter     = new CropImageIterator(patitionIter);

            // patterns
            List <CharPattern> patterns   = CharReader.readCharsFromResourcesBets();
            CharIdentifier     identifier = new CharIdentifier(patterns);

            // identify
            int count = 0;

            while (cropIter.hasNext())
            {
                List <Image> line = cropIter.next()[0];
                // chars
                String textLine = "";
                foreach (Image chars in line)
                {
                    List <Image> combos = CharDecomposer.decompose(chars);
                    foreach (Image chr in combos)
                    {
                        Image character = ImageCropper.crop(chr);
                        textLine += identifyChars(identifier, character, ref count);
                    }
                }

                // original
                Console.WriteLine(textLine);

                // check for digit
                if (!containsDigit(textLine))
                {
                    textLine = "no bet";
                }
                else
                {
                    // format
                    textLine = textLine.Replace("?", "").Replace("$", "").Trim();
                }

                Console.WriteLine(textLine);
            }
        }
Esempio n. 17
0
        private static List <ValueWithY> identifyValues(Image tableList, int x, int width, int height, ColorReducer reducer,
                                                        ColorReplacer replacer, CharIdentifier identifier, ImagesRenderer renderer)
        {
            // rows
            Image rows = tableList.crop(x, width, 0, height);

            // reduce & replace
            rows = reducer.reduceColors(rows);
            rows = replacer.replace(rows);

            // render
            setImage(renderer, toBitmap(rows));

            // chars
            List <ImageLine> lines = HorizontalPartitioner.partitionWithY(rows);

            // chars
            List <ValueWithY> result = new List <ValueWithY>();

            foreach (ImageLine line in lines)
            {
                String textLine = "";
                foreach (Image chars in line)
                {
                    List <Image> combos = CharDecomposer.decompose(chars);
                    foreach (Image chr in combos)
                    {
                        Image character = ImageCropper.crop(chr);
                        textLine += identifyChars(identifier, character);
                    }
                }

                // pure numbers
                string numericTextLine = textLine;
                foreach (char chr in textLine)
                {
                    if (!TextTools.IsNumeric(chr) && !TextTools.IsPoint(chr))
                    {
                        numericTextLine = numericTextLine.Replace(chr.ToString(), "");
                    }
                }

                // convert
                if (numericTextLine.Length != 0)
                {
                    double value = TextTools.ParseDouble(numericTextLine);
                    result.Add(new ValueWithY(value, line.Y));
                }
            }

            return(result);
        }
Esempio n. 18
0
        public static void Main(string[] args)
        {
            Log.SetLevel(Log.Level.FINEST);
            Iterator <Image> screenIter;
            LobbyLayout      layout = new LobbyLayout();
            Point            offset;

            if (USE_SCREEN)
            {
                // wait
                Log.Info("waiting ...");
                Thread.Sleep(3000);

                // full screen
                Console.WriteLine("## scanning for lobby ##");
                Image fullScreen = new ScreenImageIterator(new Win32Control()).next();
                offset = PatternLocator.locateLobby(fullScreen);
                Console.WriteLine("lobby found at x=" + offset.X + " y=" + offset.Y);

                // lobby
                screenIter = new ScreenImageIterator(new Win32Control(), new Point(offset.X, offset.Y));
                screenIter = new WaitDeltaImageIterator(screenIter);
            }
            else
            {
                offset     = new Point(0, 0);
                screenIter = new MockOneImageIterator(toImage(new Bitmap("test/lobby1.bmp")));
            }

            // screen + reduce + invert
            ColorReducer  reducer       = new ColorReducers.LobbyChars();
            ColorReducer  reducerJoined = new ColorReducers.LobbyCharsJoined();
            ColorReplacer replacer      = new ColorReplacer(Color.White, Color.Transparent);


            // renderer
            ImagesRenderer renderer      = newImageRenderer();
            ColorReplacer  replacerTrans = new ColorReplacer(Color.Transparent, Color.Cyan);

            // patterns
            List <CharPattern> patterns   = CharReader.readCharsFromResourcesLobby();
            CharIdentifier     identifier = new CharIdentifier(patterns);

            // identify
            while (screenIter.hasNext())
            {
                // rows
                List <LobbyTable> rows = new List <LobbyTable>();

                // image
                Image screen = screenIter.next();

                // list
                Image tableList = screen.crop(layout.TableList.X, layout.TableList.X + layout.TableList.Width,
                                              layout.TableList.Y, layout.TableList.Y + layout.TableList.Height);

                // identify
                List <ValueWithY> playerCounts = identifyValues(tableList, layout.PlayersCountX,
                                                                layout.PlayersCountX + layout.PlayersCountW, tableList.height,
                                                                reducer, replacer, identifier, renderer);
                List <ValueWithY> potSizes = identifyValues(tableList, layout.PotX,
                                                            layout.PotX + layout.PotW, tableList.height,
                                                            reducer, replacer, identifier, renderer);
                List <ValueWithY> flops = identifyValues(tableList, layout.FlopsX,
                                                         layout.FlopsX + layout.FlopsW, tableList.height,
                                                         reducer, replacer, identifier, renderer);

                List <LobbyTable> tables = new List <LobbyTable>();
                for (int i = 0; i < playerCounts.Count; i++)
                {
                    // location
                    int x = offset.X + layout.TableList.X + layout.TableList.Width / 2;
                    int y = offset.Y + layout.TableList.Y + playerCounts[i].Y;

                    // cell
                    int   celly  = playerCounts[i].Y;
                    int   cellx  = layout.PlayersCountX;
                    Image cell   = tableList.crop(cellx, cellx + layout.PlayersCountW, celly, celly + layout.CellHeight);
                    bool  joined = ContainsJoinedColor(cell, reducerJoined, renderer);

                    // table
                    tables.Add(new LobbyTable(i + 1, (int)playerCounts[i].Value, potSizes[i].Value, (int)flops[i].Value, x, y, offset.X, offset.Y, joined));
                }

                // print
                foreach (LobbyTable table in tables)
                {
                    Console.WriteLine(table.ToString());
                }

                // wait
                Console.ReadKey();
            }
        }