Exemple #1
0
        /// <summary>
        /// Realiza a identificação dos pontos na imagem que possuem correlação com a matriz de amostra.
        /// </summary>
        /// <param name="sample">Matriz de amostra.</param>
        /// <param name="bmpData">Um array contendo os valores R, G, B para os pixels do bitmap.</param>
        /// <param name="minFactor">Fator de correlação mínimo para considerar semelhante.</param>
        /// <returns>Uma lista dos pontos onde ocorreu a semelhança.</returns>
        /// <remarks>O tamanho da amostra deve ser um número ímpar.</remarks>
        public static List <PointCorrelation> TemplateMatching(ref byte[, ,] sample, ref byte[, ,] bmpData, double minFactor)
        {
            // tamanho do bitmap
            int width  = bmpData.GetUpperBound(0) + 1;
            int height = bmpData.GetUpperBound(1) + 1;

            // tamanho da amostra
            int sampleSize = sample.GetUpperBound(0) + 1;

            // pontos candidatos
            List <PointCorrelation> candidatePointList = new List <PointCorrelation>();

            // pontos encontrados
            List <PointCorrelation> pointList = new List <PointCorrelation>();

            // valor da correlação
            double corrFactor = 0.0;

            // tamanho da matriz semente dos pontos candidatos
            if (sampleSize >= 9)
            {
                int seedSize = sampleSize / 4;
                if (seedSize % 2 == 0)
                {
                    seedSize++;
                }

                // matriz de busca
                byte[, ,] seedSample = new byte[seedSize, seedSize, 3];
                byte[, ,] seedSearch = new byte[seedSize, seedSize, 3];

                // metade do tamanho do pixel semente
                int size = seedSize / 2;

                // cria matriz de amostra
                for (int i = sampleSize / 2 - size; i <= sampleSize / 2 + size; ++i)
                {
                    for (int j = sampleSize / 2 - size; j <= sampleSize / 2 + size; ++j)
                    {
                        seedSample[i - sampleSize / 2 + size, j - sampleSize / 2 + size, 0] = sample[i, j, 0];
                        seedSample[i - sampleSize / 2 + size, j - sampleSize / 2 + size, 1] = sample[i, j, 1];
                        seedSample[i - sampleSize / 2 + size, j - sampleSize / 2 + size, 2] = sample[i, j, 2];
                    }
                }

                // busca os pontos candidatos
                for (int j = size; j < height - size; ++j)
                {
                    for (int i = size; i < width - size; ++i)
                    {
                        // verifica se o ponto central da matriz de busca é branco (melhor performance)
                        if (bmpData[i, j, 0] == 0)
                        {
                            continue;
                        }

                        // popula matriz de busca
                        for (int l = j - size; l <= j + size; ++l)
                        {
                            for (int k = i - size; k <= i + size; ++k)
                            {
                                seedSearch[k - i + size, l - j + size, 0] = bmpData[k, l, 0];
                                seedSearch[k - i + size, l - j + size, 1] = bmpData[k, l, 1];
                                seedSearch[k - i + size, l - j + size, 2] = bmpData[k, l, 2];
                            }
                        }

                        // calcula correlação
                        corrFactor = BitmapTools.CorrelationFactor(ref seedSample, ref seedSearch);

                        if (corrFactor >= 0)
                        {
                            candidatePointList.Add(new PointCorrelation(i, j, corrFactor));
                        }
                    }
                }

                // metade do tamanho do pixel semente
                size = sampleSize / 2;

                // matriz de busca
                byte[, ,] search = new byte[sampleSize, sampleSize, 3];

                // verifica se os pontos candidatos podem ser considerados
                foreach (PointCorrelation point in candidatePointList)
                {
                    if ((point.X - size) < 0 || (point.Y - size < 0) || (point.X + size >= width) || (point.Y + size >= height))
                    {
                        continue;
                    }

                    // popula matriz de busca
                    for (int l = point.Y - size; l <= point.Y + size; ++l)
                    {
                        for (int k = point.X - size; k <= point.X + size; ++k)
                        {
                            search[k - point.X + size, l - point.Y + size, 0] = bmpData[k, l, 0];
                            search[k - point.X + size, l - point.Y + size, 1] = bmpData[k, l, 1];
                            search[k - point.X + size, l - point.Y + size, 2] = bmpData[k, l, 2];
                        }
                    }

                    // calcula correlação
                    corrFactor = BitmapTools.CorrelationFactor(ref sample, ref search);

                    if (corrFactor >= minFactor)
                    {
                        // verifica se já existe um ponto na lista com a distância menor que sampleSize
                        bool found = false;
                        foreach (PointCorrelation p in pointList)
                        {
                            if (Math.Sqrt((p.X - point.X) * (p.X - point.X) + (p.Y - point.Y) * (p.Y - point.Y)) <= sampleSize)
                            {
                                if (corrFactor >= p.CorrelationValue)
                                {
                                    pointList.Remove(p);
                                    pointList.Add(new PointCorrelation(point.X, point.Y, corrFactor));
                                }

                                found = true;
                                break;
                            }
                        }

                        // adiciona o ponto na lista
                        if (!found)
                        {
                            pointList.Add(new PointCorrelation(point.X, point.Y, corrFactor));
                        }
                    }
                }
            }
            else
            {
                // matriz de busca
                byte[, ,] search = new byte[sampleSize, sampleSize, 3];

                // metade do tamanho do pixel semente
                int size = sampleSize / 2;

                // busca os pontos
                for (int j = size; j < height - size; ++j)
                {
                    for (int i = size; i < width - size; ++i)
                    {
                        // popula matriz de busca
                        for (int l = j - size; l <= j + size; ++l)
                        {
                            for (int k = i - size; k <= i + size; ++k)
                            {
                                search[k - i + size, l - j + size, 0] = bmpData[k, l, 0];
                                search[k - i + size, l - j + size, 1] = bmpData[k, l, 1];
                                search[k - i + size, l - j + size, 2] = bmpData[k, l, 2];
                            }
                        }

                        // calcula correlação
                        corrFactor = BitmapTools.CorrelationFactor(ref sample, ref search);

                        if (corrFactor >= minFactor)
                        {
                            // verifica se já existe um ponto na lista com a distância menor que sampleSize
                            bool found = false;
                            foreach (PointCorrelation p in pointList)
                            {
                                if (Math.Sqrt((p.X - i) * (p.X - i) + (p.Y - j) * (p.Y - j)) <= sampleSize)
                                {
                                    if (corrFactor >= p.CorrelationValue)
                                    {
                                        pointList.Remove(p);
                                        pointList.Add(new PointCorrelation(i, j, corrFactor));
                                    }

                                    found = true;
                                    break;
                                }
                            }

                            // adiciona o ponto na lista
                            if (!found)
                            {
                                pointList.Add(new PointCorrelation(i, j, corrFactor));
                            }
                        }
                    }
                }
            }

            // retorna a lista de pontos
            return(pointList);
        }
Exemple #2
0
        /// <summary>
        /// Procura na imagem por regiões que representam pontos de referência.
        /// </summary>
        /// <param name="bmpData">Um array contendo os valores R, G, B para os pixels do bitmap.</param>
        /// <param name="minFactor">Fator de correlação mínimo para considerar semelhante duas matrizes (-1 a 1).</param>
        /// <returns>Uma lista com a coordenada e valor de correlação dos pontos.</returns>
        /// <remarks>Este método considera que a imagem seja preto e branco, sendo que a cor branca representa
        /// as regiões e a cor preta o plano de fundo.</remarks>
        public static List <PointCorrelation> FindImagePoints(ref byte[, ,] bmpData, double minFactor)
        {
            List <PointCorrelation> pointList = null;

            // ponto semente
            Point seedPoint = new Point(0, 0);
            bool  findSeed  = false;

            // tamanho do bitmap
            int width  = bmpData.GetUpperBound(0) + 1;
            int height = bmpData.GetUpperBound(1) + 1;

            //// procura pelo ponto semente
            //// obs.: Inicia de baixo pra cima.
            //for (int i = 0; i < width; ++i)
            //{
            //    for (int j = height - 1; j >= 0; --j)
            //    {
            //        if (bmpData[i, j, 0] == 255)
            //        {
            //            seedPoint.X = i;
            //            seedPoint.Y = j;

            //            // flag
            //            findSeed = true;

            //            // sai do loop
            //            j = -1;
            //            i = width;
            //        }
            //    }
            //}

            // procura pelo ponto semente
            // obs.: Inicia da metade da imagem e segue crescendo Y.
            for (int j = height / 2; j < height; ++j)
            {
                for (int i = 0; i < width; ++i)
                {
                    if (bmpData[i, j, 0] == 255)
                    {
                        // verifica se os vizinhos do ponto são brancos também
                        if (i >= 2 && i <= (width - 2) && j <= (height - 2))
                        {
                            if (bmpData[i - 1, j - 1, 0] == 255 && bmpData[i - 1, j, 0] == 255 &&
                                bmpData[i - 1, j + 1, 0] == 255 && bmpData[i, j - 1, 0] == 255 &&
                                bmpData[i, j + 1, 0] == 255 && bmpData[i + 1, j - 1, 0] == 255 &&
                                bmpData[i + 1, j, 0] == 255 && bmpData[i + 1, j + 1, 0] == 255)
                            {
                                seedPoint.X = i;
                                seedPoint.Y = j;

                                // flag
                                findSeed = true;

                                // sai do loop
                                j = height;
                                i = width;
                            }
                        }
                    }
                }
            }

            // se não encontrou o ponto, inicia da origem da imagem e vai até a metade.
            if (!findSeed)
            {
                for (int j = 0; j < height / 2; ++j)
                {
                    for (int i = 0; i < width; ++i)
                    {
                        if (bmpData[i, j, 0] == 255)
                        {
                            // verifica se os vizinhos do ponto são brancos também
                            if (i >= 2 && i <= (width - 2) && j >= 2)
                            {
                                if (bmpData[i - 1, j - 1, 0] == 255 && bmpData[i - 1, j, 0] == 255 &&
                                    bmpData[i - 1, j + 1, 0] == 255 && bmpData[i, j - 1, 0] == 255 &&
                                    bmpData[i, j + 1, 0] == 255 && bmpData[i + 1, j - 1, 0] == 255 &&
                                    bmpData[i + 1, j, 0] == 255 && bmpData[i + 1, j + 1, 0] == 255)
                                {
                                    seedPoint.X = i;
                                    seedPoint.Y = j;

                                    // flag
                                    findSeed = true;

                                    // sai do loop
                                    j = height;
                                    i = width;
                                }
                            }
                        }
                    }
                }
            }

            // verifica se encontrou o ponto semente
            // se não encontrou, retorna uma lista vazia de pontos
            if (!findSeed)
            {
                return(new List <PointCorrelation>());
            }

            // pilha contendo pontos a serem verificados
            Stack <Point> pointStack = new Stack <Point>();

            // cria array contendo flags para identificar a região
            bool[,] regionFlags = new bool[width, height];

            // inicializa array
            for (int i = 0; i < width; ++i)
            {
                for (int j = 0; j < height; ++j)
                {
                    regionFlags[i, j] = false;
                }
            }

            // indica que o ponto semente pertence à região
            regionFlags[seedPoint.X, seedPoint.Y] = true;

            // adiciona ponto na pilha de pontos
            pointStack.Push(seedPoint);

            // coordenadas corrente
            int x = 0;
            int y = 0;

            while (pointStack.Count != 0)
            {
                // remove ponto
                Point p = pointStack.Pop();
                x = p.X;
                y = p.Y;

                // vizinhos da esquerda
                if (x - 1 >= 0)
                {
                    // esquerda
                    if (bmpData[x - 1, y, 0] == 255)
                    {
                        if (!regionFlags[x - 1, y])
                        {
                            regionFlags[x - 1, y] = true;
                            pointStack.Push(new Point(x - 1, y));
                        }
                    }

                    // esquerda superior
                    if (y - 1 >= 0)
                    {
                        if (bmpData[x - 1, y - 1, 0] == 255)
                        {
                            if (!regionFlags[x - 1, y - 1])
                            {
                                regionFlags[x - 1, y - 1] = true;
                                pointStack.Push(new Point(x - 1, y - 1));
                            }
                        }
                    }

                    // esquerda inferior
                    if (y + 1 < height)
                    {
                        if (bmpData[x - 1, y + 1, 0] == 255)
                        {
                            if (!regionFlags[x - 1, y + 1])
                            {
                                regionFlags[x - 1, y + 1] = true;
                                pointStack.Push(new Point(x - 1, y + 1));
                            }
                        }
                    }
                }

                // vizinho superior
                if (y - 1 >= 0)
                {
                    if (bmpData[x, y - 1, 0] == 255)
                    {
                        if (!regionFlags[x, y - 1])
                        {
                            regionFlags[x, y - 1] = true;
                            pointStack.Push(new Point(x, y - 1));
                        }
                    }
                }

                // vizinho inferior
                if (y + 1 < height)
                {
                    if (bmpData[x, y + 1, 0] == 255)
                    {
                        if (!regionFlags[x, y + 1])
                        {
                            regionFlags[x, y + 1] = true;
                            pointStack.Push(new Point(x, y + 1));
                        }
                    }
                }

                // vizinhos à direita
                if (x + 1 < width)
                {
                    // direita
                    if (bmpData[x + 1, y, 0] == 255)
                    {
                        if (!regionFlags[x + 1, y])
                        {
                            regionFlags[x + 1, y] = true;
                            pointStack.Push(new Point(x + 1, y));
                        }
                    }

                    // direita superior
                    if (y - 1 >= 0)
                    {
                        if (bmpData[x + 1, y - 1, 0] == 255)
                        {
                            if (!regionFlags[x + 1, y - 1])
                            {
                                regionFlags[x + 1, y - 1] = true;
                                pointStack.Push(new Point(x + 1, y - 1));
                            }
                        }
                    }

                    // direita inferior
                    if (y + 1 < height)
                    {
                        if (bmpData[x + 1, y + 1, 0] == 255)
                        {
                            if (!regionFlags[x + 1, y + 1])
                            {
                                regionFlags[x + 1, y + 1] = true;
                                pointStack.Push(new Point(x + 1, y + 1));
                            }
                        }
                    }
                }
            }

            int xmin = width - 1, ymin = height - 1;
            int xmax = 0, ymax = 0;

            // procura pelos pontos mínimo e máximo da região
            for (int i = 0; i < width; ++i)
            {
                for (int j = 0; j < height; ++j)
                {
                    if (regionFlags[i, j])
                    {
                        if (i < xmin)
                        {
                            xmin = i;
                        }

                        if (i > xmax)
                        {
                            xmax = i;
                        }

                        if (j < ymin)
                        {
                            ymin = j;
                        }

                        if (j > ymax)
                        {
                            ymax = j;
                        }
                    }
                }
            }

            // tamanho da matriz de amostra
            int sampleSize = (int)Math.Max(xmax - xmin, ymax - ymin);

            // verifica o tamanho do ponto semente
            if (sampleSize < 2)
            {
                return(new List <PointCorrelation>());
            }

            // o tamanho deve ser um número ímpar
            if (sampleSize % 2 == 0)
            {
                sampleSize++;
            }

            // cria matriz de amostra
            byte[, ,] sample = new byte[sampleSize, sampleSize, 3];

            // corrige ponto semente
            seedPoint.X = xmin + ((xmax - xmin) / 2);
            seedPoint.Y = ymin + ((ymax - ymin) / 2);

            // metade do tamanho da matriz de amosta
            int size = sampleSize / 2;

            // copia valores para a matriz de amostra
            for (int i = seedPoint.X - size; i <= seedPoint.X + size; ++i)
            {
                for (int j = seedPoint.Y - size; j <= seedPoint.Y + size; ++j)
                {
                    sample[i - seedPoint.X + size, j - seedPoint.Y + size, 0] = bmpData[i, j, 0];
                    sample[i - seedPoint.X + size, j - seedPoint.Y + size, 1] = bmpData[i, j, 1];
                    sample[i - seedPoint.X + size, j - seedPoint.Y + size, 2] = bmpData[i, j, 2];
                }
            }

            // realiza template matching
            pointList = BitmapTools.TemplateMatching(ref sample, ref bmpData, minFactor);

            // retorna lista de pontos
            return(pointList);
        }