www.gusucode.com > 基于C++的TRY2LPR-1.0开源车牌识别核心-源码程序 > 基于C++的TRY2LPR-1.0开源车牌识别核心-源码程序\code\LPR\LPRProcess.cpp

    //Download by http://www.NewXing.com
/*
* Copyright (c) 2003, try2it.com
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* 
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* 
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
* 文件名称:LPRHelper.cpp
* 文件标识:LPR-02-05
* 摘要:牌照识别的图像处理部分
*
* 当前版本:1.0
* 作者:try2it.com
* 开始日期:2003年09月28日
* 完成日期:2003年09月30日
*/
#include "stdafx.h"
#include <malloc.h>
#include <math.h>
#include <stdio.h>
#include <io.h>
#include "../include/types.h"
#include "LPRHelper.h"
#include "LPRProcess.h"

/*------------------------------------------------------------------
* 以下声明全局变量
------------------------------------------------------------------*/
int g_LPHeight = 80;       
int g_LPWidth = 220;     
int g_LPAccurateHeight = 40; 
int g_BYDiff = 10;        
int g_BWDiff = 20;       
int g_BlackLP = 80;       
int g_WhiteLP = 220;      
int g_BYLP = 60;         
int g_Threshold = 160;    
int g_Threshold_HLP = 100; 
int g_LeftOffset = 0;      
int g_RightOffset = 0;    
int g_TopOffset = 0;       
int g_BottomOffset = 0;  

int InteEqualize(PGrayImg pDestImg, PGrayImg pSrcImg)
{
	int res = 0;
	int HistoGram[256];
	int bMap[256];

	int Temp, i, j;
	TGrayImg TempImg;

	res = CalHistoGram(HistoGram, pSrcImg);
	if (res == 0)
		return 0;

	res = GrayImg_Malloc(&TempImg, pSrcImg->Width, pSrcImg->Height);
	if (res == 0)
		return 0;
	
    for (i=0; i<256; i++)
    {
		Temp = 0;
        for (j=0; j<=i; j++)
			Temp = Temp + HistoGram[j];

        bMap[i] = (int)(Temp*255.0/pSrcImg->Height/pSrcImg->Width+0.5);
	}

    for (i=0; i<pSrcImg->Height; i++)
		for (j=0; j<pSrcImg->Width; j++)
        {
			*(TempImg.pImg+i*TempImg.Width+j) = (BYTE)bMap[*(pSrcImg->pImg+i*pSrcImg->Width+j)];
		}

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;

	if (pDestImg->pImg) 
	{
		pDestImg->pImg = NULL;
	}

	pDestImg->pImg = TempImg.pImg;

	return res;
}

int CalHistoGram(int HistoGram[], PGrayImg pSrcImg)
{
	int i, j;
	
	for (i=0; i<256; i++) HistoGram[i] = 0;

	for (i=0; i<pSrcImg->Height; i++)
		for (j=0; j<pSrcImg->Width; j++)
			HistoGram[*(pSrcImg->pImg+i*pSrcImg->Width+j)]++;

	return 1;
}

int MedianFilter(PGrayImg pDestImg, PGrayImg pSrcImg, int iFilterH, 
				               int iFilterW, int iFilterMX, int iFilterMY)
{
	int i, j, l, k;
	int res = 0;
	BYTE *aValue;

	TGrayImg TempImg;

	res = GrayImg_Malloc(&TempImg, pSrcImg->Width, pSrcImg->Height);
	if (res == 0)
		return 0;

	aValue = (BYTE*)malloc(iFilterH * iFilterW);
	if (aValue == NULL)
		return 0;

	for (i=iFilterMY; i<=TempImg.Height-iFilterH+iFilterMY; i++)
		for (j=iFilterMX; j<=TempImg.Width-iFilterW+iFilterMX; j++)
		{
			for (k=0; k<iFilterH; k++)
				for (l=0; l<iFilterW; l++)
				{
					*(aValue+k*iFilterW+l) = *(pSrcImg->pImg+(i-iFilterMY+k)*TempImg.Width+j-iFilterMX+1);
				}
			*(TempImg.pImg+i*TempImg.Width+j) = GetMedianNum(aValue, iFilterH*iFilterW);
		}

	if (aValue!=NULL)
		free(aValue);

	for (i=0; i<TempImg.Height; i++)
		for (j=0; j<iFilterMX; j++)
			*(TempImg.pImg+i*TempImg.Width+j) = *(pSrcImg->pImg+i*pSrcImg->Width+j);

	for (i=0; i<TempImg.Height; i++)
		for (j=TempImg.Width-iFilterW+iFilterMX+1; j<TempImg.Width; j++)
			*(TempImg.pImg+i*TempImg.Width+j) = *(pSrcImg->pImg+i*pSrcImg->Width+j);

	for (i=0; i<iFilterMY; i++)
		for (j=0; j<TempImg.Width; j++)
			*(TempImg.pImg+i*TempImg.Width+j) = *(pSrcImg->pImg+i*pSrcImg->Width+j);

	for (i=TempImg.Height-iFilterH+iFilterMY+1; i<TempImg.Height; i++)
		for (j=0; j<TempImg.Width; j++)
			*(TempImg.pImg+i*TempImg.Width+j) = *(pSrcImg->pImg+i*pSrcImg->Width+j);

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	if (pDestImg->pImg)
	{
		pDestImg->pImg = NULL;
	}
	pDestImg->pImg = TempImg.pImg;

	return res;
}

BYTE GetMedianNum(BYTE *aValue, int iLength)
{
	int i, j;
	BYTE tmp;

	for (j=1; j<iLength; j++)
		for (i=0; i<iLength-j; i++)
		{
			if ((*(aValue+i)) > (*(aValue+i+1)))
			{
				tmp = *(aValue+i);
				*(aValue+i) = *(aValue+i+1);
				*(aValue+i+1) = tmp;
			}
		}

	if ((iLength & 1) > 0)
	{
		tmp = *(aValue+(iLength+1)/2);
	}
	else
	{
		tmp = (*(aValue+iLength/2) + *(aValue+iLength/2+1))/2;
	}

	return tmp;
}

int GetLPPos(RECT *lpRect, PGrayImg pSrcImg)
{
	int res = 0;
	static int TemplateArr[9] = {1,0,-1,   
                                 2,0,-2,
								 1,0,-1};
	static int TemplateArr1[9] = {1,1,1,   
		                          1,0,1,
								  1,1,1};

	TGrayImg EdgeImg;          
	TGrayImg TwoImg;          
	TGrayImg HLPImg, HLPImg1, HLPImg2; 

	int StartYPos=0;           
	int UpYPos=0, DownYPos=0;  
	int LeftXPos=0, RightXPos=0; 
	int Threshold;            

	RECT Rect;

	int *pHProject = NULL;      
	int *pVProject = NULL;    

	BOOL flag;

	res = Template(&EdgeImg, pSrcImg, TemplateArr, 3 ,1);
	if (res == 0)
		return 0;

	StartYPos = EdgeImg.Height - 1;
	Threshold = g_Threshold;

	pHProject = (int*)malloc(pSrcImg->Height*sizeof(int));
	if (NULL == pHProject)
		return 0;

	flag = TRUE;
	while(flag)
	{
		res = TwoPixelCarImg(&TwoImg, &EdgeImg, Threshold);
		if (0 == res)
			return 0;

		res = ProjectImg(pHProject, &TwoImg, H_FILTER);
		if (0 == res)
			return 0;

		res = ProjectFilter(pHProject, TwoImg.Height, H_FILTER);
		if (0 == res)
			return 0;

		res = GetLPYPos(pHProject, TwoImg.Height, &StartYPos, &UpYPos, &DownYPos);
		if (0 == res)
		{
			Threshold -= 10;
			if (Threshold < 50)
			{
				return 0;
			}
		}
		else
		{
			flag = FALSE;
		}

	}
	
	LeftXPos = 0;
	RightXPos = pSrcImg->Width - 1;
	Rect.left = LeftXPos;
	Rect.top = UpYPos;
	Rect.right = RightXPos;
	Rect.bottom = DownYPos;

	res = GetSubImg(&HLPImg1, &EdgeImg, Rect);
	if (0 == res)
		return 0;

////////////////////////////////////////////////////////////////////////////////////////////
	res = Template(&HLPImg2, &HLPImg1, TemplateArr1, 3, 1.0/8.0);
	if (0 == res)
		return 0;

	res = TwoPixelCarImg(&HLPImg, &HLPImg2, g_Threshold_HLP);
	if (0 == res)
		return 0;

	GrayImg_Free(&HLPImg1);
	GrayImg_Free(&HLPImg2);

	pVProject = (int*)malloc(pSrcImg->Width*sizeof(int));
	if (NULL == pVProject)
		return 0;

	res = ProjectImg(pVProject, &HLPImg, V_FILTER);
	if (0 == res)
		return 0;

	res = ProjectFilter(pVProject, pSrcImg->Width, V_FILTER, g_LPAccurateHeight);
	if (0 == res)
		return 0;

	flag = TRUE;
	while(flag)
	{
		res = GetLPXPos(pVProject, pSrcImg->Width, &LeftXPos, &RightXPos);
		if (0 == res)
		{
			res = GetLPYPos(pHProject, pSrcImg->Height, &StartYPos, &UpYPos, &DownYPos);
			if (0 == res)
			{
				StartYPos = pSrcImg->Height - 1;
				res = GetLPYPos(pHProject, pSrcImg->Height, &StartYPos, &UpYPos, &DownYPos);
				if (0 == res)
					return 0;
				else 
				{
					res = GetLPXPos(pVProject, pSrcImg->Width, &LeftXPos, &RightXPos);
					if (0 == res)
						return 0;
					else
					{
						RightXPos += (int)(g_LPWidth * 0.8 + 0.5);
						flag = FALSE;
					}
				}
			}
		}
		else
		{
			if (RightXPos - LeftXPos < 0.6 * g_LPWidth)
			{
				res = GetLPYPos(pHProject, pSrcImg->Height, &StartYPos, &UpYPos, &DownYPos);
				if (0 == res)
				{
					StartYPos = pSrcImg->Height - 1;
					res = GetLPYPos(pHProject, pSrcImg->Height, &StartYPos, &UpYPos, &DownYPos);
					if (0 == res)
						return 0;
					else 
					{
						res = GetLPXPos(pVProject, pSrcImg->Width, &LeftXPos, &RightXPos);
						if (0 == res)
							return 0;
						else
						{
						   RightXPos += (int)(g_LPWidth * 0.8 + 0.5);
						   flag = FALSE;
						}
					}
				}
			}
			else
				flag = FALSE;
		}
	}

	if (pHProject!=NULL)
	{
		free(pHProject);
		pHProject = NULL;
	}

	if (pVProject!=NULL)
	{
		free(pVProject);
		pVProject = NULL;
	}

	lpRect->left = LeftXPos;
	lpRect->right = RightXPos;
	lpRect->top = UpYPos;
	lpRect->bottom = DownYPos;
	
	GrayImg_Free(&HLPImg);
	GrayImg_Free(&TwoImg);
	GrayImg_Free(&EdgeImg);

	return 1;
}

int GetLPYPos(int *pProject, int PrjLen, int *pStartYPos, int *pUpYPos, int *pDownYPos)
{
	int y, Temp;
	BOOL Flag;

	Flag = TRUE;
	*pDownYPos = 0;
	*pUpYPos = 0;
	*(pProject+PrjLen-1) = 0;

	for (y=*pStartYPos; y>=0; y--)
	{
		if ((*(pProject+y)!=0) && Flag)
		{
			*pDownYPos = y;
			Flag = FALSE;
		}
		if ((*(pProject+y) == 0) && (!Flag))
		{
		   *pUpYPos = y;
		   break;
		}
	}

	*pStartYPos = *pUpYPos;

	if (*pDownYPos <= *pUpYPos)
	{
		*pStartYPos = PrjLen-1;
		return 0;
	}

	Temp = *pDownYPos - *pUpYPos;
	if (Temp < g_LPHeight)
	{
	  *pDownYPos = *pDownYPos + (int)((g_LPHeight - Temp) * 0.6 + 0.5);
	  if (*pDownYPos > PrjLen - 1)
		   *pDownYPos = PrjLen - 1;

	  *pUpYPos = *pUpYPos - (int)((g_LPHeight - Temp) * 0.4 + 0.5);

	  if (*pUpYPos < 0)
		   *pUpYPos = 0;
	}

	if (Temp > g_LPHeight * 1.5)
	{
		*pDownYPos = *pDownYPos + (int)(g_LPHeight * 0.125 + 0.5);

		if (*pDownYPos > PrjLen - 1)
		   *pDownYPos = PrjLen - 1;

		*pUpYPos = *pDownYPos - g_LPHeight;

		*pUpYPos = *pUpYPos - (int)(g_LPHeight * 0.15 + 0.5);

		if (*pUpYPos < 0)
			*pUpYPos = 0;
	}

	return 1;
}

int GetLPXPos(int *pProject, int PrjLen, int *pLeftXPos, int *pRightXPos)
{
	int x, Temp;
	int TempLeft, TempRight;
	BOOL flag;

	flag = TRUE;
	Temp = 0;

	*pLeftXPos = 0; 
	*pRightXPos = 0;

	*(pProject+PrjLen-1) = 0;

	for (x=0; x<PrjLen; x++)
	{
		if (flag && (*(pProject+x) != 0))
		{
			TempLeft = x;
			flag = FALSE;
		}

		if ((!flag) && (*(pProject+x) == 0))
		{
			TempRight = x;
			flag = TRUE;
			if (Temp < TempRight - TempLeft)
			{
				*pLeftXPos = TempLeft;
				*pRightXPos = TempRight;
				Temp = TempRight - TempLeft;
			}
		}
	}

	if (*pRightXPos <= *pLeftXPos)
	{
		return 0;
	}
	
	return 1;
}

int Template(PGrayImg pDestImg, PGrayImg pSrcImg, int TemplateArr[], int TemplateN, double Coef)
{
	int temp, y, x, i, j;
	int res = 0;
	TGrayImg TempImg;

	res = GrayImg_Malloc(&TempImg, pSrcImg->Width, pSrcImg->Height);
	if (res == 0)
		return 0;

	for (x=TemplateN/2; x<pSrcImg->Height-TemplateN/2; x++)
		for (y=TemplateN/2; y<pSrcImg->Width-TemplateN/2; y++)
		{
			temp = 0;
			for (i=-TemplateN/2; i<=TemplateN/2; i++)
				for (j=-TemplateN/2; j<=TemplateN/2; j++)
					temp = temp + *(pSrcImg->pImg+(x+i)*pSrcImg->Width+(y+j)) *
		                 TemplateArr[(i+TemplateN/2)*TemplateN+j+TemplateN/2];

			temp = (int)(abs(temp) * Coef + 0.5);

			if (temp > 255)
				temp = 255;

			*(TempImg.pImg+x*TempImg.Width+y) = temp;
		}
	
	for (x=0; x<pSrcImg->Height; x++)
		for (y=0; y<TemplateN/2; y++)
			*(TempImg.pImg+x*TempImg.Width+y) = 0;

	for (x=0; x<pSrcImg->Height; x++)
		for (y=pSrcImg->Width-TemplateN/2; y<pSrcImg->Width; y++)
			*(TempImg.pImg+x*TempImg.Width+y) = 0;

	for (x=0; x<TemplateN/2; x++)
		for (y=0; y<pSrcImg->Width; y++)
			*(TempImg.pImg+x*TempImg.Width+y) = 0;

	for (x=pSrcImg->Height-TemplateN/2; x<pSrcImg->Height; x++)
		for (y=0; y<pSrcImg->Width; y++)
			*(TempImg.pImg+x*TempImg.Width+y) = 0;

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	pDestImg->pImg = TempImg.pImg;

	return 1;
}

int ProjectImg(int *pProject, PGrayImg pSrcImg,  TPrjType PrjType)
{
	int i, j;

	switch (PrjType)
	{
	case H_FILTER:

		for (i=0; i<pSrcImg->Height; i++)
			*(pProject+i) = 0;

		for (i=0; i<pSrcImg->Height; i++)
			for (j=0; j<pSrcImg->Width; j++)
				*(pProject+i) += *(pSrcImg->pImg+i*pSrcImg->Width+j);

		*(pProject+pSrcImg->Height-1) = 0;

		break;

	case V_FILTER:

		for (i=0; i<pSrcImg->Width; i++)
			*(pProject+i) = 0;

		for (i=0; i<pSrcImg->Height; i++)
			for (j=0; j<pSrcImg->Width; j++)
				*(pProject+j) += *(pSrcImg->pImg+i*pSrcImg->Width+j);

		*(pProject+pSrcImg->Width-1) = 0;

		break;

	default:
		return 0;
	}
	return 1;
}

int ProjectFilter(int *pProject, int PrjLen, TPrjType PrjType, int LPAccurateHeight)
{
	int i, j, p;
	int Temp, Temp1;
	BOOL Flag1, Flag2;
	int avg, CharID;
	int TempLeft[100], TempRight[100];
	int TempWidth[100], MergeID[100];

	*(pProject + PrjLen - 1) = 0;

	switch (PrjType)
	{
	case H_FILTER:  
		for (i=0; i<PrjLen; i++)
		{
			if (*(pProject+i) <  38 * 255)
				*(pProject+i) = 0;
		}
		Flag1 = TRUE;

		for (i=0; i<PrjLen; i++)
		{
			avg = 0;
			if ((*(pProject+i) != 0) && Flag1)
			{
				Temp = i;
				Flag1 = FALSE;
			}
			if ((*(pProject+i) == 0) && (!Flag1))
			{
				for (j=Temp; j<=i; j++)
					avg = avg + *(pProject+j) / 255;

				avg = avg / (i - Temp);

				if ((i-Temp<(int)(g_LPHeight*0.35+0.5)) ||
							(avg<(int)(g_LPWidth*0.30+0.5)))
				{
					for (j=Temp; j<i; j++)
						*(pProject+j) = 0;
				}

				Flag1 = TRUE;
			}
		}
		break;

	case V_FILTER:
		for (j=0; j<PrjLen; j++)
        {
			if (*(pProject+j) < (int)(0.2*g_LPHeight*255+0.5))
				*(pProject+j) = 0;
		}
		Flag1 = TRUE;
		for (i=0; i<PrjLen; i++)
		{
			avg = 0;
			if ((*(pProject+i)!=0) && Flag1)
			{
				Temp = i;
				Flag1 = FALSE;
			}
			
			if ((*(pProject+i) == 0) && (!Flag1))
			{
				for (j=Temp; j<=i; j++)
					avg = avg + *(pProject+j)/255;

				avg = avg / (i - Temp);

				if ((i-Temp<(int)(g_LPWidth*0.015+0.5)) ||
								(avg<(int)(g_LPHeight*0.15+0.5)))
				{
					for (j=Temp; j<i; j++)
						*(pProject+j) = 0;
				}
				Flag1 = TRUE;
			}
		}

		Flag2 = TRUE; Flag1 = TRUE;
		for (i=0; i<PrjLen; i++)
		{
			if ((*(pProject+i)!=0) && Flag1)
			{
				Flag1 = FALSE;
			}

			if ((*(pProject+i)==0) && (!Flag1))
			{
				Temp1 = i;
				Flag1 = TRUE;
				Flag2 = FALSE;
			}

			if ((*(pProject+i)!=0) && (!Flag2))
			{
				if ((i-Temp1)<(int)(0.11*g_LPWidth+0.5))
				{
					for (j=Temp1; j<i; j++)
						*(pProject+j) = 17 * 255;
				}
				Flag2 = TRUE;
			}
		}

		Flag1 = TRUE; Temp = 0;
		for (i=0; i<PrjLen; i++)
		{
			if ((*(pProject+i) != 0) && Flag1)
			{
				Temp = i;
				Flag1 = FALSE;
			}

			if ((*(pProject+i)==0) && (!Flag1))
			{
				if (i-Temp > (int)(g_LPWidth*1.5+0.5))
				{
					for (j=Temp; j<i; j++)
						*(pProject+j) = 0;
				}
				Flag1 = TRUE;
			}
		}
		break;

	case IH_FILTER :
		
		for (i=0; i<PrjLen; i++)
		{
			if (*(pProject+i) < 16 * 255)
			{
				*(pProject+i) = 0;
			}
		}
		break;

	case IV_FILTER :
		for (i=0; i<PrjLen; i++)
		{
			if (*(pProject+i) < (int)(0.1*LPAccurateHeight+0.5)*255)
		        *(pProject+i) = 0;
		}
		
		Flag1 = TRUE;
		for (i=0; i<PrjLen; i++)
		{
			if ((*(pProject+i) != 0) && Flag1)
			{
				Temp = i;
				Flag1 = FALSE;
			}

			if ((*(pProject+i) == 0) && (!Flag1))
			{
				if (i - Temp < (int)(0.2 * LPAccurateHeight + 0.5))
				{
					for (j=Temp; j<i; j++)
						if (*(pProject+j) < (int)(0.3*LPAccurateHeight + 0.5)*255)
							*(pProject+j) = 0;
				}
				Flag1 = TRUE;
			}
		}

		if (PrjLen > (int)(4.6 * LPAccurateHeight + 0.5))
		{
			Flag2 = TRUE; Flag1 = TRUE;
			for (i=0; i<=(int)((PrjLen-1)/3.0); i++)
			{
				if ((*(pProject+i) != 0) && Flag1)
				{
					Flag1 = FALSE;
				}
				
				if ((*(pProject+i) == 0) && (!Flag1))
				{
					Temp1 = i;         
					Flag1 = TRUE;
					Flag2 = FALSE;
				}

		        if ((*(pProject+i) != 0) && (!Flag2))
				{
					if (i-Temp1 > (int)(0.6*LPAccurateHeight+0.5))
					{
						for (j=i-1; j>=0; j--)
							*(pProject+j) = 0;
					}
					Flag2 = TRUE;
				}
			}

			Flag1 = TRUE;
			CharID = 0;
			for (i=0; i<=(int)((PrjLen-1)/2.0); i++)
			{
				if ((*(pProject+i) != 0) && Flag1)
				{
					TempLeft[CharID] = i;
					Flag1 = FALSE;
				}

				if ((*(pProject+i) == 0) && (!Flag1))
				{
					TempRight[CharID] = i;
					TempWidth[CharID] = TempRight[CharID] - TempLeft[CharID];
					CharID++;
					if (CharID > 100)
					{
						return 0;
					}

					Flag1 = TRUE;
				}
			}

			j = 0;
			for (i=0; i<CharID; i++)
			{
				if (TempWidth[i] < (int)(0.35*LPAccurateHeight+0.5))
				{
					MergeID[j] = i;
					j++;
				}

				if ((i==CharID-1) || (TempWidth[i]>=(int)(0.35*LPAccurateHeight+0.5)))
				{
					 if (j > 1)
					 {
						for (p=TempLeft[MergeID[0]]; p<=TempRight[MergeID[j-1]]; p++)
						{
						   *(pProject+p) = (int)(0.5 * LPAccurateHeight + 0.5) * 255;
						}
					 }
					 j = 0;
				}
			}
		}

		Flag1 = TRUE;
		for (i=0; i<PrjLen; i++)
		{
			if ((*(pProject+i) != 0) && Flag1)
			{
				Temp = i;
				Flag1 = FALSE;
			}

			if ((*(pProject+i) == 0) && (!Flag1))
			{
				if (i-Temp < (int)(0.3*LPAccurateHeight+0.5))
				{
					for (j=Temp; j<i; j++)
						*(pProject+j) = 0;
				}
				Flag1 = TRUE;
			}
		}

		break;

	default:
		return 0;
	}

	return 1;
}

int TwoPixelCarImg(PGrayImg pDestImg, PGrayImg pSrcImg, int Threshold)
{
	int i, j;
	int res = 0;
	TGrayImg TempImg;

	res = GrayImg_Malloc(&TempImg, pSrcImg->Width, pSrcImg->Height);
	if (res == 0)
		return 0;

	for (i=0; i<pSrcImg->Height; i++)
		for (j=0; j<pSrcImg->Width; j++)
		{
			if (*(pSrcImg->pImg+i*pSrcImg->Width+j) > Threshold)
				*(TempImg.pImg+TempImg.Width*i+j) = 255;
			else
				*(TempImg.pImg+TempImg.Width*i+j) = 0;
		}

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	pDestImg->pImg = TempImg.pImg;

	return 1;
}

int GetSubImg(PGrayImg pDestImg, PGrayImg pSrcImg, RECT Rect)
{
	int i, j;
	int res = 0;
	TGrayImg TempImg;

	int Left=0, Right=0, Top=0, Bottom=0;

	res = GrayImg_Malloc(&TempImg, Rect.right-Rect.left+1, Rect.bottom-Rect.top+1);
	if (0 == res)
		return 0;

	for (i=Rect.top; i<=Rect.bottom; i++)
		for (j=Rect.left; j<=Rect.right; j++)
		{
			if ((i>=0 && i<pSrcImg->Height) && (j>=0 && j<pSrcImg->Width))
				*(TempImg.pImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = *(pSrcImg->pImg+i*pSrcImg->Width+j);
			else
				*(TempImg.pImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = 0;
		}

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	pDestImg->pImg = TempImg.pImg;

	return 1;
}

int GetSubColorImg(PColorImg pDestImg, PColorImg pSrcImg, RECT Rect)
{
	int i, j;
	int res = 0;
	TColorImg TempImg;

	res = ColorImg_Malloc(&TempImg, Rect.right-Rect.left+1, Rect.bottom-Rect.top+1);
	if (0 == res)
		return 0;

	for (i=Rect.top; i<=Rect.bottom; i++)
		for (j=Rect.left; j<=Rect.right; j++)
		{
			if ((i>=0 && i<pSrcImg->Height) && (j>=0 && j<pSrcImg->Width))
			{
				*(TempImg.pRImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = *(pSrcImg->pRImg+i*pSrcImg->Width+j);
				*(TempImg.pGImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = *(pSrcImg->pGImg+i*pSrcImg->Width+j);
				*(TempImg.pBImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = *(pSrcImg->pBImg+i*pSrcImg->Width+j);
				*(TempImg.pYImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = *(pSrcImg->pYImg+i*pSrcImg->Width+j);
			}
			else
			{
				*(TempImg.pRImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = 0;
				*(TempImg.pGImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = 0;
				*(TempImg.pBImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = 0;
				*(TempImg.pYImg+(i-Rect.top)*TempImg.Width+(j-Rect.left)) = 0;
			}
		}
	TempImg.BitCount = pSrcImg->BitCount;

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	pDestImg->pRImg = TempImg.pRImg;
	pDestImg->pGImg = TempImg.pGImg;
	pDestImg->pBImg = TempImg.pBImg;
	pDestImg->pYImg = TempImg.pYImg;
	pDestImg->BitCount = TempImg.BitCount;

	return 1;
}

int RecoLPColor(TColorID *pLPColorID, PColorImg pSrcImg)
{
	int i, j;
	int ACount[4];
	int Temp;
	BYTE R, G, B;

	ACount[LP_BLACK] = 0;
	ACount[LP_BLUE] = 0; 
	ACount[LP_YELLOW] = 0; 
	ACount[LP_WHITE] = 0;

	for (i=(int)(0.15*pSrcImg->Height+0.5); i<(int)(pSrcImg->Height-0.15*pSrcImg->Height+0.5); i++)
		for (j=(int)(0.15*pSrcImg->Width+0.5); j<(int)(pSrcImg->Width-0.15*pSrcImg->Width+0.5); j++)
		{
			R = *(pSrcImg->pRImg+i*pSrcImg->Width+j);
			G = *(pSrcImg->pGImg+i*pSrcImg->Width+j);
			B = *(pSrcImg->pBImg+i*pSrcImg->Width+j);

			if ((B-G>g_BYDiff) && (B-R>g_BYDiff) && (B>g_BYLP))
				  ACount[LP_BLUE]++;

			if ((R-B>g_BYDiff) && (G-B>g_BYDiff) && (R>g_BYLP) && (G>g_BYLP))
				  ACount[LP_YELLOW]++;

			if ((B<g_BlackLP)&&(G<g_BlackLP)&&(R<g_BlackLP)&&(abs(G-B)<g_BWDiff)&&(abs(G-R)<g_BWDiff)&&(abs(B-R)<g_BWDiff))
				  ACount[LP_BLACK]++;

			if ((R>g_WhiteLP)&&(G>g_WhiteLP)&&(B>g_WhiteLP)&&(abs(G-B)<g_BWDiff)&&(abs(G-R)<g_BWDiff)&&(abs(B-R)<g_BWDiff))
				  ACount[LP_WHITE]++;
		}

	Temp = ACount[LP_BLUE];
	*pLPColorID = LP_BLUE;

	for (i=0; i<4; i++)
		if (Temp < ACount[i])
		{
			Temp = ACount[i];
			*pLPColorID = (TColorID)i;
		}
	return 1;
}

int TwoPixelLPImg(PGrayImg pDestImg, PGrayImg pSrcImg, 
				    double MaxBlackRatio, double MinBlackRatio, int *pThreshold)
{
	int i, j;
	int res = 0;
	int TempArray[9] = {1,1,1,
		                1,0,1,
						1,1,1};
	int TempArray1[9] = {-1,0,1,
						 -1,0,1,
						 -1,0,1};
	int *pProject=NULL;
	int WhitePixelCount, BlackPixelCount;
	int Bottom, Top;
	BOOL StopFlag1, StopFlag2;

	TGrayImg TempImg, EdgeImg, TempImg1;

	Top = 0;
	Bottom = pSrcImg->Height-1;

	res = Template(&EdgeImg, pSrcImg, TempArray1, 3, 1);
	if (0 == res)
		return 0;

	res = Template(&TempImg1, &EdgeImg, TempArray, 3, 1.0/8.0);
	if (0 == res)
		return 0;

	res = TwoPixelCarImg(&TempImg, &TempImg1, g_Threshold_HLP);
	if (0 == res)
		return 0;

	pProject = (int*)malloc(pSrcImg->Height*sizeof(int));
	if (pProject == NULL)
		return 0;

	res = ProjectImg(pProject, &TempImg, H_FILTER);
	if (0 == res)
		return 0;

	for (i=0; i<pSrcImg->Height; i++)
		if (*(pProject+i) < int(0.25*pSrcImg->Height))
			*(pProject+i) = 0;

	for (i=pSrcImg->Height/2; i>=0; i--)
	{
		if (*(pProject+i) == 0)
		{
			Top = i;
			break;
		}
	}
	for (i=pSrcImg->Height/2; i<pSrcImg->Height; i++)
	{
		if (*(pProject+i) == 0)
		{
			Bottom = i;
			break;
		}
	}

	if (pProject)
		free(pProject);

	GrayImg_Free(&EdgeImg);
	GrayImg_Free(&TempImg1);
	GrayImg_Free(&TempImg);

	*pThreshold = 50;

	res = GrayImg_Malloc(&TempImg, pSrcImg->Width, pSrcImg->Height);
	if (res == 0)
		return 0;

	StopFlag1 = FALSE;
    StopFlag2 = FALSE;

	while(TRUE)
	{
		BlackPixelCount = 0;
		WhitePixelCount = 0;

		for (i=0; i<pSrcImg->Height; i++)
			for (j=0; j<pSrcImg->Width; j++)
			{
				if (*(pSrcImg->pImg+i*pSrcImg->Width+j) > *pThreshold)
				{
					if (i>=Top && i<=Bottom)
						WhitePixelCount++;
					*(TempImg.pImg+i*TempImg.Width+j) = 255;
				}
				else
				{
					if (i>=Top && i<=Bottom)
						BlackPixelCount++;
					*(TempImg.pImg+i*TempImg.Width+j) = 0;
				}
			}

		if ((BlackPixelCount<=(int)(MaxBlackRatio*(BlackPixelCount+WhitePixelCount)+0.5))
		    && (BlackPixelCount>=(int)(MinBlackRatio*(BlackPixelCount+WhitePixelCount)+0.5)))
			break;

		if (BlackPixelCount>(int)(MaxBlackRatio*(BlackPixelCount+WhitePixelCount)+0.5))
		{
			StopFlag1 = TRUE;
			*pThreshold -= 5;
			if (StopFlag2)
				break;
		}

		if (BlackPixelCount < (int)(MinBlackRatio*(BlackPixelCount+WhitePixelCount)+0.5))
		{
			StopFlag2 = TRUE;
			*pThreshold += 5;
			if (StopFlag1)
				break;
		}
	}

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	pDestImg->pImg = TempImg.pImg;

	return 1;
}

int Invert(PGrayImg pDestImg, PGrayImg pSrcImg)
{
	int i, j;
	int res = 0;
	TGrayImg TempImg;

	res = GrayImg_Malloc(&TempImg, pSrcImg->Width, pSrcImg->Height);
	if (0 == res)
		return 0;

	for (i=0; i<pSrcImg->Height; i++)
		for (j=0; j<pSrcImg->Width; j++)
		{
			*(TempImg.pImg+i*TempImg.Width+j) = 255 - *(pSrcImg->pImg+i*pSrcImg->Width+j);
		}

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	pDestImg->pImg = TempImg.pImg;

	return 1;
}

int RectifyLP(PGrayImg pDestImg, PGrayImg pSrcImg, PGrayImg pModelImg)
{
	int i, j;
	int res = 0;
	TAngle Angle;

	double RectifyAngle;
	int iAngle;

	TGrayImg TempImg1, TempImg2;
	TGrayImg RowDiffImg;
    
	res = Diff(&RowDiffImg, pModelImg, H_FILTER);
	if (0 == res)
		return 0;

	res = HoughTrans(&Angle, &RowDiffImg, V_FILTER);
	if (0 == res)
		return 0;

	res = GrayImg_Free(&RowDiffImg);
	if (0 == res)
		return 0;

	res = Diff(&RowDiffImg, pModelImg, V_FILTER);
	if (0 == res)
		return 0;

	res = HoughTrans(&Angle, &RowDiffImg, H_FILTER);
	if (0 == res)
		return 0;

	res = GrayImg_Free(&RowDiffImg);
	if (0 == res)
		return 0;

	res = GrayImg_Malloc(&TempImg1, pSrcImg->Width, pSrcImg->Height);
	if (0 == res)
		return 0;

	for (i=0; i<pSrcImg->Height; i++)
		for (j=0; j<pSrcImg->Width; j++)
			*(TempImg1.pImg+i*TempImg1.Width+j) = 0;

	if (fabs(Angle.HAngle+90) != 90.0) 
		RectifyAngle = -(Angle.HAngle + 90.0)/180.0*PI;

	for (i=0; i<pSrcImg->Width; i++)
		for (j=0; j<pSrcImg->Height; j++)
		{
			if (i*tan(RectifyAngle) < 0.0)
				iAngle = (int)(i*tan(RectifyAngle)-0.5);
			else
				iAngle = (int)(i*tan(RectifyAngle)+0.5);
			
			if ((j-iAngle >= 0) && (j-iAngle < pSrcImg->Height))
				*(TempImg1.pImg+j*TempImg1.Width+i) = *(pSrcImg->pImg+(j-iAngle)*pSrcImg->Width+i);
		}

	res = GrayImg_Malloc(&TempImg2, pSrcImg->Width, pSrcImg->Height);
	if (0 == res)
		return 0;

	for (i=0; i<pSrcImg->Height; i++)
		for (j=0; j<pSrcImg->Width; j++)
			*(TempImg2.pImg+i*TempImg2.Width+j) = 0;

	if (fabs(Angle.VAngle) != 90.0)
		RectifyAngle = Angle.VAngle/180.0*PI;

	for (i=0; i<TempImg1.Height; i++)
		for (j=0; j<TempImg1.Width; j++)
		{
			if (i*tan(RectifyAngle) < 0.0)
				iAngle = (int)(i*tan(RectifyAngle)-0.5);
			else
				iAngle = (int)(i*tan(RectifyAngle)+0.5);

			if ((j-iAngle >= 0) && (j-iAngle < TempImg1.Width))
				*(TempImg2.pImg+i*TempImg2.Width+j) = *(TempImg1.pImg+i*TempImg1.Width+j-iAngle);
		}

	res = GrayImg_Free(&TempImg1);
	if (0 == res)
		return 0;

	pDestImg->Width = TempImg2.Width;
	pDestImg->Height = TempImg2.Height;
	pDestImg->pImg = TempImg2.pImg;

	return 1;

}

int Diff(PGrayImg pDestImg, PGrayImg pSrcImg, TPrjType PrjType)
{
	int i, j;
	int Temp;
	int res = 0;
	TGrayImg TempImg;

	res = GrayImg_Malloc(&TempImg, pSrcImg->Width, pSrcImg->Height);
	if (res == 0)
		return 0;

	switch(PrjType)
	{
	
	case H_FILTER:  

		for (i=0; i<pSrcImg->Height; i++)
			*(TempImg.pImg+i*TempImg.Width+0) = 0;

		for (i=0; i<pSrcImg->Height; i++)
			for (j=1; j<pSrcImg->Width; j++)
			{
				Temp = abs(*(pSrcImg->pImg+i*pSrcImg->Width+j)-*(pSrcImg->pImg+i*pSrcImg->Width+j-1));
				if (Temp > 80)
					Temp = 255;
				else
					Temp = 0;

				*(TempImg.pImg+i*TempImg.Width+j) = Temp;
			}

		break;

	case V_FILTER: 

		for (j=0; j<pSrcImg->Width; j++)
			*(TempImg.pImg+0+j) = 0;

		for (j=0; j<pSrcImg->Width; j++)
			for (i=1; i<pSrcImg->Height; i++)
			{
				Temp = abs(*(pSrcImg->pImg+i*pSrcImg->Width+j)-*(pSrcImg->pImg+(i-1)*pSrcImg->Width+j));
				
				if (Temp > 80)
					 Temp = 255;
				else
					 Temp = 0;

				*(TempImg.pImg+i*TempImg.Width+j) = Temp;
			}
		break;

	default:
		return 0;
	}

	pDestImg->Width = TempImg.Width;
	pDestImg->Height = TempImg.Height;
	pDestImg->pImg = TempImg.pImg;

	return 1;
}

int HoughTrans(PAngle pAngle, PGrayImg pSrcImg, TPrjType PrjType)
{
	int i, j, p, o, Max, Tempo;
	int *H;
	int HWidth, HHeight;
	double temp;

	o = -90; p = 0;

	HHeight = 4 * pSrcImg->Width + 1;
	HWidth = 181;
    H = (int*)malloc(HWidth*HHeight*sizeof(int));
	if (NULL == H)
		return 0;

	for (i=-(HHeight/2); i<=(HHeight/2); i++)
		for (j=-(HWidth/2); j<=(HWidth/2); j++)
			*(H+(i+HHeight/2)*HWidth+j+HWidth/2) = 0;

	switch (PrjType)
	{
	case H_FILTER: 

		for (i=0; i<pSrcImg->Height; i++)
			for (j=0; j<pSrcImg->Width; j++)
			{
				if (*(pSrcImg->pImg+i*pSrcImg->Width+j) == 255)
				{
					for (o=-10; o<=10; o++)
					{
						if (o >= 0)
							Tempo = o + 80;
						else
							Tempo = o - 80;

						temp = j*cos(Tempo*PI/180.0)+i*sin(Tempo*PI/180.0);
						if (temp < 0.0)
							p = (int)(temp-0.5);
						else
							p = (int)(temp+0.5);

						if ((p+HHeight/2 >= 0) && (p + HHeight/2 < HHeight))
							 (*(H+(p+HHeight/2)*HWidth+Tempo+HWidth/2))++;
					}
				}
			}
		Max = 0;
		for (i=-HHeight/2; i<=HHeight/2; i++)
			for (j=-10; j<=10; j++)
			{
				if (j >= 0)
					Tempo = j + 80;
				else
					Tempo = j - 80;

				if (Max<*(H+(i+HHeight/2)*HWidth+Tempo+HWidth/2))
				{
					Max = *(H+(i+HHeight/2)*HWidth+Tempo+HWidth/2);
					o = Tempo;   
					p = i;     
				}
			}
		pAngle->HAngle = o;

		break;

	case V_FILTER: 

		for (i=0; i<pSrcImg->Height; i++)
			for (j=0; j<pSrcImg->Width; j++)
			{
				if (*(pSrcImg->pImg+i*pSrcImg->Width+j) == 255)
				{

					for (o=-10; o<=10; o++)
					{
						temp = j*cos(o*PI/180.0)+i*sin(o*PI/180.0);
						if (temp < 0.0)
							p = (int)(temp-0.5);
						else
							p = (int)(temp+0.5);

						if ((p+HHeight/2 >= 0) && (p+HHeight/2 < HHeight))
							(*(H+(p+HHeight/2)*HWidth+o+HWidth/2))++;
					}
				}
			}

		Max = 0;

		for (i=-HHeight/2; i<=HHeight/2; i++)
			for (j=-10; j<=10; j++)
			{
				if (Max < *(H+(i+HHeight/2)*HWidth+j+HWidth/2))
				{
					Max = *(H+(i+HHeight/2)*HWidth+j+HWidth/2);
					o = j;  
					p = i;     
				}
			}
		pAngle->VAngle = o;
		break;
	default:
		if (H)
			free(H);
		return 0;
	}

	if (H)
	{
		free(H);
		H = NULL;
	}

	return 1;
}

int GetLPAccuratePos(RECT *lpRect, PGrayImg pSrcImg)
{
	int res = 0;

	TGrayImg DiffImg;
	TGrayImg LPImg;

	int UpYPos, DownYPos, LeftXPos, RightXPos;
	int *pHProject, *pVProject;

	res = Diff(&DiffImg, pSrcImg, H_FILTER);
	if (0 == res)
		return 0;

	pHProject = (int*)malloc(pSrcImg->Height*sizeof(int));

	res = ProjectImg(pHProject, &DiffImg, H_FILTER);
	if (0 == res)
		return 0;

	res = ProjectFilter(pHProject, pSrcImg->Height, IH_FILTER);
	if (0 == res)
		return 0;

	res = GetLPAccurateYPos(pHProject, pSrcImg->Height, &UpYPos, &DownYPos);
	if (0 == res)
		return 0;

	lpRect->left = 0;
	lpRect->right = pSrcImg->Width - 1;
	lpRect->top = UpYPos;
	lpRect->bottom = DownYPos;

	res = GetSubImg(&LPImg, pSrcImg, *lpRect);
	if (0 == res)
		return 0;

	res = GrayImg_Free(&DiffImg);
	if (0 == res)
		return 0;

	pVProject = (int*)malloc(LPImg.Width*sizeof(int));

	res = ProjectImg(pVProject, &LPImg, V_FILTER);
	if (0 == res)
		return 0;

	res = ProjectFilter(pVProject, LPImg.Width, IV_FILTER, DownYPos - UpYPos);
	if (0 == res)
		return 0;

	res = GetLPAccurateXPos(pVProject, LPImg.Width, DownYPos - UpYPos, &LeftXPos, &RightXPos);
	if (0 == res)
		return 0;

	if (pHProject != NULL)
	{
		free(pHProject);
		pHProject = NULL;
	}
	if (pVProject != NULL)
	{
		free(pVProject);
		pVProject = NULL;
	}
	
	res = GrayImg_Free(&LPImg);
	if (0 == res)
		return 0;

	lpRect->top = UpYPos;
	lpRect->bottom = DownYPos;
	lpRect->left = LeftXPos;
	lpRect->right = RightXPos;

	return 1;
}

int GetLPAccurateXPos(int *pProject, int PrjLen, int LPHeight, int *pLeftXPos, int *pRightXPos)
{

	int i, j, k;
	int TempLeft, TempRight;
	int TempPos[101], Code[101];
	BOOL Flag1, Flag2;

	*pLeftXPos = 0; 
	*pRightXPos = 0;

	for (i=0; i<PrjLen; i++)
	{
		if (*(pProject+i) != 0)
		{
			*pLeftXPos = i;
			break;
		}
	}

	if ((int)(4.4*LPHeight+0.5)+(*pLeftXPos) > PrjLen-1)
		*pRightXPos = PrjLen - 1;
	else
		*pRightXPos = (int)(4.4 * LPHeight + 0.5) + (*pLeftXPos);

	if (*(pProject+(*pRightXPos)) != 0)
	{
		for (i=(*pRightXPos); i<PrjLen; i++)
		{
			if  (*(pProject+i) == 0)
				break;
		}
		*pRightXPos = i;
	}

	if ((*pRightXPos)-(*pLeftXPos) > (int)(4.0*LPHeight+0.5))
	{
		Flag2 = TRUE;
		Flag1 = TRUE;
		j = 0; 
		k = 0;
		for (i=(*pLeftXPos); i<PrjLen; i++)
		{
			if ((*(pProject+i) != 0) && Flag1)
				Flag1 = FALSE;

			if ((*(pProject+i) == 0) && (!Flag1))
			{
				TempPos[j] = i; 
				j++;

				if (j > 100)
				{
					return 0;
				}

				TempLeft = i;  
				Flag1 = TRUE;
				Flag2 = FALSE;
			}

			if ((*(pProject+i) != 0) && (!Flag2))
			{
				TempRight = i; 
				if (TempRight-TempLeft < (int)(0.25*LPHeight+0.5))
					 Code[k] = 0;
				else
					 Code[k] = 1;
				k++;

				if (k > 100)
					return 0;

				Flag2 = TRUE;
			}
		}

		for (i=0; i<=j-2; i++)
		{
			if (Code[i] == 0)
			{
				if (Code[i+1] == 1)
				{
					if (TempPos[i]-(int)(0.45*LPHeight+0.5) > 0)
						*pLeftXPos = TempPos[i]-(int)(0.45*LPHeight+0.5);
					else
						*pLeftXPos = 0;

					break;
				}
			}
		}

		if ((int)(4.4*LPHeight+0.5)+(*pLeftXPos) < PrjLen-1)
			*pRightXPos = (int)(4.4*LPHeight+0.5)+(*pLeftXPos);
		else
			*pRightXPos = PrjLen - 1;

		if (*(pProject+(*pRightXPos)) != 0)
		{
			for (i=(*pRightXPos); i<PrjLen; i++)
			{
				if (*(pProject+i) == 0)
					break;
			}
			*pRightXPos = i;
		}
	}

	if ((*pRightXPos) <= (*pLeftXPos))
	{
		return 0;
	}

	return 1;
}

int GetLPAccurateYPos(int *pProject, int PrjLen, int *pUpYPos, int *pDownYPos)
{
	int x;
	int Temp, TempUp, TempDown;
	BOOL Flag;

	Flag = TRUE;
	Temp = 0;
	*pUpYPos = 0; *pDownYPos = 0;

	*(pProject+PrjLen-1) = 0;

	for (x=0; x<PrjLen; x++)
	{
		if (Flag && (*(pProject+x) != 0))
		{
			TempUp = x;
			Flag = FALSE;
		}
		if ((!Flag) && (*(pProject+x) == 0))
		{
		   TempDown = x;
		   Flag = TRUE;
		   if  (Temp < TempDown- TempUp)
		   {
				*pUpYPos = TempUp;
				*pDownYPos = TempDown;
				Temp = TempDown - TempUp;
		   }
		}
	}

	if ((*pDownYPos) <= (*pUpYPos))
		return 0;

	return 1;
}

int GetLPCharPos(int *pCharCount, RECT LPCharRect[], PGrayImg pSrcImg)
{

	int i, j, k, x, y;
	BOOL Flag, Flag1;
	int CharID;
	int avg;
	int TempLeft, TempRight;
	int Code[101];
	int *pOutLineProject;

	int res = 0;

	pOutLineProject = (int*)malloc(pSrcImg->Width*sizeof(int));

	res = OutLineProject(pOutLineProject, pSrcImg);
	if (0 == res)
		return 0;

	res = OutLineProjectFilter(pOutLineProject, pSrcImg->Width, pSrcImg->Height);
	if (0 == res)
		return 0;

	Flag = TRUE;
	CharID = 0;
	*(pOutLineProject+pSrcImg->Width-1) = 0;

	for (i=0; i<pSrcImg->Width; i++)
	{
		if ((*(pOutLineProject+i) != 0) && Flag)
		{
			LPCharRect[CharID].left = i;
			LPCharRect[CharID].top = 0;
			LPCharRect[CharID].bottom = pSrcImg->Height - 1;
			Flag = FALSE;
			avg = 0;
		}

		if ((*(pOutLineProject+i) == 0) && (!Flag))
		{
			LPCharRect[CharID].right = i;

			for (j=LPCharRect[CharID].left; j<=LPCharRect[CharID].right; j++)
			{
				avg += *(pOutLineProject+j);
			}

			avg = (int)(avg*1.0/(LPCharRect[CharID].right-LPCharRect[CharID].left)+0.5);

			if (!((LPCharRect[CharID].right-LPCharRect[CharID].left<(int)(0.2*pSrcImg->Height+0.5)) && (avg < (int)(0.5*pSrcImg->Height+0.5))))
			{
				if (LPCharRect[CharID].right-LPCharRect[CharID].left > (int)(0.05*pSrcImg->Height+0.5))
				{
					if (LPCharRect[CharID].right-LPCharRect[CharID].left < (int)(0.25*pSrcImg->Height+0.5))
					{
						avg = 0;
						for (x=0; x<pSrcImg->Height; x++)
							for (y=LPCharRect[CharID].left; y<=LPCharRect[CharID].right; y++)
							{
								if (*(pSrcImg->pImg+x*pSrcImg->Width+y) == 255)
									avg++;
							}
						if (1.0*avg/(LPCharRect[CharID].right-LPCharRect[CharID].left)/pSrcImg->Height > 0.6)
							CharID++;
					}
					else
						CharID++;
				}
			} 

			if (CharID > MAX_LPCHAR_CURRENT_COUNT-1)
				break;

			Flag = TRUE;
		}
	}

	Flag = TRUE; 
    Flag1 = TRUE;
	k = 0;

	if (LPCharRect[CharID-1].right-LPCharRect[0].left < (int)(4.3*pSrcImg->Height+0.5))
	{
		for (i=0; i<pSrcImg->Width; i++)
		{
			if ((*(pOutLineProject+i) != 0) && Flag1)
				Flag1 = FALSE;

			if ((*(pOutLineProject+i) == 0) && (!Flag1))
			{
				TempLeft = i;    
				Flag1 = TRUE;
				Flag = FALSE;
			}

			if ((*(pOutLineProject+i) != 0) && (!Flag))
			{
				TempRight = i;   

				if (TempRight-TempLeft < (int)(0.26*pSrcImg->Height+0.5))
					Code[k] = 0;
				else
					Code[k] = 1;

				k++;

				if (k > 100)
					return 0;

				Flag = TRUE;
			}
		}

		if (Code[0] != 0)
		{
			if (CharID > MAX_LPCHAR_CURRENT_COUNT-1) 
				CharID--;
		}
		else 
		{
			if ((Code[1] == 1) && (CharID < MAX_LPCHAR_CURRENT_COUNT))
				CharID++;
		}
	}

	for (i=CharID-1; i>=1; i--)
	{
		if (LPCharRect[i].right-LPCharRect[i].left < (int)(0.2*pSrcImg->Height+0.5))
		{
		   if (LPCharRect[i].left-LPCharRect[i-1].right < (int)(0.22*pSrcImg->Height+0.5))
			   CharID--;
		}
		else
		   break;
	}

	if (LPCharRect[CharID-1].right-LPCharRect[CharID-1].left > (int)(0.5*pSrcImg->Height+0.5))
	{
	
		if (LPCharRect[CharID-1].left+(int)(0.5*pSrcImg->Height+0.5)<pSrcImg->Width-1)
		{
			LPCharRect[CharID-1].right = LPCharRect[CharID-1].left+(int)(0.5*pSrcImg->Height+0.5);
		}
		else
			LPCharRect[CharID-1].right = pSrcImg->Width - 1;
	}

	*pCharCount = CharID;

	if (pOutLineProject != NULL)
	{
		free(pOutLineProject);
		pOutLineProject = NULL;
	}

	return 1;
}

int OutLineProject(int *pProject, PGrayImg pSrcImg)
{
	int i, j, HighP, LowP;

	for (j=0; j<pSrcImg->Width; j++)
	{
		HighP = pSrcImg->Height;
		LowP = pSrcImg->Height;

		for (i=0; i<pSrcImg->Height; i++)
		{
			if (*(pSrcImg->pImg+i*pSrcImg->Width+j) > 0)
			{
				HighP = i;
				break;
			}
		}

		for (i=pSrcImg->Height-1; i>=0; i--)
		{
		   if (*(pSrcImg->pImg+i*pSrcImg->Width+j) > 0)
		   {
				LowP = i;
				break;
		   }
		}

		*(pProject+j) = LowP - HighP;
	}

	*(pProject+pSrcImg->Width-1) = 0;

	return 1;
}

int OutLineProjectFilter(int *pProject, int PrjLen, int LPHeight)
{

	int i, CharID, j;
	int Temp;
	int MergeID[101], TempWidth[101];
	RECT LPCharRect[101];
	BOOL Flag;

	*(pProject+PrjLen-1) = 0;
	Flag = TRUE;

	for (i=0; i<PrjLen; i++)
	{
		if ((*(pProject+i) != 0) && Flag)
		{
			Temp = i;
			Flag = FALSE;
		}

		if ((*(pProject+i) == 0) && (!Flag))
		{
			if (i-Temp < (int)(0.2*LPHeight+0.5))
			{
				for (j=Temp; j<i; j++)
				{
					if ((*(pProject+j)<(int)(0.5*LPHeight+0.5)) || (i-Temp<(int)(0.05*LPHeight+0.5)))
						*(pProject+j) = 0;
				}
			}
			Flag = TRUE;
		}
	}

	Flag = FALSE;
	for (i=0; i<PrjLen-1; i++)
	{
		if (*(pProject+i) < 2)
			*(pProject+i) = 0;

		if ((*(pProject+i) < *(pProject+i+1)) && Flag)
		{
			if (*(pProject+i) < (int)(0.3*LPHeight+0.5))
				*(pProject+i) = 0;

			Flag = FALSE;
		}

		if ((*(pProject+i) > *(pProject+i+1)) && (!Flag))
		   Flag = TRUE;
	}

	Flag = TRUE;
	CharID = 0;

	for (i=0; i<PrjLen; i++)
	{
		if ((*(pProject+i) != 0) && Flag)
		{
			LPCharRect[CharID].left = i;
			Flag = FALSE;
		}

		if ((*(pProject+i) == 0) && (!Flag))
		{
			LPCharRect[CharID].right = i - 1;
			TempWidth[CharID] = LPCharRect[CharID].right - LPCharRect[CharID].left + 1;
			if (TempWidth[CharID] < 2)
			{
				for (j=LPCharRect[CharID].left; j<=LPCharRect[CharID].right; j++)
					*(pProject+j) = 0;
			}
			else
				CharID++;

			if (CharID > 100)
				return 0;

			Flag = TRUE;
		}
	}

	j = 0;
	for (i=0; i<CharID; i++)
	{
		if (TempWidth[i] < (int)(0.4 * LPHeight + 0.5))
		{
			MergeID[j] = i;
			j++;
		}

		if ((i==CharID-1) || (TempWidth[i]>=(int)(0.4*LPHeight+0.5)))
		{
			switch (j)
			{
			case 1:
				if (MergeID[0] < CharID - 1)
				{
					if (1 == IsChar(LPCharRect[MergeID[0]].left, LPCharRect[MergeID[0]+1].right, LPHeight))
						if (LPCharRect[MergeID[0]+1].left-LPCharRect[MergeID[0]].right <= 4)
							*(pProject+LPCharRect[MergeID[0]].right+1) = 20;
				}

				if (MergeID[0] > 0)
				{
					if (1 == IsChar(LPCharRect[MergeID[0]-1].left, LPCharRect[MergeID[0]].right, LPHeight))
						if (LPCharRect[MergeID[0]].left - LPCharRect[MergeID[0] - 1].right <= 4)
							*(pProject+LPCharRect[MergeID[0]].right+1) = 20;
				}
				break;

			case 2:
				Merge2(pProject, PrjLen, LPCharRect, MergeID, 0, 1, LPHeight);
				break;

			case 3:
				Merge3(pProject, PrjLen, LPCharRect, MergeID, 0, 2, LPHeight);
				break;

			case 4:
				Merge4(pProject, PrjLen, LPCharRect, MergeID, 0, 3, LPHeight);
				break;

			case 5:
				Merge5(pProject, PrjLen, LPCharRect, MergeID, 0, 4, LPHeight);
				break;

			case 6:
			case 7:
			case 8:
			case 9:
			case 10:
			case 11:
				Merge6(pProject, PrjLen, LPCharRect, MergeID, 0, 5, LPHeight);
				break;
			}

			j = 0;
		}
	}
	return 1;
}

int Merge2(int *pProject, int PrjLen, RECT LPCharRect[], 
		        int MergeID[], int StartID, int EndID, int CharHeight)
{

	int p;
	BOOL Flag;

	if (1 == IsChar(LPCharRect[MergeID[StartID]].left, LPCharRect[MergeID[EndID]].right, CharHeight))
	{
		Flag = TRUE;
		for (p=StartID; p<EndID; p++)
		{
			if (LPCharRect[MergeID[StartID+1]].left-LPCharRect[MergeID[StartID]].right>(int)(0.15*CharHeight+0.5))
				Flag = FALSE;
		}

		if (Flag)
		{
			for (p=LPCharRect[MergeID[StartID]].left; p<=LPCharRect[MergeID[EndID]].right; p++)
				*(pProject+p) = (int)(CharHeight * 0.8 + 0.5);
		}
		else
			return 0;
	}
	else
		return 0;

	return 1;
}

int Merge3(int *pProject, int PrjLen, RECT LPCharRect[], 
		        int MergeID[], int StartID, int EndID, int CharHeight)
{
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID, CharHeight))
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 1, CharHeight))
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID, CharHeight))
		return 0;
	return 1;
}

int Merge4(int *pProject, int PrjLen, RECT LPCharRect[], 
		        int MergeID[], int StartID, int EndID, int CharHeight)
{
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID, CharHeight))
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 1, CharHeight))
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID, CharHeight))
	if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 2, CharHeight))
		Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID, CharHeight);
	else
	{
		if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID - 1, CharHeight))
		if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID, CharHeight))
		   return 0;
	}

	return 1;
}

int Merge5(int *pProject, int PrjLen, RECT LPCharRect[], 
		        int MergeID[], int StartID, int EndID, int CharHeight)
{
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID, CharHeight))

	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 1, CharHeight))

	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID, CharHeight))

	if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 2, CharHeight))
		Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 3, EndID, CharHeight);
	else
	{
		if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID - 1, CharHeight))
		if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID, CharHeight))
			Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 3, CharHeight);
		else
		{
			if  (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 3, CharHeight))
				Merge3(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID, CharHeight);
			else
			{
				if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID - 2, CharHeight))
					Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 3, EndID, CharHeight);
				else
				{
					if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID - 1, CharHeight))
						Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 3, CharHeight);
					else
					{
						if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 3, EndID, CharHeight))
						if (0 == Merge3(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 2, CharHeight))
							return 0;
					}
				}
			}
		}
	}

	return 1;
}

int Merge6(int *pProject, int PrjLen, RECT LPCharRect[], 
		        int MergeID[], int StartID, int EndID, int CharHeight)
{
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID, CharHeight))
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 1, CharHeight))
	if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID, CharHeight))
	if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 2, CharHeight))
		Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 4, EndID, CharHeight);
	else
	{
		if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID - 1, CharHeight))
		if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID, CharHeight))
			Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 4, CharHeight);
		else
		{
			if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 3, CharHeight))
				Merge3(pProject, PrjLen, LPCharRect, MergeID, StartID + 3, EndID, CharHeight);
			else
			{
				if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID - 2, CharHeight))
					Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 4, EndID, CharHeight);
				else
				{
					if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID - 1, CharHeight))
						Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 4, CharHeight);
					else
					{
						if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 3, EndID, CharHeight))
							Merge3(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 3, CharHeight);
						else
						{
							if  (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 4, CharHeight))
								Merge4(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID, CharHeight);
							else
							{
								if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 1, EndID - 3, CharHeight))
									Merge3(pProject, PrjLen, LPCharRect, MergeID, StartID + 3, EndID, CharHeight);
								else
								{
									if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 2, EndID - 2, CharHeight))
									{
										Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 4, CharHeight);
										Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 4, EndID, CharHeight);
									}
									else
									{
										if  (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 3, EndID - 1, CharHeight))
											Merge3(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 3, CharHeight);
										else
										{
											if (1 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID + 4, EndID, CharHeight))
												if (0 == Merge2(pProject, PrjLen, LPCharRect, MergeID, StartID, EndID - 2, CharHeight))
													return 0;
									   }
									}
								}
							}
						}
					}
				}
			}
		}
	}
	return 1;
}

int Merge7(int *pProject, int PrjLen, RECT LPCharRect[], 
		        int MergeID[], int StartID, int EndID, int CharHeight)
{
	return 1;
}

int Merge8(int *pProject, int PrjLen, RECT LPCharRect[], 
		        int MergeID[], int StartID, int EndID, int CharHeight)
{
	return 1;
}

int IsChar(int CharLeft, int CharRight, int CharHeight)
{
	int res = 0;

	if ((CharRight-CharLeft>(int)(0.30*CharHeight+0.5)) && (CharRight-CharLeft<(int)(0.6*CharHeight+0.5)))
		res = 1;
	else
		res = 0;

	return res;
}

int ReadParam(char *szFileName)
{
	_finddata_t fileinfo;
	long lres;

	lres = _findfirst(szFileName, &fileinfo);

	if (-1 != lres)
	{
		g_LPHeight = GetPrivateProfileInt("GDCLPRINI", "LPHeight", 80, szFileName);
		g_LPWidth = GetPrivateProfileInt("GDCLPRINI", "LPWidth", 220, szFileName);       
		g_LPAccurateHeight = GetPrivateProfileInt("GDCLPRINI", "LPAccurateHeight", 40, szFileName);; 
		g_Threshold = GetPrivateProfileInt("GDCLPRINI", "Threshold", 160, szFileName);      
		g_Threshold_HLP = GetPrivateProfileInt("GDCLPRINT", "Threshold_HLP", 100, szFileName);
		g_LeftOffset = GetPrivateProfileInt("GDCLPRINI", "LeftOffset", 0, szFileName);      
		g_RightOffset = GetPrivateProfileInt("GDCLPRINI", "RightOffset", 0, szFileName);     
		g_TopOffset = GetPrivateProfileInt("GDCLPRINI", "TopOffset", 0, szFileName);       
		g_BottomOffset = GetPrivateProfileInt("GDCLPRINI", "BottomOffset", 0, szFileName);    
	}

	return 1;
}

int SaveParam(int LPHeight,      
			  int LPWidth,        
              int LPAccurateHeight,
              int Threshold,       
			  int Threshold_HLP,    
              int LeftOffset,       
              int RightOffset,      
              int TopOffset,        
              int BottomOffset,   
			  char *szFileName)
{
	char str[255];

	sprintf(str, "%d", LPHeight);
	WritePrivateProfileString("GDCLPRINI", "LPHeight", str, szFileName);

	sprintf(str, "%d", LPWidth);
	WritePrivateProfileString("GDCLPRINI", "LPWidth", str, szFileName);

	sprintf(str, "%d", LPAccurateHeight);
	WritePrivateProfileString("GDCLPRINI", "LPAccurateHeight", str, szFileName);

	sprintf(str, "%d", Threshold);
	WritePrivateProfileString("GDCLPRINI", "Threshold", str, szFileName);

	sprintf(str, "%d", Threshold_HLP);
	WritePrivateProfileString("GDCLPRINI", "Threshold_HLP", str, szFileName);

	sprintf(str, "%d", LeftOffset);
	WritePrivateProfileString("GDCLPRINI", "LeftOffset", str, szFileName);

	sprintf(str, "%d", RightOffset);
	WritePrivateProfileString("GDCLPRINI", "RightOffset", str, szFileName);

	sprintf(str, "%d", TopOffset);
	WritePrivateProfileString("GDCLPRINI", "TopOffset", str, szFileName);

	sprintf(str, "%d", BottomOffset);
	WritePrivateProfileString("GDCLPRINI", "BottomOffset", str, szFileName);

	return 1;
}

RECT GetManualCutRect(int *pLeftOffset, int *pRightOffset, int *pTopOffset, int *pBottomOffset, int OriWidth, int OriHeight)
{
	RECT CutRect;

	*pLeftOffset = g_LeftOffset;
	*pRightOffset = g_RightOffset;
	*pTopOffset = g_TopOffset;
	*pBottomOffset = g_BottomOffset;

	CutRect.left = g_LeftOffset;
	CutRect.top = g_TopOffset;
	CutRect.right = OriWidth - g_RightOffset - 1;
	CutRect.bottom = OriHeight - g_BottomOffset - 1;

	return CutRect;
}