/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package testejavadesktop;
/**
*
* @author Administrator
*/
public class UTioPatinhas {
static int BORDA_CLARO_ESCURO = 0, BORDA_ESCURO_CLARO = 1;
static int TAM_VETOR_LIMITES_VERTICAIS_GRUPOS = 300;
static int PIXEL_ACEITO = 1;
static int PIXEL_NAO_ACEITO = 2;
static int DELTA_Y_HISTOGRAM = 5, DELTA_X_HISTOGRAM = 5;
UTioPatinhas() {
}
static void ReconheceCedula(TParamsRC ParamsRC) {
ParamsRC.LumMedianaImagem = Histograma(ParamsRC.ParamsMLT.TCImgSrc);
ParamsRC.ConverteParametrosDependentesLumMediana();
ParamsRC.ParamsMLT.DifMinLum = ParamsRC.ParamsABT.DifMinLum;
MostraLimiteTarja(ParamsRC.ParamsMLT);
ParamsRC.ParamsABT.BImgDest = ParamsRC.ParamsMLT.BImgDest;
ParamsRC.ParamsABT.TCImgSrc = ParamsRC.ParamsMLT.TCImgSrc;
ParamsRC.ParamsABT.BordasColunas = ParamsRC.ParamsMLT.BordasColunas;
AnalizaBordasTarja(ParamsRC.ParamsABT);
//DeterminaInclinaçãoTarja(ParamsRC.ParamsABT, ParamsRC.ParamsAI);
ParamsRC.ParamsAI.AltTarja = (int) ParamsRC.ParamsABT.MediaAlturaTarja;
ParamsRC.ConverteParametrosDependentesAlturaFaixa();
if (ParamsRC.ParamsABT.AchouTarja) {
ParamsRC.ParamsAI.RefTarja = ParamsRC.ParamsABT.RefTarja;
ParamsRC.ParamsAI.BImgDest = ParamsRC.ParamsABT.BImgDest;
ParamsRC.ParamsAI.TCImgSrc = ParamsRC.ParamsMLT.TCImgSrc;
VerificaSeTemMaisVerdeDoQueVermelho(ParamsRC.ParamsAI);
AnalizaIdentificador(ParamsRC.ParamsAI);
}
//EscreveParametros(ParamsRC);
}
static int Histograma(CTonsCinza TCImgSrc) {
int[] vetor = new int[256];
int[] vetorCumulativa = new int[256];
int n, x, y;
int MetadeTotal;
int Mediana;
short[][] ImgSrc = TCImgSrc.TonsCinza;
for (y = 0; y < TCImgSrc.Alt; y += DELTA_Y_HISTOGRAM) {
for (x = 0; x < TCImgSrc.Larg; x += DELTA_X_HISTOGRAM) {
vetor[ImgSrc[y][x]]++;
}
}
vetorCumulativa[0] = vetor[0];
for (n = 1; n < 256; n++) {
vetorCumulativa[n] = vetorCumulativa[n - 1] + vetor[n];
}
Mediana = 0;
MetadeTotal = vetorCumulativa[255] / 2;
for (n = 1; n < 256; n++) {
if (vetorCumulativa[n] >= MetadeTotal) {
Mediana = n;
break;
}
}
return Mediana;
}
/**
* Varre a imagem verticalmente detectando grande variação de contraste entre
* os pixels. Estas variações são marcadas superiormente com uma faixa vermelha
* e inferiormente com uma faixa verde.
*/
static void MostraLimiteTarja(TParamsMLT ParamsMLT) {
int ALT_COLUNA = 3, DY = 2;
int x, y, j;
int yBorda;
int DifLum;
int UltYBordaCE, UltYBordaEC;
int MaisEscuroAtual, MaisClaroAtual, MaisClaroAnterior, MaisEscuroAnterior;
int lum;
short[][] ImgSrc = ParamsMLT.TCImgSrc.TonsCinza;
Cor[][] ImgDest = null;
if (ParamsMLT.BImgDest != null) {
ImgDest = ParamsMLT.BImgDest.PMCor;
}
int YIni = (int) (ParamsMLT.TCImgSrc.Alt * ParamsMLT.PropYIni);
int XFim = (int) (ParamsMLT.TCImgSrc.Larg * ParamsMLT.PropXFim);
TBorda BordaTemp;
TMaiorBorda MaiorBorda = new TMaiorBorda();
ParamsMLT.BordasColunas = new TBordasColunas(XFim);
for (x = 0; x < XFim; x++) {
UltYBordaCE = UltYBordaEC = -1;
MaiorBorda.DifLum = 0;
for (y = YIni + ALT_COLUNA; y < (ParamsMLT.TCImgSrc.Alt - ALT_COLUNA); y++) {
MaisEscuroAtual = 255;
MaisEscuroAnterior = 255;
MaisClaroAtual = 0;
MaisClaroAnterior = 0;
//define os mais claros e mais escuros atuais
for (j = y; j < (y + ALT_COLUNA); j++) {
lum = ImgSrc[j][x];
if (lum > MaisClaroAtual) {
MaisClaroAtual = lum;
}
if (lum < MaisEscuroAtual) {
MaisEscuroAtual = lum;
}
}
//define os mais claros e os mais escuros anteriores
for (j = y - (ALT_COLUNA + DY); j < (y - DY); j++) {
lum = ImgSrc[j][x];
if (lum > MaisClaroAnterior) {
MaisClaroAnterior = lum;
}
if (lum < MaisEscuroAnterior) {
MaisEscuroAnterior = lum;
}
}
// if (x==25 && y==170)
// int w=5;
//borda claro encima, escuro embaixo
DifLum = MaisEscuroAnterior - MaisClaroAtual;
if (DifLum > ParamsMLT.DifMinLum) {
if (DifLum > MaiorBorda.DifLum) {
MaiorBorda.DifLum = DifLum;
MaiorBorda.y = y;
}
UltYBordaCE = y;
} else {
if (y == (UltYBordaCE + 1)) {
yBorda = MaiorBorda.y - ALT_COLUNA;
if (ImgDest != null) {
ImgDest[yBorda][x].SetVermelho();
}
BordaTemp = new TBorda();
BordaTemp.Y = yBorda;
BordaTemp.TipoBorda = BORDA_CLARO_ESCURO;
ParamsMLT.BordasColunas.Bordas[x].addElement(BordaTemp);
MaiorBorda.DifLum = 0;
}
}
//borda escuro encima, claro embaixo
DifLum = MaisEscuroAtual - MaisClaroAnterior;
if (DifLum > ParamsMLT.DifMinLum) {
if (DifLum > MaiorBorda.DifLum) {
MaiorBorda.DifLum = DifLum;
MaiorBorda.y = y;
}
UltYBordaEC = y;
} else {
if (y == (UltYBordaEC + 1)) {
yBorda = MaiorBorda.y - ALT_COLUNA;
if (ImgDest != null) {
ImgDest[yBorda][x].SetVerde();
}
BordaTemp = new TBorda();
BordaTemp.Y = yBorda;
BordaTemp.TipoBorda = BORDA_ESCURO_CLARO;
ParamsMLT.BordasColunas.Bordas[x].addElement(BordaTemp);
MaiorBorda.DifLum = 0;
}
}
}
}
}
/**
* Analiza os limites vermelhos e verdes de cada uma das tarjas, marcando
* a faixa amarela na distancia média entre as mesmas.
*/
static void AnalizaBordasTarja(TParamsABT ParamsABT) {
int x, n;
int NumColunas = ParamsABT.BordasColunas.NumColunas;
ParamsABT.ConjuntoMeioBordas = new TConjuntoMeioBordas(NumColunas);
int dif;
TVectorBorda BordasTemp;//guarda as bordas da coluna corrente
TBorda BordaEnc, BordaEmb;
TMeioBordas MeioBordasTemp;//TMeioBordas: ponto amarelo, verde e vermelho
Cor[][] ImgDest = null;
if (ParamsABT.BImgDest != null) {
ImgDest = ParamsABT.BImgDest.PMCor;
}
//percorre todas as colunas
for (x = 0; x < NumColunas; x++) {
BordasTemp = ParamsABT.BordasColunas.Bordas[x];
//percorre todas as bordas da coluna
for (n = 1; n < BordasTemp.size(); n++) {
BordaEnc = BordasTemp.retornaTBorda(n - 1);
BordaEmb = BordasTemp.retornaTBorda(n);
dif = BordaEmb.Y - BordaEnc.Y;
//se a borda de cima for vermelha, a de baixo for verde,
//e a distância entre elas for de borda, marca ponto amarelo
if ((BordaEmb.TipoBorda == BORDA_ESCURO_CLARO) &&
(BordaEnc.TipoBorda == BORDA_CLARO_ESCURO) &&
(dif >= ParamsABT.AltMinTarja) && (dif <= ParamsABT.AltMaxTarja)) {
//cria ponto amarelo
MeioBordasTemp = new TMeioBordas(BordaEnc.Y, BordaEmb.Y);
//adiciona ponto amarelo na lista de pontos da coluna corrente
ParamsABT.ConjuntoMeioBordas.VectorMeioBordas[x].addElement(MeioBordasTemp);
//se tiver imagem de destino, pinta o ponto amarelo
if (ImgDest != null) {
ImgDest[MeioBordasTemp.yMeio][x].SetAmarelo();
}
}
}
}
SelecionaTarja(ParamsABT);
if (ParamsABT.AchouTarja) {
if (ImgDest != null) {
ImgDest[ParamsABT.RefTarja.y][ParamsABT.RefTarja.x].SetMagenta();
ImgDest[ParamsABT.RefTarja.y + 1][ParamsABT.RefTarja.x].SetMagenta();
ImgDest[ParamsABT.RefTarja.y][ParamsABT.RefTarja.x + 1].SetMagenta();
ImgDest[ParamsABT.RefTarja.y + 1][ParamsABT.RefTarja.x + 1].SetMagenta();
}
}
}
/**
* Descarta as tarjas que estao fora dos limites de largura e com a altura
* variando muito (analizando os desvios padrão calculados em preparaSelecionaTarja)
*/
static void SelecionaTarja(TParamsABT ParamsABT) {
int n, nMenorX, m, LargTarjaCandidata;
TTarja TarjaCandidata;
int MenorX, AlturaTarjaMColunaN;
double soma, desvio, AlturaMedia, MediaTarjaSelecionada = 0;
PreparaSelecionaTarja(ParamsABT);
MenorX = 0xFFFFFF;
nMenorX = -1;
ParamsABT.AchouTarja = false;
//percorre vector com todas as tarjas
for (n = 0; n < ParamsABT.VectorTarja.size(); n++) {
TarjaCandidata = ParamsABT.VectorTarja.retornaTTarja(n);
LargTarjaCandidata = TarjaCandidata.VectorPontoAmarelo.size();
//ifdef DEBUG
COutputDebug.WriteOutput("Tarja candidata " + String.valueOf(n) + ".\tLargura:\t" + String.valueOf(LargTarjaCandidata) +
"\tX:\t" + String.valueOf(TarjaCandidata.X) +
"\tY:\t" + String.valueOf(TarjaCandidata.PriYEnc));
//endif
//continua se a tarja possui a largura dentro dos limites
if ((LargTarjaCandidata <= ParamsABT.LargMaxTarja) &&
(LargTarjaCandidata >= ParamsABT.LargMinTarja)) {
soma = 0;
//calcula a média da altura de cada coluna da possível tarja
for (m = 0; m < ParamsABT.VectorTarja.retornaTTarja(n).VectorPontoAmarelo.size(); m++) {
soma += ParamsABT.VectorTarja.retornaTTarja(n).VectorPontoAmarelo.retornaPontoAmarelo(m).Altura;
}
AlturaMedia = soma / ParamsABT.VectorTarja.retornaTTarja(n).VectorPontoAmarelo.size();
//calcula o desvio padrão
soma = 0;
for (m = 0; m < ParamsABT.VectorTarja.retornaTTarja(n).VectorPontoAmarelo.size(); m++) {
AlturaTarjaMColunaN =
ParamsABT.VectorTarja.retornaTTarja(n).VectorPontoAmarelo.retornaPontoAmarelo(m).Altura;
soma = Math.abs(AlturaMedia - AlturaTarjaMColunaN);
}
desvio = soma / ParamsABT.VectorTarja.retornaTTarja(n).VectorPontoAmarelo.size();
COutputDebug.WriteOutput("desvio padrão alturas: " + String.valueOf(desvio));
if (desvio < ParamsABT.DesvioMax) {
boolean TemContrasteSuficienteNoLadoEsquerdo;
COutputDebug.WriteOutput("menor do que o limite de : " + String.valueOf(ParamsABT.DesvioMax));
TemContrasteSuficienteNoLadoEsquerdo =
GeraContrasteLadoEsquerdoTarja(ParamsABT, (int) AlturaMedia,
new TPonto(TarjaCandidata.X, TarjaCandidata.PriYEnc),
ParamsABT.DifMinLum);
if (TemContrasteSuficienteNoLadoEsquerdo && ParamsABT.VectorTarja.retornaTTarja(n).X < MenorX) {
MenorX = ParamsABT.VectorTarja.retornaTTarja(n).X;
nMenorX = n;
MediaTarjaSelecionada = AlturaMedia;
}
}
}
}
ParamsABT.nTarjaSelecionada = nMenorX;
if (nMenorX != -1) {
ParamsABT.RefTarja.x = ParamsABT.VectorTarja.retornaTTarja(nMenorX).X;
ParamsABT.RefTarja.y = ParamsABT.VectorTarja.retornaTTarja(nMenorX).PriYEnc;
ParamsABT.MediaAlturaTarja = MediaTarjaSelecionada;
ParamsABT.AchouTarja = true;
}
}
/**
* Agrupa pontos amarelos em listas de pontos amarelos conectados
*/
static void PreparaSelecionaTarja(TParamsABT ParamsABT) {
int x;
int DistYTarjas;
boolean TarjaAtiva;
int n, m;
boolean Adicionou;
TMeioBordas MeioBordasTemp;
//percorre todas as colunas
for (x = 0; x < ParamsABT.ConjuntoMeioBordas.NumColunas; x++) {
//percorre todos os meio de bordas da coluna (pixels amarelos)
for (m = 0; m < ParamsABT.ConjuntoMeioBordas.VectorMeioBordas[x].size(); m++) {
Adicionou = false;
//MeioBordasTemp ponto amarelo, e par de pontos vermelho e verde
//da coluna x, e o ponto amarelo de índice m, de cima para baixo
MeioBordasTemp = ParamsABT.ConjuntoMeioBordas.VectorMeioBordas[x].retornaTMeioBordas(m);
//percorre todas as tarjas que estão ativas na coluna corrente
for (n = 0; n < ParamsABT.VectorTarja.size(); n++) {
//distância em Y entre o ponto amarelo corrente e o último ponto amarelo
//adicionado na tarja sendo processada no momento (Tarja n)
DistYTarjas = Math.abs(ParamsABT.VectorTarja.retornaTTarja(n).UltYMeio -
MeioBordasTemp.yMeio);
TarjaAtiva = ParamsABT.VectorTarja.retornaTTarja(n).Ativa(x);
if (TarjaAtiva && (DistYTarjas <= ParamsABT.DistMaxTarjas)) {
ParamsABT.VectorTarja.retornaTTarja(n).VectorPontoAmarelo.adicionaPontoAmarelo(
new TPontoAmarelo(MeioBordasTemp.Altura,
x, MeioBordasTemp.yMeio));
ParamsABT.VectorTarja.retornaTTarja(n).UltYMeio = MeioBordasTemp.yMeio;
Adicionou = true;
}
}
//se o ponto amarelo não faz contato com nenhuma tarja, cria-se
//uma tarja nova para ele
if (!Adicionou) {
TTarja TarjaTemp = new TTarja(ParamsABT.DistHorMaxPartesTarja);
TarjaTemp.X = x;
TarjaTemp.UltYMeio = MeioBordasTemp.yMeio;
TarjaTemp.PriYEnc = MeioBordasTemp.Y1;
TarjaTemp.VectorPontoAmarelo.adicionaPontoAmarelo(
new TPontoAmarelo(MeioBordasTemp.Altura,
x, MeioBordasTemp.yMeio));
ParamsABT.VectorTarja.adicionaTTarja(TarjaTemp);
}
}
}
}
static boolean GeraContrasteLadoEsquerdoTarja(TParamsABT ParamsABT,
int AltTarja, TPonto OrigemTarja, int LimiarDifLum) {
int DX = 2;
int LargRegiaoContrasteD2 =
(int) (ParamsABT.LargRegiaoContrasteLadoEsqTarja * AltTarja);
short[][] ImgSrc = ParamsABT.TCImgSrc.TonsCinza;
Cor[][] ImgDest = null;
if (ParamsABT.BImgDest != null) {
ImgDest = ParamsABT.BImgDest.PMCor;
}
short dif;
int XIni, XFim, YIni, YFim;
int NumPontosContraste = 0;
YIni = OrigemTarja.y;
YFim = OrigemTarja.y + AltTarja;
XIni = OrigemTarja.x - LargRegiaoContrasteD2;
XFim = OrigemTarja.x + LargRegiaoContrasteD2;
if (XIni < 0) {
XIni = 0;
}
COutputDebug.WriteOutput("XIni busca contraste: " + XIni);
COutputDebug.WriteOutput("XFim busca contraste: " + XFim);
for (int y = YIni; y < YFim; y++) {
for (int x = XIni; x <= XFim; x++) {
dif = (short) (ImgSrc[y][x] - ImgSrc[y][x + DX]);
if (dif > LimiarDifLum) {
NumPontosContraste++;
if (ImgDest != null) {
ImgDest[y][x + 1].SetCyan();
}
break;
}
}
}
COutputDebug.WriteOutput("Num pontos contraste: " + NumPontosContraste * 100.0 / AltTarja + "%");
return NumPontosContraste > (ParamsABT.NumMinLinhasComContraste * AltTarja);
}
public static void DeterminaInclinaçãoTarja(TParamsABT ParamsABT,
TParamsAI ParamsAI) {
if (ParamsABT.nTarjaSelecionada >= 0) {
int somax = 0, somay = 0, somaxy = 0, somax2 = 0;
int x, y;
TTarja Tarja = ParamsABT.VectorTarja.retornaTTarja(ParamsABT.nTarjaSelecionada);
int NumPontos = Tarja.VectorPontoAmarelo.size();
for (int n = 0; n < NumPontos; n++) {
x = Tarja.VectorPontoAmarelo.retornaPontoAmarelo(n).x;
y = Tarja.VectorPontoAmarelo.retornaPontoAmarelo(n).y;
somax += x;
somay += y;
somaxy += x * y;
somax2 += x * x;
}
//fórmula do coeficiente "a" da reta dos mínimos quadrados
int denominador = NumPontos * somax2 - somax * somax;
if (denominador > 0) {
ParamsAI.InclinacaoTarja = (NumPontos * somaxy - somax * somay) * 1.0 /
denominador;
COutputDebug.WriteOutput("Inclinação tarja: " + ParamsAI.InclinacaoTarja);
} else {
ParamsAI.InclinacaoTarja = 0;
}
}
}
//Mostra a linha cyan (azul claro) que representa o ponto de referência da tarja para a localização
//do identificador, e retorna a luminosidade média dos pixels da faixa
static int MediaFaixa(TParamsAI ParamsAI) {
int x, y, xIni, xFim, soma;
short[][] ImgSrc = ParamsAI.TCImgSrc.TonsCinza;
Cor[][] ImgDest = null;
if (ParamsAI.BImgDest != null) {
ImgDest = ParamsAI.BImgDest.PMCor;
}
xIni = ParamsAI.RefTarja.x;
xFim = xIni + ParamsAI.LargFaixaRef;
y = ParamsAI.RefTarja.y - ParamsAI.DistFaixaRef;
soma = 0;
for (x = xIni; x < xFim; x++) {
soma += ImgSrc[y][x];
if (ImgDest != null) {
ImgDest[y][x].SetCyan();
}
}
double retorno1 = (soma * 1.0 / ParamsAI.LargFaixaRef);
int retorno = (int) MathUtils.round(retorno1);
return retorno;
}
//---------------------------------------------------------------------------
/**
* Processa a imagem na região marcada pelo ARect agrupando os grupos conexos de pixels escuros.
* O ARect guarda a regiao detectada como o identificador na cedula.
*
* entradas de dados: CTonsCinza tcImgSrc, TRect ARect, int limiar
* saidas de dados: int[][] MatrizGrupos, TLimitesVerticaisGrupo[] VetorLimitesVerticaisGrupo, int[] PonteiroGrupos
*/
static void MatrizGruposConexos(CTonsCinza tcImgSrc, TRect ARect, int[][] MatrizGrupos, int limiar,
TLimitesVerticaisGrupo[] VetorLimitesVerticaisGrupo, int[] PonteiroGrupos) {
int x, y, i, j, n;
boolean AnteriorDentroGrupo;//informa se o pixel anteriormente processado na linha possuía um grupo
boolean AchouGrupoEncima;
boolean EmGrupoNovo = false;
int ContadorGrupos, GrupoAtual, GrupoEncima;
short[][] ImgSrc = tcImgSrc.TonsCinza;
//inicialmente cada grupo aponta para ele mesmo
for (n = 0; n < TAM_VETOR_LIMITES_VERTICAIS_GRUPOS; n++) {
PonteiroGrupos[n] = n;
}
ContadorGrupos = 1;
GrupoAtual = 0;
for (y = ARect.top + 1; y < ARect.bottom; y++) {
AnteriorDentroGrupo = false;
for (x = ARect.left + 1; x < ARect.right - 1; x++) {
if (ImgSrc[y][x] < limiar) {
if (!AnteriorDentroGrupo)//se pixel anterior (da esquerda) não possuia grupo, prossegue
{
EmGrupoNovo = true;
AchouGrupoEncima = false;
j = y - ARect.top;
//procura encima por pixels com grupo
for (n = -1; n <= 1; n++) {
i = x - ARect.left;
GrupoAtual = PonteiroGrupos[MatrizGrupos[j - 1][i + n]];
if (GrupoAtual > 0) {
AchouGrupoEncima = true;
EmGrupoNovo = false;
break;
}
}
//se não achou pixels encima então cria um novo grupo
if (!AchouGrupoEncima) {
GrupoAtual = ContadorGrupos;
VetorLimitesVerticaisGrupo[GrupoAtual].yEmb = 0;
VetorLimitesVerticaisGrupo[GrupoAtual].yEnc = 0xFFFF;
ContadorGrupos++;
}
} else //já estamos dentro de um grupo
{
//devemos sempre ver se encima existe algum grupo antigo
j = y - ARect.top - 1;
i = x - ARect.left + 1;
GrupoEncima = PonteiroGrupos[MatrizGrupos[j][i]];
if ((MatrizGrupos[j][i] > 0) && (GrupoEncima != GrupoAtual))//tem grupo antigo encima
{
if (EmGrupoNovo) {
PonteiroGrupos[GrupoAtual] = GrupoEncima;
GrupoAtual = GrupoEncima;//o grupo atual agora é o de cima
EmGrupoNovo = false;
} else {
PonteiroGrupos[GrupoEncima] = GrupoAtual;
}
}
}
j = y - ARect.top;
i = x - ARect.left;
MatrizGrupos[j][i] = GrupoAtual;
AnteriorDentroGrupo = true;
//atualiza limites verticais do grupo caso necessário
if (j > VetorLimitesVerticaisGrupo[GrupoAtual].yEmb) {
VetorLimitesVerticaisGrupo[GrupoAtual].yEmb = j;
}
if (j < VetorLimitesVerticaisGrupo[GrupoAtual].yEnc) {
VetorLimitesVerticaisGrupo[GrupoAtual].yEnc = j;
}
} else //se pixel é mais claro que o limiar
{
AnteriorDentroGrupo = false;
}
}
}
}
//---------------------------------------------------------------------------
/**
* Corta fora dos grupos conexos os grupos cujas alturas sejam muito pequenas
* em comparação com a altura da faixa preta de referencia detectada.
*/
static void SelecionaGruposIdentificador(TLimitesVerticaisGrupo[] VetorLimitesVerticaisGrupo,
char[] VetGruposValidos, int AltMin, int[] PonteiroGrupos, int yFim, int DifMinEmb) {
int altura, DifEmb;
int GrupoReal;
for (int n = 1; n < TAM_VETOR_LIMITES_VERTICAIS_GRUPOS; n++) {
GrupoReal = PonteiroGrupos[n];
altura = VetorLimitesVerticaisGrupo[GrupoReal].yEmb - VetorLimitesVerticaisGrupo[GrupoReal].yEnc;
DifEmb = yFim - VetorLimitesVerticaisGrupo[GrupoReal].yEmb;
//ifdef DEBUG
// if (altura)
if (altura > 0) {
COutputDebug.WriteOutput("Região candidata altura: " + String.valueOf(altura) +
" DifEmb: " + String.valueOf(DifEmb));
//endif
}
if (altura >= AltMin && DifEmb < DifMinEmb) {
VetGruposValidos[n] = (char) PIXEL_ACEITO;
} else {
VetGruposValidos[n] = (char) PIXEL_NAO_ACEITO;
}
}
}
//---------------------------------------------------------------------------
//MatrizGrupos é variável de entrada e de saída
static void CopiaGruposValidos(int[][] MatrizGrupos, TRect ARect, char[] VetGruposValidos) {
int x, y;
int larg, alt;
larg = ARect.Width();
alt = ARect.Height();
for (y = 0; y < alt; y++) {
for (x = 0; x < larg; x++) {
MatrizGrupos[y][x] = VetGruposValidos[MatrizGrupos[y][x]];
}
}
}
//---------------------------------------------------------------------------
static void PintaIdentificador(CBitmap BImgDest, TRect ARect, int[][] MatrizGrupos) {
int x, y;
int larg, alt;
Cor[][] ImgDest = BImgDest.PMCor;
larg = ARect.Width();
alt = ARect.Height();
for (y = 0; y < alt; y++) {
for (x = 0; x < larg; x++) {
if (MatrizGrupos[y][x] == PIXEL_ACEITO) {
ImgDest[y + ARect.top][x + ARect.left].SetCyan();
} else if (MatrizGrupos[y][x] == PIXEL_NAO_ACEITO) {
ImgDest[y + ARect.top][x + ARect.left].SetAzul();
}
}
}
}
//---------------------------------------------------------------------------
static float RetornaRelacaoMedianasLargurasEncEmb(int[] VetorLarguras, int comeco, int fim,
int[] MediaLarguras, int[] MenorLargura) {
if (fim == -1) {
return 0;
}
int alt = fim - comeco;
int[] vetor = new int[alt + 1];
int MetadeAltura = alt / 2;
int QuartoAltura = (int) MathUtils.round(alt * 1.0 / 4);
int[] Larguras = new int[2];
for (int n = 0; n < 2; n++) {
System.arraycopy(VetorLarguras, comeco + n * MetadeAltura, vetor, 0, MetadeAltura);
COrdenacao.OrdenaInt(vetor, MetadeAltura);
Larguras[n] = vetor[QuartoAltura];
}
COutputDebug.WriteOutput("Largura encima: " + String.valueOf(Larguras[0]));
COutputDebug.WriteOutput("Largura embaixo: " + String.valueOf(Larguras[1]));
MediaLarguras[0] = (Larguras[0] + Larguras[1]) / 2;
MenorLargura[0] = Larguras[0];
if (Larguras[1] < MenorLargura[0]) {
MenorLargura[0] = Larguras[1];
}
if (Larguras[1] > 0) {
return (float) (Larguras[0] * 1.0 / Larguras[1]);
} else {
return -100;
}
}
//---------------------------------------------------------------------------
static void VerificaSeTemMaisVerdeDoQueVermelho(TParamsAI ParamsAI) {
Cor[][] ImgOriginal = ParamsAI.ImagemCores.PMCor;
Cor Pixel;
int QuartoAltura = (int) (ParamsAI.AltTarja * 0.25);
int xIni, xFim, yIni, yFim, x, y;
xIni = ParamsAI.RefTarja.x + QuartoAltura;
xFim = ParamsAI.RefTarja.x + ParamsAI.AltTarja - QuartoAltura;
yIni = ParamsAI.RefTarja.y + QuartoAltura;
yFim = ParamsAI.RefTarja.y + ParamsAI.AltTarja - QuartoAltura;
int NumVerde = 0, NumVermelho = 0;
for (y = yIni; y < yFim; y += 2) {
for (x = xIni; x < xFim; x += 2) {
Pixel = ImgOriginal[y][x];
if (((Pixel.Vermelho % 255) - Pixel.Verde) > ParamsAI.DifVermelhoVerdeMin) {
NumVermelho++;
} else {
NumVerde++;
}
}
}
COutputDebug.WriteOutput("NumVerde: " + NumVerde);
COutputDebug.WriteOutput("NumVermelho: " + NumVermelho);
ParamsAI.MaisVerdeDoQueVermelho = (NumVerde > NumVermelho);
}
/**
* Analiza o identificador para detectar o valor das notas.
*/
static void AnalizaIdentificador(TParamsAI ParamsAI) {
int NADA = 0, IDENTIFICADOR = 1, FUNDO = 2;
int TAM_HIST = 200;
int EstadoUltPixel;
int x, y;
int xIni, xFim, yIni, yFim;
int YEnc, YEmb, LargLinha, MaiorLargLinha, NumBordasPixelLinha;
//usadas para guardar os limites laterais de uma linha
int XEsq, XDir;
int UltXEnc = 0, UltXEmb = 0, MaiorUltXEnc;
int NumLinha, UltYComLinha, NumPixelsIdentificador;
short[][] ImgSrc = ParamsAI.TCImgSrc.TonsCinza;
//vetores que armazenam em cada posição, qual o pixel mais escuro até o momento,
//processando ea esquerda para a direita e da direita para a esquerda.
//usados para diferenciar 5 de 1
int[] VetorMaisEscuroEsqDir, VetorMaisEscuroDirEsq;
//Usada para diferenciar 5 de 1
int MaisEscuroAteAgora;
int yImagemOriginal;
int[] VetorLarguras;
char[] VetGruposValidos = new char[TAM_VETOR_LIMITES_VERTICAIS_GRUPOS];
//usado para indicar grupos conexos que fazem parte de outros grupos
int[] PonteiroGrupos = new int[TAM_VETOR_LIMITES_VERTICAIS_GRUPOS];
boolean AchouLinha;
int[] HistogramaNumBordasPixelLinha = new int[TAM_HIST];
TRect ARect;
xIni = ParamsAI.RefTarja.x - ParamsAI.XIniParaRefTarja;
xFim = xIni + ParamsAI.LargIdentificador;
yFim = ParamsAI.RefTarja.y - ParamsAI.YIniParaRefTarja;
yIni = yFim - ParamsAI.AltIdentificador;
int TamVetLarguras = yFim - yIni + 1;
VetorLarguras = new int[TamVetLarguras];
int Media = MediaFaixa(ParamsAI);
COutputDebug.WriteOutput("Luminosidade média faixa: " + String.valueOf(Media));
int Limiar = Media - ParamsAI.DifMinMediaFaixaRef;
COutputDebug.WriteOutput("Luminosidade limiar pixel identificador: " + Limiar);
CMatrizInteiro MatrizGrupos = new CMatrizInteiro(xFim - xIni + 1, yFim - yIni + 1);
TLimitesVerticaisGrupo[] VetorLimitesVerticaisGrupo =
new TLimitesVerticaisGrupo[TAM_VETOR_LIMITES_VERTICAIS_GRUPOS];
for (int s = 0; s < TAM_VETOR_LIMITES_VERTICAIS_GRUPOS; s++) {
VetorLimitesVerticaisGrupo[s] = new TLimitesVerticaisGrupo();
}
ARect = new TRect(xIni, yIni, xFim, yFim);
COutros.LimitaTRect(ARect);
VetorMaisEscuroEsqDir = new int[ARect.Width()];
VetorMaisEscuroDirEsq = new int[ARect.Width()];
MatrizGruposConexos(ParamsAI.TCImgSrc, ARect,
MatrizGrupos.Matriz, Limiar, VetorLimitesVerticaisGrupo, PonteiroGrupos);
SelecionaGruposIdentificador(VetorLimitesVerticaisGrupo, VetGruposValidos,
ParamsAI.AltMinGrupoConexoIdentificador, PonteiroGrupos, ARect.Height(),
ParamsAI.DifMinEmbGrupoEmbRegiaoIdentificador);
CopiaGruposValidos(MatrizGrupos.Matriz, ARect, VetGruposValidos);
if (ParamsAI.BImgDest != null) {
PintaIdentificador(ParamsAI.BImgDest, ARect, MatrizGrupos.Matriz);
}
YEnc = 0;
YEmb = -1;
MaiorLargLinha = 0;
NumLinha = 0;
MaiorUltXEnc = 0;
NumPixelsIdentificador = 0;
UltYComLinha = -1;
COutputDebug.WriteOutput("Área do identificador: X: (" + xIni + ", " +
xFim + ") Y: (" + yIni + ", " + yFim + ")");
//percorre a imagem de baixo até encima
for (y = ARect.Height(); y > 0; y--) {
XEsq = -1;
XDir = 0;
AchouLinha = false;
NumBordasPixelLinha = 0;
EstadoUltPixel = NADA;
//percorre a linha para determinar os lites da linha e contar pixels
//do identificador
for (x = 0; x < ARect.Width(); x++) {
if (MatrizGrupos.Matriz[y][x] == PIXEL_ACEITO) {
if (YEmb == -1) {
YEmb = y;
}
YEnc = y;
if (XEsq == -1) {
XEsq = x;
}
XDir = x;
//se for a primeira linha
if (NumLinha == 0) {
UltXEmb = x;
}
UltXEnc = x;
AchouLinha = true;
NumPixelsIdentificador++;
if (EstadoUltPixel != IDENTIFICADOR) {
NumBordasPixelLinha++;
}
EstadoUltPixel = IDENTIFICADOR;
} else {
EstadoUltPixel = FUNDO;
}
}
LargLinha = XDir - XEsq;
if ((LargLinha > 0) && (xIni > 0) && (XEsq > 0)) {
//preenche vetor VetorMaisEscuroEsqDir
yImagemOriginal = y + yIni;
if (yImagemOriginal<0)
yImagemOriginal=0;
MaisEscuroAteAgora = 255;
int contador = 0;
for (x = xIni + XEsq; x <= (xIni + XDir); x++) {
if (ImgSrc[yImagemOriginal][x] < MaisEscuroAteAgora) {
MaisEscuroAteAgora = ImgSrc[yImagemOriginal][x];
}
VetorMaisEscuroEsqDir[contador++] = MaisEscuroAteAgora;
}
//preenche vetor VetorMaisEscuroDirEsq
MaisEscuroAteAgora = 255;
contador = XDir - XEsq;
for (x = xIni + XDir; x >= (xIni + XEsq); x--) {
if (ImgSrc[yImagemOriginal][x] < MaisEscuroAteAgora) {
MaisEscuroAteAgora = ImgSrc[yImagemOriginal][x];
}
VetorMaisEscuroDirEsq[contador--] = MaisEscuroAteAgora;
}
}//if ((LargLinha > 0) && (xIni>0) && (XEsq>0)) {
VetorLarguras[y] = LargLinha;
if (LargLinha > MaiorLargLinha) {
MaiorLargLinha = LargLinha;
}
if (AchouLinha) {
if (UltXEnc > MaiorUltXEnc) {
MaiorUltXEnc = UltXEnc;
}
NumLinha++;
UltYComLinha = y;
HistogramaNumBordasPixelLinha[NumBordasPixelLinha]++;
} else {
if ((UltYComLinha != -1) &&
((UltYComLinha - y) >= ParamsAI.MaiorDistSemPixelsIdentificador) &&
(NumPixelsIdentificador > ParamsAI.NumMinPixelsIdentificador)) {
break;
}
}
}
int soma = 0;
for (int w = 0; w < TAM_HIST; w++) {
soma += HistogramaNumBordasPixelLinha[w] * w;
}
if (NumLinha > 0) {
ParamsAI.NumMedColunas = (float) (soma * 1.0 / NumLinha);
} else {
ParamsAI.NumMedColunas = -100;
}
int[] MediaLarguras = new int[1];
int[] MenorLargura = new int[1];
ParamsAI.RelacaoMedianasLargurasEncEmb =
RetornaRelacaoMedianasLargurasEncEmb(VetorLarguras, YEnc, YEmb,
MediaLarguras, MenorLargura);
ParamsAI.Alt = YEmb - YEnc;
if (MediaLarguras[0] > 0) {
ParamsAI.RelacaoLargAlt = (float) (ParamsAI.Alt * 1.0 / MediaLarguras[0]);
} else {
ParamsAI.RelacaoLargAlt = 0;
}
if (MenorLargura[0] > 0) {
ParamsAI.RelacaoMenorLargAlt = (float) (ParamsAI.Alt * 1.0 / MenorLargura[0]);
} else {
ParamsAI.RelacaoMenorLargAlt = 0;
}
COutputDebug.WriteOutput("UltXEnc: " + String.valueOf(MaiorUltXEnc) +
"\tUltXEmb: " + String.valueOf(UltXEmb));
COutputDebug.WriteOutput("YEmb: " + String.valueOf(YEmb) + "\t\tYEnc: " + String.valueOf(YEnc));
if (ParamsAI.Alt > 0) {
ParamsAI.Inclinacao = (float) ((MaiorUltXEnc - UltXEmb) * 1.0 / ParamsAI.Alt);
} else {
ParamsAI.Inclinacao = -100;
}
ParamsAI.MaiorLargLinha = MaiorLargLinha;
Identifica(ParamsAI);
//delete [] VetorLarguras;
//delete ARect;
//delete MatrizGrupos;
}
/**
* Pega as informacoes estraidas da imagem pelas outras funcoes e faz a decisao
* sobre qual identificador foi detectado.
*/
static void Identifica(TParamsAI ParamsAI) {
//ifdef DEBUG
COutputDebug.WriteOutput("Inclinação identificador: " + String.valueOf(ParamsAI.Inclinacao));
COutputDebug.WriteOutput("Altura identificador: " + String.valueOf(ParamsAI.Alt));
COutputDebug.WriteOutput("Relação larguras identificador: " + String.valueOf(ParamsAI.RelacaoMedianasLargurasEncEmb));
if (ParamsAI.RelacaoMedianasLargurasEncEmb > 0) {
COutputDebug.WriteOutput("Relação inversa larguras identificador: " + String.valueOf(1.0 / ParamsAI.RelacaoMedianasLargurasEncEmb));
}
COutputDebug.WriteOutput("Relação Altura/Largura: " + String.valueOf(ParamsAI.RelacaoLargAlt));
COutputDebug.WriteOutput("Relação Altura/Menor Largura: " + String.valueOf(ParamsAI.RelacaoMenorLargAlt));
COutputDebug.WriteOutput("Número médio de colunas: " + String.valueOf(ParamsAI.NumMedColunas));
//endif
if ((ParamsAI.Inclinacao > ParamsAI.LimiarInclinacaoidentificador) &&
(ParamsAI.Alt > ParamsAI.LimiarAlturaIdentificador)) {
//ifdef DEBUG
COutputDebug.WriteOutput("Inclinação e altura maiores que o limite, pode ser \tR$2\tR$20");
///endif
if ((ParamsAI.RelacaoLargAlt > ParamsAI.LimiarRelacaoLargAlt)) {
//ifdef DEBUG
COutputDebug.WriteOutput("Relação Altura/Largura maior que o limite, é R$2");
//endif
ParamsAI.ValorCedula = 2;
} else {
//ifdef DEBUG
COutputDebug.WriteOutput("Relação Altura/Largura menor que o limite, é R$20");
//endif
ParamsAI.ValorCedula = 20;
}
} else {
//ifdef DEBUG
COutputDebug.WriteOutput("Inclinação menor que o limite, pode ser \tR$1\tR$5\tR$10\tR$50\tR$100");
//endif
if (ParamsAI.RelacaoMenorLargAlt > ParamsAI.LimiarRelacaoMenorLargAlt) {
//ifdef DEBUG
COutputDebug.WriteOutput("Altura maior que o limite, pode ser \tR$1\tR$5\tR$50\tR$100");
//endif
if (ParamsAI.RelacaoMedianasLargurasEncEmb > ParamsAI.LimiarLargLinhasIdentificador) {
//ifdef DEBUG
COutputDebug.WriteOutput("Relação medianas larguras maior que o limite, é R$50");
//endif
ParamsAI.ValorCedula = 50;
} else if (1.0 / ParamsAI.RelacaoMedianasLargurasEncEmb > ParamsAI.LimiarLargLinhasIdentificadorInverso) {
//ifdef DEBUG
COutputDebug.WriteOutput("Relação inversa medianas larguras maior que o limite, é R$100");
//endif
ParamsAI.ValorCedula = 100;
} else {
//ifdef DEBUG
COutputDebug.WriteOutput("Relação medianas larguras menor que o limite, pode ser \tR$1\tR$5");
//endif
if (ParamsAI.MaisVerdeDoQueVermelho) {
//ifdef DEBUG
COutputDebug.WriteOutput("Número de verde maior que o de vermelho, é R$1");
//endif
ParamsAI.ValorCedula = 1;
} else {
//ifdef DEBUG
COutputDebug.WriteOutput("Número de verde menor que o de vermelho, é R$5");
//endif
ParamsAI.ValorCedula = 5;
}
}
} else {
//ifdef DEBUG
COutputDebug.WriteOutput("Altura menor que o limite, é R$10");
//endif
ParamsAI.ValorCedula = 10;
}
}
}
//---------------------------------------------------------------------------
}