#ifdef PC_SIM
#include <mem.h>
#endif
#ifdef TARGET_PC
#include <mem.h>
#endif
#include <math.h>
#include <stdio.h>
#include "cpb_module.h"
#include "CPB_Global.h"

#ifndef TARGET_CPB
#include "Virtual_CPB_System.h"
#else
#include "environment.h"
#include "hardware.h"
#endif

//---------------------------------------------------------------------------
// Global Variable
// Assign to IDRAM
int SetupDataPrint1CenterXFor2D;
int SetupDataPrint1CenterYFor2D;
int SetupDataPrint2CenterXFor2D;
int SetupDataPrint2CenterYFor2D;
int Camera1RecordedColorCount_Of_InspectionProcess;
int Camera9RecordedColorCount_Of_InspectionProcess;
int tabletETCShape_UpSideDownSW;

int dummyCounter;

int ProcessingModeGlobal;
int MeanColorR;
int MeanColorG;
int MeanColorB;
int MeanOneColor;

#pragma DATA_ALIGN(8) // byte 단위로 메모리를 쓰면 이후 정렬이 깨져서 곤란? 64비트로 고침. 실제로 효과가 있는지는 미확인.
unsigned char PrintIsSW;
#pragma DATA_ALIGN(8)
unsigned char Front_Rear;

int selectedRGB;
int OnePrintIncludeOtherPrintSWFor2D;
int OnePrintIncludeOtherPrintSWFor3D;
int DefectSW;

int ImageWidth;
int ImageHeight;
int Max3DHeight;
int Center3DHeight;

#pragma DATA_ALIGN(8)
unsigned char ThickErrorSW;

int CurrentPrintType;
int ProtoTabletCenterX;
int ProtoTabletCenterY;
int ProtoTabletCenterZ;

int AdjustTabletCenterX;
int AdjustTabletCenterY;
int AdjustTabletCenterZ;

int GlobalTabletRotationXZAngle;
int GlobalTabletRotationYZAngle;

int ExecutiveSearchingRotationAngle;
int ProtoTabletRotationAngle;

#pragma DATA_ALIGN(8) // 배열 등은 무조건 정렬을 해주자.
int AdjustTabletCenterInfo[2];

int ETCShape_ForwardProtoRotationAngle;
int ETCShape_ReverseProtoRotationAngle;

int lineCenterX;
int lineCenterY;
int SelectedFace;
int TabletAreaSize;
int MeanColorRForNormal1;
int MeanColorGForNormal1;
int MeanColorBForNormal1;

int MeanColorRForNormal2;
int MeanColorGForNormal2;
int MeanColorBForNormal2;

int corePrintDataAddStepForCam5;
int corePrintDataAddStepForCam13;

int globalPrintSelectedRGB;

#pragma DATA_ALIGN(8)
unsigned char RecoredCamera1ColorR_Of_InspectionProcess[100];
#pragma DATA_ALIGN(8)
unsigned char RecoredCamera1ColorG_Of_InspectionProcess[100];
#pragma DATA_ALIGN(8)
unsigned char RecoredCamera1ColorB_Of_InspectionProcess[100];
#pragma DATA_ALIGN(8)
unsigned char RecoredCamera9ColorR_Of_InspectionProcess[100];
#pragma DATA_ALIGN(8)
unsigned char RecoredCamera9ColorG_Of_InspectionProcess[100];
#pragma DATA_ALIGN(8)
unsigned char RecoredCamera9ColorB_Of_InspectionProcess[100];

int TheOhterSideShapeMatchingSW;
int BlurredEngraveSW;

int ThreeDRealCenterX, ThreeDRealCenterY, ThreeDRealLength;

#pragma DATA_ALIGN(8)
int TabletSlopeInfoStartPoint[2];
#pragma DATA_ALIGN(8)
int TabletSlopeInfoEndPoint[2];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short SideShapeEdgeMatchingPointTop[MAX_IMAGE_WIDTH * 2];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short SideShapeEdgeMatchingPointBottom[MAX_IMAGE_WIDTH * 2];

int SideShapeEdgeMatchingPointTopCount;
int SideShapeEdgeMatchingPointBottomCount;

#pragma DATA_ALIGN(8)
TPrintMarkingInformation PrintMarkingInformation;

/////////////////////////////////////////////////////////////////////////

#ifdef PC_SIM
TSideData *SideData;
int PrintStateForDebug;
int labelCount;

unsigned char BayerImage[HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3]; // 이것은 PC에서는 RGB 이미지로서 3배의 크기.
unsigned char InspectionArea_Virtual[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];
unsigned char GradientImageForFstStudy[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];
unsigned char *currentBackgroundImage;

unsigned char Debug_RealThreeD_Image[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];
unsigned char Debug_LabelingImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];
unsigned char Debug_ProtoShapeArea[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT];
unsigned char Debug_NormalizedThreeDImage[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT];
unsigned char Debug_OvelapRemoveResult[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];
unsigned char Debug_SatAreaImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];
unsigned char Debug_BeforeRotationResult[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

int PrintMatchingDiff;

#else

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TSideData SideData[SIDE_ANGLE_TOTAL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char BayerImage[HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT];

#endif

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char smallSizeBinaryImage[(MAX_IMAGE_WIDTH / 4) * (MAX_IMAGE_HEIGHT / 4)];		  // 19k

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char smallSizeShrinkBinaryImage[(MAX_IMAGE_WIDTH / 4) * (MAX_IMAGE_HEIGHT / 4)]; // 19k

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short smallSizeLabelImage[(MAX_IMAGE_WIDTH / 4) * (MAX_IMAGE_HEIGHT / 4)];				  // 38k

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char smallSizeOneColorImage[(MAX_IMAGE_WIDTH / 4) * (MAX_IMAGE_HEIGHT / 4)];	  // 19k

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char smallSizeGradientImage[(MAX_IMAGE_WIDTH / 4) * (MAX_IMAGE_HEIGHT / 4)];	  // 19k

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char SideFaceBreakCheckArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char SideEdgeMaskingArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)	// DATA_ALIGN은 최적화에 도움이 된다.
#pragma DATA_SECTION(".sdram")
TTabletCharacter TabletCharacter;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TTabletStudyData TabletStudyData;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TTabletGradeData TabletGradeData;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TTabletSetupData TabletSetupData;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TTablet3DSetupData Tablet3DSetupData;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TSideWallMatchingData SideWallMatchingData;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TSideShapeData finalMatchingShapeData;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TWhiteBalanceInfo WhiteBalanceInfo[SYSTEM_TOTAL_CAMERA_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TDefectInformation DefectInformation;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TThreeDPositionInfo ThreeDPositionInfo_CPB;

#pragma DATA_ALIGN(8)
TPrintMatchingResult PrintMatchingResult;

#pragma DATA_ALIGN(8)
TTabletMatchingResult TabletMatchingResult;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
TTabletETCMatchingResult TabletETCMatchingResult;


#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ColorSourceImage[HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char tempColorSourceImage[HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char OneColorImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char MeanOneColorImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ShapeBinaryImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ShapeBinaryImageForPrintArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char GradientImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char TempImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char InspectionArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char realPrintMaskingArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char colorMaskingArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char TempImage2[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char TempImage3[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char TempImage4[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char noneGradientArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short RotationEdgeImage[MAX_IMAGE_WIDTH * MAX_IMAGE_WIDTH];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char BrightPixelNeighborPrint[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char DarkPixelNeighborPrint[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char DarkPixelNeighborPrint2[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ExtractedSplitLineImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char HalfShapeData[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT / 4];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char PlanariztionThreeDEdgeImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ThreeD_Image[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char AdjustThreeD_Data[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned short outlineSectionInfo[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ThreeD_Data[HALF_MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ProtoShapeArea[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char NormalizedThreeDImage[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char DentedArea[IMAGE_3D_WIDTH * IMAGE_3D_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char tempDentedArea[IMAGE_3D_WIDTH * IMAGE_3D_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ThreeDPrintPartialCheckArea[IMAGE_3D_WIDTH * IMAGE_3D_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char HalfTempImage[(MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char HalfExtendShapeBinaryImage[(MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char HalfGradientImage[(MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char HalfShapeBinaryImage[(MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char HalfShrinkShapeBinaryImage[(MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short HalfLabelImage[(MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char PrintLabelArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short LabelImage_Virtual[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char tShellInspectionArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char realBinaryArea[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short ColorRateImageSrcArr[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * 3];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char RotationThreeDImage[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

unsigned char *threeDShellImage;
unsigned char *ExpectedThreeDDefectArea;
unsigned char *ThreeDOutlineImage;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int limitBinaryAreaInfo[MAX_IMAGE_WIDTH];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int tempShiftTopLine[520];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short ShapeShellData[SHAPE_SHELL_DEPTH][2000][3];

#pragma DATA_ALIGN(8)
short ShapeShellDataCount[SHAPE_SHELL_DEPTH];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short ShapeShellGrayLebel[SHAPE_SHELL_DEPTH][360];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short DefectGroup[10000 * 2];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned short Pixel_N_Of_Label[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short Pixel_N_Of_MoreDarkOfLabel[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short StartX_Label[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short EndX_Label[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short StartY_Label[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short EndY_Label[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short PixelNInShapeEdgeNeighbor[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short PixelNInShapeSideEdge[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short PixelNInShapeSideNormal[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short PixelNInShapeSideNormalSideEdge[MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int labelingPxCount[SMALL_SIZE_DEFECT_MAX_LABEL_N];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int LabelStX[SMALL_SIZE_DEFECT_MAX_LABEL_N];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int LabelStY[SMALL_SIZE_DEFECT_MAX_LABEL_N];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int LabelEdX[SMALL_SIZE_DEFECT_MAX_LABEL_N];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int LabelEdY[SMALL_SIZE_DEFECT_MAX_LABEL_N];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short Higher_Pixel_N_Of_Label[MAX_LABEL_COUNT];


#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int detailedCorePrintRotationAddress1[720][1500];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int detailedCorePrintRotationAddress2[720][1500];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int detailedSplitLineRotationAddress[720][2000];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int detailedCorePrintRotationAddress1For3D[720][2500];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int detailedCorePrintRotationAddress2For3D[720][2500];


#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
char ThreeDSplitLineData1[2500];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
char ThreeDSplitLineData2[2500];

#pragma DATA_ALIGN(8)
int ThreeDSplitLineLabel[2][2][THREED_PRINT_MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
int PrintLabelAvgColor[THREED_PRINT_MAX_LABEL_COUNT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short tempPosition_printData[PRINT_DATA_SIZE][2];

int ProtoEngraveDistinguishV_Cam1;
int ProtoEngraveDistinguishV_Cam9;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char CorePrint1Weight[3000];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char CorePrint2Weight[3000];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short Position_SmallPrintCoreData1[3000][2];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short Position_SmallPrintCoreData2[3000][2];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short Position_SmallPrintData1[3000][2];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short Position_SmallPrintData2[3000][2];

int SmallPrintData1Count;
int SmallPrintData2Count;
int SmallPrintCoreData1Count;
int SmallPrintCoreData2Count;
int SmallPrintCoreData1CountFor3D;
int SmallPrintCoreData2CountFor3D;
int SmallSplitLineDataCount;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
THREAD_VARIABLE unsigned int AddressTable[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT]; // 듀얼코어에서 각 코어가 임시로 사용하는 글로벌 변수에는 THREAD_VARIABLE를 붙여줘야 한다. 안그러면 PC에서 듀얼코어 시뮬레이션 시 오류 발생.

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
THREAD_VARIABLE unsigned short shiftInfoArray[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT][3];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ThreeDEraseArea[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char TabletShapeData[HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT];

int TabletShapeMinX, TabletShapeMaxX;
int TabletShapeMinY, TabletShapeMaxY;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short SmallSplitLineData[2000][2];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int CosData[720];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int SinData[720];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int CosSqrData[720];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int arcCosTable[20001];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned int sqrtTable[MAX_SHAPE_RADIAL * MAX_SHAPE_RADIAL];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int sinTable[361];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int cosTable[361];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned int SqrtData[9 * 10000];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short ArcSinData[10001];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short ArcSinData2[10001];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
int tabletAreaInfo[20];

int threeDshapeMinX, threeDshapeMaxX;

#pragma DATA_ALIGN(8)
int GlobalPrintColor[3];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned short SideFaceDivisionLineData[180][SIDE_FACE_DIVISION_LINE_DATA_COUNT * 2];

int SideFaceDivisionLineDataCount;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short LabelImageHighResolution[HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char OneColorImageHighResolution[HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT];

int globalFrontFaceSplitLineMatchingSW;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short globalTabletSplitLineData[PRINT_DATA_SIZE][2];

int globalTabletSplitLineDataCount;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned short EdgeLineForThreeDImage[MAX_THREED_EDGE_POINT_COUNT][3];

int EdgeLineCountForThreeDImage;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short ThreeDRotationShiftArray[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT][2];

#define GROUP_SIZE 4

//---------------------------------------------------------------------------
int DefectLabeling(short *RESTRICT(label_Image), short *RESTRICT(defectPointData), int defectPointDataCnt, int cameraIndex)
{
	int i, m, x, y;
	int temp_address;
	int currentLabel;
	int new_count;
	short CollisionArray[MAX_LABEL_COUNT];
	int newLval;
	int temp;
	short labelGrid[(MAX_IMAGE_WIDTH / GROUP_SIZE + 1) * (MAX_IMAGE_HEIGHT / GROUP_SIZE + 1)]; // 30k
	int gridWidth;
	int gX, gY;
	int tempColorDiff;
	int tempAddress;
	int areaValue;
	int limitValue2;
	int bSideFace;
	int startX, endX, startY, endY;
	int threeDNormalAreaThreshold;

	threeDNormalAreaThreshold = TabletGradeData.option_Breaking_Intensity / 10;

	bSideFace = 0;
	if (cameraIndex == SD1_2D_SIDE_FACE_P45_CAMERA_INDEX ||
		cameraIndex == SD1_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX ||
		cameraIndex == SD2_2D_SIDE_FACE_P45_CAMERA_INDEX ||
		cameraIndex == SD2_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX ||
		cameraIndex == SD1_2D_SIDE_FACE_M45_CAMERA_INDEX ||
		cameraIndex == SD1_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX ||
		cameraIndex == SD2_2D_SIDE_FACE_M45_CAMERA_INDEX ||
		cameraIndex == SD2_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX ||
		cameraIndex == SD1_2D_SIDE_FACE_00_CAMERA_INDEX ||
		cameraIndex == SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX ||
		cameraIndex == SD2_2D_SIDE_FACE_00_CAMERA_INDEX ||
		cameraIndex == SD2_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX)
	{
		bSideFace = 1;
	}

	if (bSideFace)
	{
		limitValue2 = (SIDE_DIRTY_THRESH + (TabletGradeData.side_dirty_Intensity - 1) * 2) * MeanOneColor / 128;
	}

	gridWidth = (MAX_IMAGE_WIDTH / GROUP_SIZE + 1);

	memset(label_Image, 0, sizeof(short) * MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

	currentLabel = 0;
	for (i = 0; i < MAX_LABEL_COUNT; i++)
	{
		CollisionArray[i] = i;
		Pixel_N_Of_Label[i] = 0;
		Pixel_N_Of_MoreDarkOfLabel[i] = 0;
		StartX_Label[i] = 640;
		EndX_Label[i] = 0;
		StartY_Label[i] = 640;
		EndY_Label[i] = 0;
		PixelNInShapeEdgeNeighbor[i] = 0;
		PixelNInShapeSideEdge[i] = 0;
		PixelNInShapeSideNormal[i] = 0;
		Higher_Pixel_N_Of_Label[i] = 0;
	}

	startX = MAX_IMAGE_WIDTH;
	endX = 0;
	startY = MAX_IMAGE_HEIGHT;
	endY = 0;

	memset(TempImage4, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	for (m = 0; m < defectPointDataCnt; m++)
	{
		x = defectPointData[m * 3 + 0];
		y = defectPointData[m * 3 + 1];

		TempImage4[MAX_IMAGE_WIDTH * y + x] = 1;

		if (startX > x)
			startX = x;
		if (endX < x)
			endX = x;
		if (startY > y)
			startY = y;
		if (endY < y)
			endY = y;
	}

	startX = max(startX - 10, 10);
	endX = min(endX + 10, MAX_IMAGE_WIDTH - 10);
	startY = max(startY - 10, 10);
	endY = min(endY + 10, MAX_IMAGE_HEIGHT - 10);

	if (defectPointDataCnt)
	{
		for (y = startY; y < endY; y++)
		{
			for (x = startX; x < endX; x++)
			{
				temp_address = MAX_IMAGE_WIDTH * y + x;
				if (TempImage4[temp_address])
				{
					if (*(label_Image + temp_address - MAX_IMAGE_WIDTH) == 0) // up is background
					{
						if (*(label_Image + temp_address - 1) == 0) // left is also background
						{
							currentLabel++;
							*(label_Image + temp_address) = currentLabel; // first label number is '1'
						}
						else // left is not background
						{
							*(label_Image + temp_address) = *(label_Image + temp_address - 1);
						}
					}
					else // up is not background
					{
						if (*(label_Image + temp_address - 1) == 0) // left is background
						{
							*(label_Image + temp_address) = *(label_Image + temp_address - MAX_IMAGE_WIDTH);
						}
						else // left is not background
						{
							if (*(label_Image + temp_address - MAX_IMAGE_WIDTH) == *(label_Image + temp_address - 1))
							{
								*(label_Image + temp_address) = *(label_Image + temp_address - MAX_IMAGE_WIDTH);
							}
							else // collision detected
							{	 // Left label이 Up label보다 항상 크다
								CollisionArray[max(*(label_Image + temp_address - 1), *(label_Image + temp_address - MAX_IMAGE_WIDTH))] =
									min(*(label_Image + temp_address - 1), *(label_Image + temp_address - MAX_IMAGE_WIDTH));
								*(label_Image + temp_address) = CollisionArray[*(label_Image + temp_address - MAX_IMAGE_WIDTH)];
							}
						}
					}
				}
				if (currentLabel >= MAX_LABEL_COUNT - 1)
					break;
			}
			if (currentLabel >= MAX_LABEL_COUNT - 1)
				break;
		}
	}

	newLval = 1;
	for (i = 1; i <= currentLabel; i++)
	{
		if (CollisionArray[CollisionArray[i]] > newLval)
		{
			newLval++;
			CollisionArray[i] = newLval;
		}
		else
		{
			CollisionArray[i] = CollisionArray[CollisionArray[i]];
		}
	}

	if (newLval >= MAX_LABEL_COUNT)
		newLval = MAX_LABEL_COUNT - 1;
	new_count = newLval;

	/*
	  if (cameraIndex == SD1_2D_FRONT_FACE_CAMERA_INDEX || cameraIndex == SD2_2D_FRONT_FACE_CAMERA_INDEX ||
		cameraIndex == SD1_3D_FRONT_FACE_CAMERA_INDEX || cameraIndex == SD2_3D_FRONT_FACE_CAMERA_INDEX)
	*/
	{
		memset(labelGrid, 0, (MAX_IMAGE_WIDTH / GROUP_SIZE + 1) * (MAX_IMAGE_HEIGHT / GROUP_SIZE + 1) * 2);
		for (m = 0; m < defectPointDataCnt; m++)
		{
			x = defectPointData[m * 3];
			y = defectPointData[m * 3 + 1];
			gX = x / GROUP_SIZE;
			gY = y / GROUP_SIZE;
			temp = *(label_Image + MAX_IMAGE_WIDTH * y + x);
			if (*(labelGrid + gridWidth * gY + gX) == 0)
			{
				*(labelGrid + gridWidth * gY + gX) = CollisionArray[temp];
			}
			else
			{
				*(labelGrid + gridWidth * gY + gX) = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
				CollisionArray[temp] = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
			}
		}

		/*
		memset(labelGrid, 0, (MAX_IMAGE_WIDTH / GROUP_SIZE)*(MAX_IMAGE_HEIGHT / GROUP_SIZE) * 2);
			for (m = 0; m < defectPointDataCnt; m++)
			{
				x = defectPointData[m * 3];
				y = defectPointData[m * 3 + 1];
				gX = (x + GROUP_SIZE / 2) / GROUP_SIZE;
				gY = (y + GROUP_SIZE / 2) / GROUP_SIZE;
				temp = *(label_Image + MAX_IMAGE_WIDTH * y + x);
				if (*(labelGrid + gridWidth * gY + gX) == 0)
				{
					*(labelGrid + gridWidth * gY + gX) = CollisionArray[temp];
				}
				else
				{
					*(labelGrid + gridWidth * gY + gX) = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
					CollisionArray[temp] = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
				}
			}
		*/
	}

	for (m = 0; m < defectPointDataCnt; m++)
	{
		x = defectPointData[m * 3];
		y = defectPointData[m * 3 + 1];
		tempColorDiff = defectPointData[m * 3 + 2];
		tempAddress = MAX_IMAGE_WIDTH * y + x;

		temp = *(label_Image + tempAddress);
		temp = CollisionArray[temp];
		*(label_Image + tempAddress) = temp;

		Pixel_N_Of_Label[temp]++;

		if (cameraIndex == SD1_3D_FRONT_FACE_CAMERA_INDEX || cameraIndex == SD2_3D_FRONT_FACE_CAMERA_INDEX)
		{
			if (ExpectedThreeDDefectArea[tempAddress] > threeDNormalAreaThreshold)
				Higher_Pixel_N_Of_Label[temp]++;
		}
		else
		{
			areaValue = *(InspectionArea + tempAddress);

			if (bSideFace)
			{
				if (areaValue == SIDE_SHAPE_TOP_EDGE_UPPER_NEIGHBOR)
				{
					PixelNInShapeEdgeNeighbor[temp]++;
				}
				if (areaValue == SIDE_SHAPE_TOP_NORMAL_BOUNDARY_AREA)
				{
					PixelNInShapeSideEdge[temp]++;
				}
				if (areaValue == NORMAL_INPECTION_AREA ||
					areaValue == NORMAL_INPECTION_AREA2 ||
					areaValue == SIDE_SHAPE_BOTTOM_EDGE_SHORT_NEIGHBOR ||
					areaValue == SIDE_SHAPE_BOTTOM_EDGE_LONG_NEIGHBOR ||
					areaValue == SIDE_SHAPE_MULTI_TABLET_BOUNDARY_AREA)
				{
					PixelNInShapeSideNormal[temp]++;
				}
			}
			else
			{
				if (areaValue == FRONT_SHAPE_EDGE_NEIGHBOR || areaValue == FRONT_SHAPE_EDGE)
				{
					PixelNInShapeEdgeNeighbor[temp]++;
				}
			}

			if (bSideFace)
			{
				// 사이드 모서리가 아닌경우에만 짙은 이물류 체크
				// 사이드 모서리의 경우엔 이물 및 깨짐 등급을 이용해서 불량 검출
				if (areaValue != SIDE_SHAPE_TOP_EDGE_UPPER_NEIGHBOR && areaValue != SIDE_SHAPE_BOTTOM_EDGE_SHORT_NEIGHBOR && areaValue != SIDE_SHAPE_BOTTOM_EDGE_LONG_NEIGHBOR && areaValue != SIDE_SHAPE_TOP_NORMAL_BOUNDARY_AREA)
				{
					if (tempColorDiff > limitValue2)
						Pixel_N_Of_MoreDarkOfLabel[temp]++;
				}
			}
			else
			{
				if (areaValue == PRINT_AREA || areaValue == FRONT_FACE_SPLIT_AREA)
				{
					Pixel_N_Of_MoreDarkOfLabel[temp]++;

					if (Pixel_N_Of_Label[temp] > 0)
						Pixel_N_Of_Label[temp]--;
				}
			}
		}

		if (StartX_Label[temp] > x)
			StartX_Label[temp] = x;
		if (StartY_Label[temp] > y)
			StartY_Label[temp] = y;
		if (EndX_Label[temp] < x)
			EndX_Label[temp] = x;
		if (EndY_Label[temp] < y)
			EndY_Label[temp] = y;
	}

	return (new_count);
}
//---------------------------------------------------------------------------
void LineDataDialation(short *RESTRICT(src), short *RESTRICT(dst), int size, int step, int srcSize)
{
	int m, n;
	int max;
	for (n = 0; n < srcSize; n++)
	{
		max = -100;
		for (m = n - size; m <= n + size; m += step)
		{
			if (m >= 0 && m < srcSize && src[m] > max)
			{
				max = src[m];
			}
		}
		dst[n] = max;
	}
}
//---------------------------------------------------------------------------
void LineDataErosion(short *RESTRICT(src), short *RESTRICT(dst), int size, int step, int srcSize)
{
	int m, n;
	int min;
	for (n = 0; n < srcSize; n++)
	{
		min = 1000;
		for (m = n - size; m <= n + size; m += step)
		{
			if (m >= 0 && m < srcSize && src[m] < min)
			{
				min = src[m];
			}
		}
		dst[n] = min;
	}
}
//---------------------------------------------------------------------------
void DataInitiate(int option, int cameraIndex)
{
	dummyCounter = 0;

	ImageWidth = 640;
	ImageHeight = 480;

#ifdef PC_SIM
	memset(&InspectData, 0, sizeof(TInspectData));	
	for (int coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
	{
		InspectData.CoreProcessingMode[coreIndex] = SPLIT_PROCESSING_MODE_NONE;
	}

	CPB_CORE_NUMBER = 0;

	PrintStateForDebug = 0;	
	PrintMatchingDiff = 0;

	memset(ColorSourceImage, 0, HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3);
	memset(OneColorImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

	memset(MeanOneColorImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(ShapeBinaryImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(ShapeBinaryImageForPrintArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(GradientImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

	memset(InspectionArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(realPrintMaskingArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(colorMaskingArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(BrightPixelNeighborPrint, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(DarkPixelNeighborPrint, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(DarkPixelNeighborPrint2, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(tShellInspectionArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(PlanariztionThreeDEdgeImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(TempImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(ThreeD_Image, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(AdjustThreeD_Data, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

	memset(DentedArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(PrintLabelArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(RotationEdgeImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * 2);
	memset(LabelImage_Virtual, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * 2);

	memset(TempImage2, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(TempImage3, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(GradientImageForFstStudy, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

#else

	memset(InspectionArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(ShapeBinaryImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(PlanariztionThreeDEdgeImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT); // side 카메라의 gradient 임시 버퍼

	if (option == NOT_THREED)
	{
		memset(ColorSourceImage, 0, HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3);
		memset(OneColorImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
		memset(MeanOneColorImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
		memset(ShapeBinaryImageForPrintArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
		memset(GradientImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
		memset(TempImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

		if (cameraIndex == SD1_2D_FRONT_FACE_CAMERA_INDEX ||
			cameraIndex == SD2_2D_FRONT_FACE_CAMERA_INDEX)
			memset(realPrintMaskingArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	}
#endif

	memset(&DefectInformation, 0, sizeof(TDefectInformation));
	memset(SideEdgeMaskingArea, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

	if (cameraIndex == SD1_2D_FRONT_FACE_CAMERA_INDEX ||
		cameraIndex == SD2_2D_FRONT_FACE_CAMERA_INDEX)
	{
		CurrentPrintType = 0;
		ProtoEngraveDistinguishV_Cam1 = 0;
		ProtoEngraveDistinguishV_Cam9 = 0;

		if (TabletCharacter.shape == ROUND)
		{
			if (TabletCharacter.kind == SUGARCOATING)
			{
				TabletGradeData.frontShapeEdgeNeighborRange = 30 * (TabletCharacter.width * 37) / 12000;
			}
			else
			{
				TabletGradeData.frontShapeEdgeNeighborRange = 22 * (TabletCharacter.width * 37) / 12000;
			}
		}
		else if (TabletCharacter.shape == OBLONG || TabletCharacter.shape == OVAL)
			TabletGradeData.frontShapeEdgeNeighborRange = 15 + ((TabletCharacter.width * 37 - 5000) * 5 + 500) / 1000;
		else
			TabletGradeData.frontShapeEdgeNeighborRange = 15;

		if (ProcessingModeGlobal == INSPECTION_MODE)
		{
			if (TabletGradeData.FrontEdgeAreaExtendSW)
			{
				if (TabletCharacter.shape == ROUND)
					TabletGradeData.frontShapeEdgeNeighborRange = 22 * (TabletCharacter.width * 37) / 12000 + TabletGradeData.FrontEdgeAreaExtendSW;
				else if (TabletCharacter.shape == OBLONG || TabletCharacter.shape == OVAL)
					TabletGradeData.frontShapeEdgeNeighborRange = 15 + ((TabletCharacter.width * 37 - 5000) * 5 + 500) / 1000 + TabletGradeData.FrontEdgeAreaExtendSW * 2 / 3;
				else
					TabletGradeData.frontShapeEdgeNeighborRange = 15 + TabletGradeData.FrontEdgeAreaExtendSW;
			}
		}

		if (TabletGradeData.frontShapeEdgeNeighborRange >= SHAPE_SHELL_DEPTH - 1)
			TabletGradeData.frontShapeEdgeNeighborRange = SHAPE_SHELL_DEPTH - 1;
	}

	if (ProcessingModeGlobal == STUDY_MODE || ProcessingModeGlobal == FIRST_STUDY_MODE)
	{
		memset(&TabletStudyData, 0, sizeof(TTabletStudyData));

		TabletGradeData.front_stain_Intensity = 5;
		TabletGradeData.front_stain_Size = 30;
		TabletGradeData.front_edge_Intensity = 5;
		TabletGradeData.front_edge_Size = 40;
		TabletGradeData.front_edge_dirty_Intensity = 2;
		TabletGradeData.front_edge_dirty_Size = 10;
		TabletGradeData.front_dirty_Intensity = 2;
		TabletGradeData.front_dirty_Size = 13;
		TabletGradeData.front_color_Intensity = 3;
		TabletGradeData.frontBorderIsSW = 0;
		TabletGradeData.frontSmallSizeGrade = 2;

		TabletGradeData.option_front_edgeBreaking_Intensity_Type1 = 60;
		TabletGradeData.option_front_edgeBreaking_Size_Type1 = 100;

		TabletGradeData.option_front_edgeBreaking_Intensity_Type2 = 60;
		TabletGradeData.option_front_edgeBreaking_Size_Type2 = 100;

		TabletGradeData.option_Breaking_Intensity = 22;
		TabletGradeData.option_PrintMark_Intensity = 20;
		TabletGradeData.option_Breaking_Size = 90;
		TabletGradeData.front_Color_Dirty_Intensity = 6;

		TabletGradeData.side_Edge_Color_Dirty_Intensity = 6;
		TabletGradeData.side_Edge_Color_Dirty_Size = 35;

		TabletGradeData.front_unInspectionIntensity_ForPrint = 0;
		TabletGradeData.front_unInspectionIntensity_ForEdge = 0;
		TabletGradeData.front_unInspectionIntensity_ForOptionPrint = 0;
		TabletGradeData.front_unInspectionIntensity_ForOptionEdge = 0;

		TabletGradeData.side_Edge_Top_Neighbor_Intensity = 0;
		TabletGradeData.side_Edge_Bottom_Neighbor_Intensity = 2;

		TabletGradeData.SideFaceEdgeAreaSize = 6;
		TabletGradeData.SideFaceEdgeUnInsAreaSize = 2;

		TabletGradeData.rear_stain_Intensity = 5;
		TabletGradeData.rear_stain_Size = 35;
		TabletGradeData.rear_dirty_Intensity = 2;
		TabletGradeData.rear_dirty_Size = 13;
		TabletGradeData.rear_edge_dirty_Intensity = 2;
		TabletGradeData.rear_edge_dirty_Size = 10;
		TabletGradeData.rear_edge_Intensity = 5;
		TabletGradeData.rear_edge_Size = 40;
		TabletGradeData.rear_Color_Dirty_Intensity = 2;
		TabletGradeData.rear_Color_Dirty_Size = 35;
		TabletGradeData.rear_print_dirty_Inetensity = 3;

		TabletGradeData.side_stain_Intensity = 4;
		TabletGradeData.side_stain_Size = 25;
		TabletGradeData.side_dirty_Intensity = 4;
		TabletGradeData.side_dirty_Size = 12;
		TabletGradeData.sideShapeEdgeMaskRange = 1;
		TabletGradeData.side_Color_Dirty_Intensity = 5;
		TabletGradeData.side_Color_Dirty_Size = 25;

		TabletGradeData.FrontEdgeAreaExtendSW = 0;
		TabletGradeData.CoatedTablet_SideInspectionAreaSize = 10;

		if (TabletCharacter.plateInformation == PLATE)
			TabletGradeData.threeDEdgeAreaExtend = 3;
		else
			TabletGradeData.threeDEdgeAreaExtend = 0;

		TabletGradeData.front_print_dirty_Inetensity = 6;
		TabletGradeData.front_print_dirty_Inetensity2 = 15;
		TabletGradeData.front_print_erase_Intensity = 3;
		TabletGradeData.front_print_spread_Intensity = 3;

		TabletGradeData.threeD_Height_Plus_Limit = 7;
		TabletGradeData.threeD_Height_Minus_Limit = 7;
		TabletGradeData.Saturation_Erase_SW = 0;

		TabletGradeData.ETC_Side_None_Horizontality_Tablet = 0;
		TabletGradeData.ETC_Side_Split_Line_UnInspection_Area_Setting = 0;

		TabletGradeData.EngraveDistinguishGrade = 2;
		TabletGradeData.EngraveDistinguishGradeFor3D = 2;

		TabletGradeData.Side_Edge_Neighbor_Intensity = 4;
		TabletGradeData.Side_Edge_Neighbor_Defect_Size = 20;

		TabletGradeData.Side_Edge_Dark_Intensity = 5;
		TabletGradeData.Side_Edge_Dark_Defect_Size = 60;

		TabletGradeData.Side_Edge_Bright_Intensity = 5;
		TabletGradeData.Side_Edge_Bright_Defect_Size = 20;

		TabletGradeData.Side_Edge_Neighbor_Break_Intensity = 5;
		TabletGradeData.Side_Edge_Neighbor_Break_Size = 40;
		TabletGradeData.Side_Edge_Neighbor_Min_Break_Depth_Size = 3;

		// 학습과정에서 변수 초기화
		TabletStudyData.TabletEngraveMisMatchCount_Remaining_CAM1 = 0;
		TabletStudyData.TabletEngraveMisMatchCount_Remaining_CAM9 = 0; // For SELMA200, Rev by moon. (20180208) Camera Index
		TabletStudyData.TabletEngraveMisMatchCount_Empty_CAM1 = 0;
		TabletStudyData.TabletEngraveMisMatchCount_Empty_CAM9 = 0; // For SELMA200, Rev by moon. (20180208) Camera Index

		TabletGradeData.DirtyGradeSensitivity = GRADE_SENSITIVITY_NORMAL;

		TabletGradeData.SplitLineMatchingSWForPrintTablet = 0;
		TabletGradeData.SplitLineMatchingThreshold = 10;

		TabletGradeData.ETC_ApplyColorDirtyIgnoreAlgorithm = 0; // 적용 안함
		TabletGradeData.ETC_InterestedColor = 2;				// RED Color
		TabletGradeData.ETC_ColorDirtyIgnoreLevel = 20;
		TabletGradeData.ETC_AdjustPrintAreaSW = 0;
		TabletGradeData.ETC_ColorDirtySize = 75;
		TabletGradeData.ETC_ThreeDCenterSize = 0;

		TabletGradeData.dummy[0] = 0;

		TabletGradeData.ETC_FrontFaceEdgeInspectionSW = 0;

		TabletGradeData.ETC_Partial3DPrintCheckSW = 0;

		TabletGradeData.ETC_RemoveBrightDotSW = 0;
		TabletGradeData.ETC_ApplyTiltTabletAlgorithm = 0;
		TabletGradeData.ETC_SideFaceMultiTabletUnInspectionSize = 0;

		TabletGradeData.DarkSpotDefectIntensityGradeForMarvelingTablet = 4;
		TabletGradeData.DarkSpotDefectSizeGradeForMarvelingTablet = 100;
		TabletGradeData.BrightSpotDefectIntensityGradeForMarvelingTablet = 4;
		TabletGradeData.BrightSpotDefectSizeGradeForMarvelingTablet = 100;

		TabletGradeData.DarkStainDefectIntensityGradeForMarvelingTablet = 6;
		TabletGradeData.DarkStainDefectSizeGradeForMarvelingTablet = 250;
		TabletGradeData.BrightStainDefectIntensityGradeForMarvelingTablet = 6;
		TabletGradeData.BrightStainDefectSizeGradeForMarvelingTablet = 250;

		TabletGradeData.DirtyDefectCheckSWInNeighborPrint = 0;
		TabletGradeData.ETC_EngraveWhiteDefectCheckAlgorithm = 0;
		TabletGradeData.ETC_EnforcementStainDefectCheckAlgorithm = 0;

		TabletGradeData.ETC_ApplyWhiteEngraveAlgorithm = 0;

		TabletGradeData.ETC_AdjustUnalignedTabletAlgorithm = 0;

		TabletGradeData.FrontFaceEngraveColorGrade = 10;

		TabletGradeData.FrontFaceEngraveWhiteSpotIntensity = 10;
		TabletGradeData.FrontFaceEngraveWhiteSpotSize = 100;

		TabletGradeData.EnforcementStainDefectInspectionAreaSize = 50;
		TabletGradeData.EnforcementStainDefectThreshold = 10;
		TabletGradeData.EnforcementStainDefectMaxLabelSize = 100;
		TabletGradeData.EnforcementStainDefectAllGroupSize = 200;

		TabletGradeData.ETC_EngraveMatchingOption_ReflectedTabletShape = 0;
		TabletGradeData.ETC_EngraveMatchingOption_LightEngrave = 0;

		TabletGradeData.ETC_ThreeD_DiffShapeTabletSW = 0;

		TabletGradeData.ETC_PrintPositionDefectIntensity = 0;
		TabletGradeData.ETC_PrintPositionRotationDefectIntensity = 0;

		TabletGradeData.ThreeD_CoatedTablet_ShapeError_Height = 40;
		TabletGradeData.ThreeD_CoatedTablet_ShapeError_Size = 200;

		TabletGradeData.ETC_CoatedTablet_ShapeCheck = 0;

		TabletGradeData.ETC_PartialThreeDStampDefectIntensity = 2;
		TabletGradeData.ETC_PartialThreeDStampDefectSize = 200;

		TabletGradeData.ETC_ActiveSideEdgeDefectCheck = 0;
		TabletGradeData.ETC_SideEdgeDefectIntensity = 40;
		TabletGradeData.ETC_SideEdgeDefectSize = 200;

		TabletGradeData.EngraveMatchingOrNotValue = 0;
		TabletGradeData.ETC_TabletFrontFaceThreshold = 0;

		TabletGradeData.LIMA_ThreeD_Side_EraseLevel = 0;
		TabletGradeData.LIMA_ThreeD_MaxHeight = 0;
		TabletGradeData.LIMA_ThreeD_OverHeightSize = 40;

		TabletGradeData.BeltPowderSensitivity = 0;
		TabletGradeData.RemoveBeltActive = 0;
		TabletGradeData.EngravePrintMatching2DInActive = 0;
	}
}
//---------------------------------------------------------------------------
void DefectInformationWrite(int defectSeries, int cameraIndex, int defectStartX, int defectEndX, int defectStartY, int defectEndY, int size)
{
	DefectInformation.defectSeries = defectSeries;
	DefectInformation.cameraIndex = cameraIndex;
	DefectInformation.defectPositionStartX = defectStartX - 20;
	DefectInformation.defectPositionEndX = defectEndX + 20;
	DefectInformation.defectPositionStartY = defectStartY - 20;
	DefectInformation.defectPositionEndY = defectEndY + 20;
	DefectInformation.size = size;
}
//---------------------------------------------------------------------------
int LabellingForTabletImage(short *RESTRICT(label_Image), unsigned char *RESTRICT(smallSizeBinaryImage), int startX, int endX, int startY, int endY, int imageWidth, int imageHeight)
{
	int i, x, y;
	int temp_address;
	int currentLabel;
	int new_count;
	short CollisionArray[MAX_LABEL_COUNT];
	int newLval;
	int temp;
	int tempAddress;
	int maxLabelN;
	int maxLabelCount;
	int breakSW;

	currentLabel = 0;

	for (i = 0; i < MAX_LABEL_COUNT; i++)
	{
		CollisionArray[i] = i;
		Pixel_N_Of_Label[i] = 0;
		StartX_Label[i] = 640;
		EndX_Label[i] = 0;
		StartY_Label[i] = 640;
		EndY_Label[i] = 0;
	}

	breakSW = 0;
	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			temp_address = imageWidth * (y) + x;
			if (*(smallSizeBinaryImage + temp_address))
			{
				if (*(label_Image + temp_address - imageWidth) == 0) // up is background
				{
					if (*(label_Image + temp_address - 1) == 0) // left is also background
					{
						currentLabel++;
						*(label_Image + temp_address) = currentLabel; // first label number is '1'
					}
					else // left is not background
					{
						*(label_Image + temp_address) = *(label_Image + temp_address - 1);
					}
				}
				else // up is not background
				{
					if (*(label_Image + temp_address - 1) == 0) // left is background
					{
						*(label_Image + temp_address) = *(label_Image + temp_address - imageWidth);
					}
					else // left is not background
					{
						if (*(label_Image + temp_address - imageWidth) == *(label_Image + temp_address - 1))
						{
							*(label_Image + temp_address) = *(label_Image + temp_address - imageWidth);
						}
						else // collision detected
						{	 // Left label이 Up label보다 항상 크다
							CollisionArray[max(*(label_Image + temp_address - 1), *(label_Image + temp_address - imageWidth))] =
								min(*(label_Image + temp_address - 1), *(label_Image + temp_address - imageWidth));
							*(label_Image + temp_address) = CollisionArray[*(label_Image + temp_address - imageWidth)];
						}
					}
				}
				if (currentLabel >= MAX_LABEL_COUNT - 1)
				{
					breakSW = 1;
					break;
				}
			}
		}
		if (breakSW == 1)
			break;
	}

	newLval = 1;
	for (i = 1; i <= currentLabel; i++)
	{
		if (CollisionArray[CollisionArray[i]] > newLval)
		{
			newLval++;
			CollisionArray[i] = newLval;
		}
		else
		{
			CollisionArray[i] = CollisionArray[CollisionArray[i]];
		}
	}

	if (newLval > 500)
		newLval = 499;
	new_count = newLval;

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = imageWidth * (y) + x;
			if (*(smallSizeBinaryImage + tempAddress))
			{
				temp = *(label_Image + tempAddress);
				temp = CollisionArray[temp];
				*(label_Image + tempAddress) = temp;
				Pixel_N_Of_Label[temp]++;
				if (StartX_Label[temp] > x)
					StartX_Label[temp] = x;
				if (StartY_Label[temp] > y)
					StartY_Label[temp] = y;
				if (EndX_Label[temp] < x)
					EndX_Label[temp] = x;
				if (EndY_Label[temp] < y)
					EndY_Label[temp] = y;
			}
		}
	}

	maxLabelN = 0;
	maxLabelCount = 0;
	for (i = 1; i <= new_count; i++)
	{
		if (Pixel_N_Of_Label[i] > maxLabelCount)
		{
			maxLabelN = i;
			maxLabelCount = Pixel_N_Of_Label[i];
		}
	}
	return (maxLabelN);
}
//---------------------------------------------------------------------------
void ColorChange(int cameraIndex, int ImageConvertOption)
{
	int x, y;
	int startX, endX, startY, endY;
	int rgb;
	int tempAddress, tempAddress2;
	int currentImageWidth;
	int currentImageHeight;
	int halfImageWidth;
	int value;
	
	rgb = 1;
	selectedRGB = 1;

	if (TabletSetupData.protoStudyColorR != 0 && TabletSetupData.protoStudyColorG != 0 && TabletSetupData.protoStudyColorB != 0)
	{
		if (TabletSetupData.protoStudyColorR > TabletSetupData.protoStudyColorG * 110 / 100)
		{
			if (TabletSetupData.protoStudyColorR > TabletSetupData.protoStudyColorB * 110 / 100)
			{
				rgb = 2;
				selectedRGB = 2;
			}
		}
		if (TabletSetupData.protoStudyColorB > TabletSetupData.protoStudyColorG * 110 / 100)
		{
			if (TabletSetupData.protoStudyColorB > TabletSetupData.protoStudyColorR * 110 / 100)
			{
				rgb = 0;
				selectedRGB = 0;
			}
		}
	}

	startX = TabletSetupData.ImageCutStartX[cameraIndex - 1];
	endX = TabletSetupData.ImageCutEndX[cameraIndex - 1];
	startY = TabletSetupData.ImageCutStartY[cameraIndex - 1];
	endY = TabletSetupData.ImageCutEndY[cameraIndex - 1];

	if (startX < 1)
		startX = 1;
	if (endX > ImageWidth)
		endX = ImageWidth - 1;

	if (startY < 1)
		startY = 1;
	if (endY > ImageHeight)
		endY = ImageHeight - 1;

	/*
	if(ProcessingModeGlobal == FIRST_STUDY_MODE)
	{
	startX = 10;
	endX = MAX_IMAGE_WIDTH - 10;
	startY = 10;
	endY = MAX_IMAGE_HEIGHT - 10;
	}
	*/

	currentImageWidth = MAX_IMAGE_WIDTH;
	currentImageHeight = MAX_IMAGE_HEIGHT;

	if (TabletCharacter.HighResolutionImage)
	{
		startX *= 2;
		endX *= 2;
		startY *= 2;
		endY *= 2;

		currentImageWidth = HD_IMAGE_WIDTH;
		currentImageHeight = HD_IMAGE_HEIGHT;
	}

	halfImageWidth = MAX_IMAGE_WIDTH / 2;

	if (ImageConvertOption == 0)
	{		
		if (TabletSetupData.ImageOffSetSW[cameraIndex - 1]) // 오프셋 값이 있다면 적용.
		{
			if (TabletCharacter.HighResolutionImage)
			{
				halfImageWidth = HD_IMAGE_WIDTH / 4;

				int xquarter, yquarter;
				for (y = 10, yquarter = y / 4; y < HD_IMAGE_HEIGHT - 10; ++y, ((y & 3) == 0 && ++yquarter))				
				{
					for (x = 10, xquarter = x / 4; x < HD_IMAGE_WIDTH - 10; ++x, ((x & 3) == 0 && ++xquarter))					
					{
						value = BayerImage[HD_IMAGE_WIDTH * y + x] - TabletSetupData.referenceImageForOffset[cameraIndex - 1][halfImageWidth * yquarter + xquarter];
						if (value < 4)
						{
							value = 4;
						}

						BayerImage[HD_IMAGE_WIDTH * y + x] = value;
					}
				}
			}
			else
			{
				int xhalf, yhalf;
				for (y = 10, yhalf = y / 2; y < MAX_IMAGE_HEIGHT - 10; ++y, ((y & 1) == 0 && ++yhalf))
				{
					for (x = 10, xhalf = x / 2; x < MAX_IMAGE_WIDTH - 10; ++x, ((x & 1) == 0 && ++xhalf))
					{
						value = BayerImage[MAX_IMAGE_WIDTH * y + x] - TabletSetupData.referenceImageForOffset[cameraIndex - 1][halfImageWidth * yhalf + xhalf];
						if (value < 4)
						{
							value = 4;
						}

						BayerImage[MAX_IMAGE_WIDTH * y + x] = value;
					}
				}
			}
		}

		// BayerImage를 ColorSourceImage로 전환.
		if (cameraIndex == SD2_2D_SIDE_FACE_P45_CAMERA_INDEX ||
			cameraIndex == SD2_2D_SIDE_FACE_M45_CAMERA_INDEX)
		{
			ImageFlipX(ColorSourceImage, BayerImage, startX, endX, startY, endY, currentImageWidth, currentImageHeight);
		}
		else if (cameraIndex == SD1_2D_FRONT_FACE_CAMERA_INDEX ||
				cameraIndex == SD2_2D_FRONT_FACE_CAMERA_INDEX ||
				cameraIndex == SD1_2D_SIDE_FACE_00_CAMERA_INDEX ||
				cameraIndex == SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX ||
				cameraIndex == SD1_2D_SIDE_FACE_P45_CAMERA_INDEX ||
				cameraIndex == SD1_2D_SIDE_FACE_M45_CAMERA_INDEX ||
				cameraIndex == SD1_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX ||
				cameraIndex == SD1_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX)
		{
			ImageFlipY(ColorSourceImage, BayerImage, startX, endX, startY, endY, currentImageWidth, currentImageHeight);
		}
		else
		{
			ImageFlipNone(ColorSourceImage, BayerImage, startX, endX, startY, endY, currentImageWidth, currentImageHeight);
		}

		// 화이트 밸런스를 맞춤.
		ApplyWhiteBalance(ColorSourceImage, startX, endX, startY, endY, currentImageWidth, &WhiteBalanceInfo[cameraIndex - 1]);
	}
	else if (ImageConvertOption == 1)
	{
		for (y = startY; y < endY; y++)
		{
			for (x = startX; x < endX; x++)
			{
				ColorSourceImage[(currentImageWidth * y + x) * 3 + 0] = BayerImage[(currentImageWidth * y + x) * 3 + 0];
				ColorSourceImage[(currentImageWidth * y + x) * 3 + 1] = BayerImage[(currentImageWidth * y + x) * 3 + 1];
				ColorSourceImage[(currentImageWidth * y + x) * 3 + 2] = BayerImage[(currentImageWidth * y + x) * 3 + 2];
			}
		}
	}

	if (TabletCharacter.HighResolutionImage)
	{
		memcpy(tempColorSourceImage, ColorSourceImage, HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3);
		memset(ColorSourceImage, 0, HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3);

		startX /= 2;
		endX /= 2;
		startY /= 2;
		endY /= 2;

		for (y = startY; y < endY; ++y)
		{
			for (x = startX; x < endX; ++x)
			{
				tempAddress = HD_IMAGE_WIDTH * y * 2 + x * 2;
				tempAddress2 = MAX_IMAGE_WIDTH * y + x;

				ColorSourceImage[tempAddress2 * 3 + 0] = tempColorSourceImage[tempAddress * 3 + 0];
				ColorSourceImage[tempAddress2 * 3 + 1] = tempColorSourceImage[tempAddress * 3 + 1];
				ColorSourceImage[tempAddress2 * 3 + 2] = tempColorSourceImage[tempAddress * 3 + 2];
			}
		}
	}

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = MAX_IMAGE_WIDTH * y + x;

			OneColorImage[tempAddress] = ColorSourceImage[tempAddress * 3 + rgb];
		}
	}
}
//---------------------------------------------------------------------------
void ColorCountClear_Func(void)
{
	Camera1RecordedColorCount_Of_InspectionProcess = 0;
	Camera9RecordedColorCount_Of_InspectionProcess = 0;
}
//---------------------------------------------------------------------------
void Make_ThreeD_Data_From_Src(int cameraIndex, int copyToImage)
{
	int x, y, x2, y2;
	int startX, endX, startY, endY;
	int rotateStX, rotateEdX, rotateStY, rotateEdY;
	const int THREE_D_SRC_IMAGE_WIDTH = 480;
	int tempAddress, tempAddress2;
	unsigned int upperValue;
	unsigned int lowerValue;
	unsigned int normalized;
	unsigned int tempValue;

	startX = TabletSetupData.ImageCutStartX[cameraIndex - 1];
	endX = TabletSetupData.ImageCutEndX[cameraIndex - 1];
	startY = TabletSetupData.ImageCutStartY[cameraIndex - 1];
	endY = TabletSetupData.ImageCutEndY[cameraIndex - 1];

	if (startX < 0)
		startX = 0;
	if (endX > MAX_IMAGE_WIDTH)
		endX = MAX_IMAGE_WIDTH;
	if (startY < 0)
		startY = 0;
	if (endY > MAX_IMAGE_HEIGHT)
		endY = MAX_IMAGE_HEIGHT;

	// 90도 회전된 영상이므로 X, Y 축 ROI 영역을 반대로 적용한다.
	rotateStX = (startY / 2) * 4;
	rotateEdX = (endY / 2) * 4;
	rotateStY = startX / 2;
	rotateEdY = endX / 2;

	if (copyToImage)
	{
		// 3D 이미지 추출 -> 회전 -> half 사이즈 복원을 한번에 처리.
		memset(ThreeD_Image, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

		for (y = rotateStY, y2 = rotateStY * 2; y < rotateEdY; y++, y2 += 2)
		{
			for (x = rotateStX, x2 = rotateStX / 2; x < rotateEdX; x += 2, ++x2)
			{
				// upperValue = (BayerImage[(y * THREE_D_SRC_IMAGE_WIDTH * 2) + x + 1]) << 8;
				// lowerValue = (BayerImage[(y * THREE_D_SRC_IMAGE_WIDTH * 2) + x + 0]);
				// normalized = (upperValue + lowerValue) * 255u / 65535u; // 0 ~ 65535의 스케일을 0 ~ 255로 바꾸는 것
				// normalized = ((upperValue + lowerValue) * 255u) >> 16; // 위의 것과 거의 차이가 없고 계산속도는 약간 빠르다.
				normalized = BayerImage[(y * THREE_D_SRC_IMAGE_WIDTH * 2) + x + 1]; // 약간의 손실이 있지만 속도는 빠르다. 문제 있으면 롤백하자.

				if (normalized && 245u >= normalized) // 255 - normalized >= 10
				{
					tempValue = 255u - normalized;
					tempAddress2 = MAX_IMAGE_WIDTH * x2 + y2; // 곱하기 1개 제거.
					ThreeD_Image[tempAddress2 + 0] = tempValue;
					ThreeD_Image[tempAddress2 + 1] = tempValue;
				}
			}
		}
	}
	else
	{
		memset(ThreeD_Data, 0, HALF_MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
		for (y = rotateStY; y < rotateEdY; y++)
		{
			for (x = rotateStX, x2 = rotateStX / 2; x < rotateEdX; x += 2, ++x2)
			{
				// upperValue = (BayerImage[(y * THREE_D_SRC_IMAGE_WIDTH * 2) + x + 1]) << 8;
				// lowerValue = (BayerImage[(y * THREE_D_SRC_IMAGE_WIDTH * 2) + x + 0]);
				// normalized = (upperValue + lowerValue) * 255u / 65535u; // 0 ~ 65535의 스케일을 0 ~ 255로 바꾸는 것
				// normalized = ((upperValue + lowerValue) * 255u) >> 16; // 위의 것과 거의 차이가 없고 계산속도는 약간 빠르다.
				normalized = BayerImage[(y * THREE_D_SRC_IMAGE_WIDTH * 2) + x + 1]; // 약간의 손실이 있지만 속도는 빠르다. 문제 있으면 롤백하자.

				if (normalized)
				{
					ThreeD_Data[x2 * HALF_MAX_IMAGE_WIDTH + y] = 255u - normalized;
				}
			}
		}
	}
}
//---------------------------------------------------------------------------------------------------------------------
int ColorDotLabeling(short *RESTRICT(label_Image), short *RESTRICT(defectPointData), int defectPointDataCnt, int cameraIndex)
{
	int i, m, x, y;
	int temp_address;
	int currentLabel;
	int new_count;
	short CollisionArray[MAX_LABEL_COUNT];
	int newLval;
	int temp;
	short labelGrid[(MAX_IMAGE_WIDTH / GRID_SIZE + 1) * (MAX_IMAGE_HEIGHT / GRID_SIZE + 1)]; // 30k

	int gridWidth;
	int gX, gY;
	int tempAddress;

	memset(label_Image, 0, sizeof(short) * MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	gridWidth = (MAX_IMAGE_WIDTH / GRID_SIZE + 1);

	currentLabel = 0;
	for (i = 0; i < MAX_LABEL_COUNT; i++)
	{
		CollisionArray[i] = i;
		Pixel_N_Of_Label[i] = 0;
		StartX_Label[i] = 640;
		EndX_Label[i] = 0;
		StartY_Label[i] = 640;
		EndY_Label[i] = 0;
	}

	for (m = 0; m < defectPointDataCnt; m++)
	{
		x = defectPointData[m * 3 + 0];
		y = defectPointData[m * 3 + 1];
		temp_address = MAX_IMAGE_WIDTH * (y) + x;
		if (*(label_Image + temp_address - MAX_IMAGE_WIDTH) == 0) // up is background
		{
			if (*(label_Image + temp_address - 1) == 0) // left is also background
			{
				currentLabel++;
				*(label_Image + temp_address) = currentLabel; // first label number is '1'
			}
			else // left is not background
			{
				*(label_Image + temp_address) = *(label_Image + temp_address - 1);
			}
		}
		else // up is not background
		{
			if (*(label_Image + temp_address - 1) == 0) // left is background
			{
				*(label_Image + temp_address) = *(label_Image + temp_address - MAX_IMAGE_WIDTH);
			}
			else // left is not background
			{
				if (*(label_Image + temp_address - MAX_IMAGE_WIDTH) == *(label_Image + temp_address - 1))
				{
					*(label_Image + temp_address) = *(label_Image + temp_address - MAX_IMAGE_WIDTH);
				}
				else // collision detected
				{	 // Left label이 Up label보다 항상 크다
					CollisionArray[max(*(label_Image + temp_address - 1), *(label_Image + temp_address - MAX_IMAGE_WIDTH))] =
						min(*(label_Image + temp_address - 1), *(label_Image + temp_address - MAX_IMAGE_WIDTH));
					*(label_Image + temp_address) = CollisionArray[*(label_Image + temp_address - MAX_IMAGE_WIDTH)];
				}
			}
		}
		if (currentLabel >= MAX_LABEL_COUNT - 1)
			break;
	}

	newLval = 1;
	for (i = 1; i <= currentLabel; i++)
	{
		if (CollisionArray[CollisionArray[i]] > newLval)
		{
			newLval++;
			CollisionArray[i] = newLval;
		}
		else
		{
			CollisionArray[i] = CollisionArray[CollisionArray[i]];
		}
	}

	if (newLval > 500)
		newLval = 499;
	new_count = newLval;

	memset(labelGrid, 0, (MAX_IMAGE_WIDTH / GRID_SIZE + 1) * (MAX_IMAGE_HEIGHT / GRID_SIZE + 1) * 2);
	for (m = 0; m < defectPointDataCnt; m++)
	{
		x = defectPointData[m * 3];
		y = defectPointData[m * 3 + 1];
		gX = x / GRID_SIZE;
		gY = y / GRID_SIZE;
		temp = *(label_Image + MAX_IMAGE_WIDTH * y + x);
		if (*(labelGrid + gridWidth * gY + gX) == 0)
		{
			*(labelGrid + gridWidth * gY + gX) = CollisionArray[temp];
		}
		else
		{
			*(labelGrid + gridWidth * gY + gX) = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
			CollisionArray[temp] = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
		}
	}
	memset(labelGrid, 0, (MAX_IMAGE_WIDTH / GRID_SIZE) * (MAX_IMAGE_HEIGHT / GRID_SIZE) * 2);
	for (m = 0; m < defectPointDataCnt; m++)
	{
		x = defectPointData[m * 3];
		y = defectPointData[m * 3 + 1];
		gX = (x + GRID_SIZE / 2) / GRID_SIZE;
		gY = (y + GRID_SIZE / 2) / GRID_SIZE;
		temp = *(label_Image + MAX_IMAGE_WIDTH * y + x);
		if (*(labelGrid + gridWidth * gY + gX) == 0)
		{
			*(labelGrid + gridWidth * gY + gX) = CollisionArray[temp];
		}
		else
		{
			*(labelGrid + gridWidth * gY + gX) = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
			CollisionArray[temp] = min(CollisionArray[temp], *(labelGrid + gridWidth * gY + gX));
		}
	}

	for (m = 0; m < defectPointDataCnt; m++)
	{
		x = defectPointData[m * 3];
		y = defectPointData[m * 3 + 1];
		tempAddress = MAX_IMAGE_WIDTH * y + x;

		temp = *(label_Image + tempAddress);
		temp = CollisionArray[temp];
		*(label_Image + tempAddress) = temp;

		Pixel_N_Of_Label[temp]++;

		if (StartX_Label[temp] > x)
			StartX_Label[temp] = x;
		if (StartY_Label[temp] > y)
			StartY_Label[temp] = y;
		if (EndX_Label[temp] < x)
			EndX_Label[temp] = x;
		if (EndY_Label[temp] < y)
			EndY_Label[temp] = y;
	}

	return (new_count);
}
//---------------------------------------------------------------------------------------------------------------------
int SmallSizePixelLabeling(unsigned char *RESTRICT(srcImage), short *RESTRICT(dstLabelImage), int startX, int endX, int startY, int endY, int imageWidth)
{
	// 2픽셀 단위 거리를 기반으로 라벨?처리함
	int tempAddress;
	int x, y;
	int maxLabelNum;
	int currentLabelNum;
	int i, j;
	int nX, nY;
	int MaxDefectGroupSize;
	int PixelCountInDefectGroup;
	int PixelIndex;
	int breakSW;
	int m;
	int tempLabelN;

	MaxDefectGroupSize = 10000; // 1개 라벨로 결정되는 최대 불량 크기

	// maxLabelNum -> short 크기(half), 기존의 short 이미지 array를 사용하여 half 사이즈임, -값은 사용하지 않음s
	// Array가 너무 커짐, 10000으로 제한
	maxLabelNum = SMALL_SIZE_DEFECT_MAX_LABEL_N - 1;
	currentLabelNum = 0;

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = imageWidth * y + x;

			if (srcImage[tempAddress] && dstLabelImage[tempAddress] == 0)
			{
				memset(DefectGroup, 0, sizeof(short) * 2500 * 2);
				PixelCountInDefectGroup = 0;
				PixelIndex = 0;

				if (currentLabelNum < maxLabelNum)
				{
					currentLabelNum++;

					DefectGroup[PixelCountInDefectGroup * 2 + 0] = x;
					DefectGroup[PixelCountInDefectGroup * 2 + 1] = y;

					breakSW = 0;

					while (1)
					{
						nX = DefectGroup[PixelIndex * 2 + 0];
						nY = DefectGroup[PixelIndex * 2 + 1];

						for (i = nY - 2; i <= nY + 2; i++)
						{
							for (j = nX - 2; j <= nX + 2; j++)
							{
								tempAddress = imageWidth * i + j;

								if (srcImage[tempAddress] && dstLabelImage[tempAddress] == 0)
								{
									dstLabelImage[tempAddress] = currentLabelNum;

									if (PixelCountInDefectGroup < MaxDefectGroupSize - 1)
									{
										PixelCountInDefectGroup++;

										DefectGroup[PixelCountInDefectGroup * 2 + 0] = j;
										DefectGroup[PixelCountInDefectGroup * 2 + 1] = i;
									}
									else
									{
										breakSW = 1;
										break;
									}
								}
							}

							if (breakSW)
								break;
						}

						if (breakSW)
							break;
						if (PixelCountInDefectGroup == PixelIndex)
							break;

						PixelIndex++;
					}
				}
			}
		}
	}

	memset(labelingPxCount, 0, sizeof(int) * SMALL_SIZE_DEFECT_MAX_LABEL_N);

	for (m = 0; m < SMALL_SIZE_DEFECT_MAX_LABEL_N; m++)
	{
		LabelStX[m] = 640;
		LabelStY[m] = 480;
		LabelEdX[m] = 0;
		LabelEdY[m] = 0;
	}

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = imageWidth * y + x;

			if (dstLabelImage[tempAddress])
			{
				tempLabelN = dstLabelImage[tempAddress];

				labelingPxCount[tempLabelN]++;

				if (LabelStX[tempLabelN] > x)
					LabelStX[tempLabelN] = x;
				if (LabelStY[tempLabelN] > y)
					LabelStY[tempLabelN] = y;
				if (LabelEdX[tempLabelN] < x)
					LabelEdX[tempLabelN] = x;
				if (LabelEdY[tempLabelN] < y)
					LabelEdY[tempLabelN] = y;
			}
		}
	}

	return currentLabelNum;
}
//---------------------------------------------------------------------------
void CheckPrintMatchingResult(int bThreeD)
{
	if (bThreeD == NOT_THREED)
	{
		if (TabletCharacter.discriminationDisplay_kind == PRINT || TabletCharacter.discriminationDisplay_kind == STAMP)
		{
			if (TabletCharacter.discriminationDisplay_num == ONE_FACE || TabletCharacter.discriminationDisplay_num == TWO_FACE_SAME)
			{
				if (PrintMatchingResult.dataNumberWithMaxValue > -1 && PrintMatchingResult.dataNumberWithMaxValue < 2)
				{
					PrintIsSW = 1;
					CurrentPrintType = 0;
				}
			}
			else // diff
			{
				if (PrintMatchingResult.dataNumberWithMaxValue > -1)
				{
					PrintIsSW = 1;

					if (PrintMatchingResult.dataNumberWithMaxValue < 2)
					{
						CurrentPrintType = 0;
					}
					else
					{
						CurrentPrintType = 1;
					}
				}
			}
		}
	}
	else if (bThreeD == THREED)
	{
		if (TabletCharacter.discriminationDisplay_kind == STAMP)
		{
			if (TabletCharacter.discriminationDisplay_num == ONE_FACE || TabletCharacter.discriminationDisplay_num == TWO_FACE_SAME)
			{
				if (PrintMatchingResult.dataNumberWithMaxValue > -1 && PrintMatchingResult.dataNumberWithMaxValue < 2)
				{
					PrintIsSW = 1;
					CurrentPrintType = 0;
				}
			}
			else // diff
			{
				if (PrintMatchingResult.dataNumberWithMaxValue > -1)
				{
					PrintIsSW = 1;

					if (PrintMatchingResult.dataNumberWithMaxValue < 2)
					{
						CurrentPrintType = 0;
					}
					else
					{
						CurrentPrintType = 1;
					}
				}
			}
		}
	}
}
//---------------------------------------------------------------------------
void CPBCommonVariableInitial()
{
	int x;
	int m;
	int tempIndex;

	for (m = 0; m < 720; m++)
	{
		CosData[m] = cos((float)m / 2.0 * PI / 180.0) * 1024.0;
		SinData[m] = sin((float)m / 2.0 * PI / 180.0) * 1024.0;

		CosSqrData[m] = cos((float)m / 2.0 * PI / 180.0) * cos((float)m / 2.0 * PI / 180.0) * 10000.0;
	}
	for (m = 0; m < 90000; m++)
	{
		if (m == 0)
			SqrtData[m] = 128;
		else
			SqrtData[m] = sqrt(m) * 128.0;
	}

	for (m = 0; m <= 10000; m++)
	{
		ArcSinData[m] = (int)(asin((float)m / 10000.0) * 180.0 / 3.141592 + 0.5);
		ArcSinData2[m] = (int)(asin((float)m / 10000.0) * 180.0 / 3.141592 * 1.2 + 0.5); // 1.2배 가중된 값.
	}

	memset(sinTable, 0, sizeof(int) * 361);
	memset(cosTable, 0, sizeof(int) * 361);
	memset(arcCosTable, 0, sizeof(int) * 20001);
	memset(sqrtTable, 0, sizeof(int) * MAX_SHAPE_RADIAL * MAX_SHAPE_RADIAL);

	tempIndex = 0;
	for (m = -10000; m <= 10000; m++)
	{
		arcCosTable[tempIndex] = (acos(m / 10000.0) / (float)PI) * 180.0;
		tempIndex++;
	}
	for (m = 0; m < MAX_SHAPE_RADIAL * MAX_SHAPE_RADIAL; m++)
	{
		sqrtTable[m] = sqrt(m) * 1000.0;
	}
	for (m = 0; m <= 360; m++)
	{
		sinTable[m] = sin((m / 180.0) * PI) * 10000.0;
		cosTable[m] = cos((m / 180.0) * PI) * 10000.0;
	}

#ifdef PC_SIM
	CPB_CORE_NUMBER = 0;
#endif

}
//---------------------------------------------------------------------------
void ApplyWhiteBalance(unsigned char *RESTRICT(srcImage), int startX, int endX, int startY, int endY, int imageWidth, TWhiteBalanceInfo *RESTRICT(pWhiteBalance))
{
	int x, y;
	int tempAddress;
	int tempBuff[3];
	int normalized[3];

	int maxB = min((pWhiteBalance->BColorInfo * 255) / 1000, 255);
	int maxG = min((pWhiteBalance->GColorInfo * 255) / 1000, 255);
	int maxR = min((pWhiteBalance->RColorInfo * 255) / 1000, 255);

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = imageWidth * y + x;

			tempBuff[0] = srcImage[tempAddress * 3 + 0];
			tempBuff[1] = srcImage[tempAddress * 3 + 1];
			tempBuff[2] = srcImage[tempAddress * 3 + 2];

			tempBuff[0] = min((pWhiteBalance->BColorInfo * tempBuff[0]) / 1000, 255);
			tempBuff[1] = min((pWhiteBalance->GColorInfo * tempBuff[1]) / 1000, 255);
			tempBuff[2] = min((pWhiteBalance->RColorInfo * tempBuff[2]) / 1000, 255);

			if (maxB)
				normalized[0] = min((tempBuff[0] * 255) / maxB, 255);
			else
				normalized[0] = 0;

			if (maxG)
				normalized[1] = min((tempBuff[1] * 255) / maxG, 255);
			else
				normalized[1] = 0;

			if (maxR)
				normalized[2] = min((tempBuff[2] * 255) / maxR, 255);
			else
				normalized[2] = 0;

			srcImage[tempAddress * 3 + 0] = normalized[0];
			srcImage[tempAddress * 3 + 1] = normalized[1];
			srcImage[tempAddress * 3 + 2] = normalized[2];
		}
	}
}
//---------------------------------------------------------------------------
int GetGlobalCameraIndex(int spbIndex, int SideAngle)
{
	// 같은 spb안에서 동일한 각도를 보는 카메라가.. 겹친다..
	// 일단 의미있는 res는 2,3,4 카메라만...
	int retCameraIndex;

	retCameraIndex = -1;

	if (spbIndex == 0 || spbIndex == 3) // 1번, 4번 SPB 무시
	{
		retCameraIndex = -1;
	}
	else
	{
		if (SideAngle == 0)
		{
			retCameraIndex = 2;
		}
		else if (SideAngle == 1)
		{
			retCameraIndex = 3;
		}
		else if (SideAngle == 2)
		{
			retCameraIndex = 4;
		}
	}

	return retCameraIndex;
}
//---------------------------------------------------------------------------
/*
void Erode(unsigned char *RESTRICT(srcImage), unsigned char *RESTRICT(dstImage), int startX, int endX, int startY, int endY, int maskSize)
{
	int x, y;
	int tempAddress, tempAddress2;
	int wm, hm;
	int tempX, tempY;
	int ErodeSW;

	wm = maskSize / 2;
	hm = maskSize / 2;

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = MAX_IMAGE_WIDTH * y + x;

			if (srcImage[tempAddress])
			{
				ErodeSW = 0;

				if (srcImage[tempAddress - hm] == 0 ||
					srcImage[tempAddress + hm] == 0 ||
					srcImage[tempAddress - wm * MAX_IMAGE_WIDTH] == 0 ||
					srcImage[tempAddress + wm * MAX_IMAGE_WIDTH] == 0)
				{
					ErodeSW = 1;
				}

				if (ErodeSW)
				{
					for (tempY = y - hm; tempY <= y + hm; tempY++)
					{
						for (tempX = x - wm; tempX <= x + wm; tempX++)
						{
							tempAddress2 = MAX_IMAGE_WIDTH * tempY + tempX;

							dstImage[tempAddress2] = 0;
						}
					}
				}
			}
		}
	}
}

void Dilate(unsigned char *RESTRICT(srcImage), unsigned char *RESTRICT(dstImage), int startX, int endX, int startY, int endY, int maskSize)
{
	int x, y;
	int tempAddress, tempAddress2;
	int wm, hm;
	int tempX, tempY;
	int DilateSW;

	wm = maskSize / 2;
	hm = maskSize / 2;

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = MAX_IMAGE_WIDTH * y + x;

			if (srcImage[tempAddress] == 0)
			{
				DilateSW = 0;

				if (srcImage[tempAddress - hm] ||
					srcImage[tempAddress + hm] ||
					srcImage[tempAddress - wm * MAX_IMAGE_WIDTH] ||
					srcImage[tempAddress + wm * MAX_IMAGE_WIDTH])
				{
					DilateSW = 1;
				}

				if (DilateSW)
				{
					for (tempY = y - hm; tempY <= y + hm; tempY++)
					{
						for (tempX = x - wm; tempX <= x + wm; tempX++)
						{
							if (tempX > startX && tempX < endX && tempY > startY && tempY < endY)
							{
								tempAddress2 = MAX_IMAGE_WIDTH * tempY + tempX;

								dstImage[tempAddress2] = 1;
							}
						}
					}
				}
			}
		}
	}
}
*/
//---------------------------------------------------------------------------
void SetThreeDSourceImage(int cameraIndex, int option)
{
	int x, y, x2, y2;
	int startX, endX, startY, endY;
	int tempAddress, tempAddress2;
	int HalfStartX, HalfEndX;
	int value;

	startX = TabletSetupData.ImageCutStartX[cameraIndex - 1] + 4;
	endX = TabletSetupData.ImageCutEndX[cameraIndex - 1] - 4;
	startY = TabletSetupData.ImageCutStartY[cameraIndex - 1] + 4;
	endY = TabletSetupData.ImageCutEndY[cameraIndex - 1] - 4;

	if (startX < 0)
		startX = 1;
	if (endX > ImageWidth)
		endX = ImageWidth - 1;
	if (startY < 0)
		startY = 1;
	if (endY > ImageHeight)
		endY = ImageHeight - 1;

	HalfStartX = startX / 2;
	HalfEndX = endX / 2;

	if (option != 2)
	{		
		memset(ThreeD_Data, 0, HALF_MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
		Make_ThreeD_Data_From_Src(cameraIndex, 1); // ThreeD_Data에 값이 없는 경우 BayerImage에서 3D 이미지 추출부터 10이하 커트와 half 사이즈 복원까지 전부 처리 해준다. 뒤의 옵션 1을 넣어야 동시에 처리됨.
	}
	else
	{
		// ThreeD_Data에 값이 이미 들어있는 경우. 10이하 커트와 half 사이즈 복원만 해준다.
		// half 사이즈 복원
		memset(ThreeD_Image, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		for (y = startY; y < endY; y++)
		{
			for (x = HalfStartX, x2 = HalfStartX * 2; x < HalfEndX; x++, x2 += 2)
			{
				tempAddress = HALF_MAX_IMAGE_WIDTH * y + x;
				tempAddress2 = MAX_IMAGE_WIDTH * y + x2; // 곱하기 1개 제거.

				value = ThreeD_Data[tempAddress];
				if (value >= 10) // 10미만 커트.
				{
					ThreeD_Image[tempAddress2 + 0] = value;
					ThreeD_Image[tempAddress2 + 1] = value;
				}
			}
		}
	}
}
//---------------------------------------------------------------------------
void threeDRotation(unsigned char *RESTRICT(threeDEraseArea), unsigned char *RESTRICT(halfRotationThreeDImage), unsigned int *RESTRICT(addressTable), unsigned short RESTRICT_ARRAY(shiftInfoArray)[3], unsigned char *RESTRICT(srcImage), int xzR, int yzR, int centerX, int centerY, int centerZ, int startX, int endX, int startY, int endY)
{
	int x, y, z;
	int tempAddress, tempAddress2;
	int xzCosValue, xzSinValue;
	int yzCosValue, yzSinValue;
	int rX, rY, rZ;
	int rX2, rY2, rZ2;
	
	int shiftInfoArrayCount;	

	shiftInfoArrayCount = 0;

	xzCosValue = CosData[(xzR + 720) % 720];
	xzSinValue = SinData[(xzR + 720) % 720];

	yzCosValue = CosData[(yzR + 720) % 720];
	yzSinValue = SinData[(yzR + 720) % 720];

	// 회전 각도에 따라 커트되는 측면의 범위를 한정하여 프로세싱 시간을 줄인다.
	if (yzR > 0)
	{
		if (endY >= centerY)
			endY = centerY;
	}
	else
	{
		if (startY <= centerY)
			startY = centerY;
	}

	// 가속을 위해서 범위를 2 배수로 바꿔줌 (원래도 기본적으로 2의 배수로 설정하고 있었으나 확실히 하기 위해서 다시 설정)
	startX = startX / 2 * 2;
	endX = endX / 2 * 2;
	startY = startY / 2 * 2;
	endY = endY / 2 * 2;

	memset(halfRotationThreeDImage, 0, HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT);

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			z = srcImage[HALF_IMAGE_WIDTH * y + x];

			if (z == 0) 
				continue;
			
			rX = (((x - centerX) * xzCosValue + (z - centerZ) * xzSinValue) / 1024) + centerX;
			rY = y;
			rZ = ((-(x - centerX) * xzSinValue + (z - centerZ) * xzCosValue) / 1024) + centerZ;

			if (rZ < 0)
				rZ = 0;
			else if (rZ > 255)
				rZ = 255;

			rX2 = rX;
			rY2 = (((rY - centerY) * yzCosValue - (rZ - centerZ) * yzSinValue) / 1024) + centerY;
			rZ2 = (((rY - centerY) * yzSinValue + (rZ - centerZ) * yzCosValue) / 1024) + centerZ;

			if (rZ2 < 0)
				rZ2 = 0;
			else if (rZ2 > 255)
				rZ2 = 255;

			if (rX2 < 0 || rX2 >= HALF_IMAGE_WIDTH || rY2 < 0 || rY2 >= HALF_IMAGE_HEIGHT)
				continue;

			// 회전된 이미지를 halfRotationThreeDImage에 입력하되 겹치는 경우 높은 값을 사용한다.
			// 이렇게 할 경우 측면의 픽셀은 정면의 픽셀 때문에 가려지게 되고 shiftInfoArray에 저장된 값과 halfRotationThreeDImage의 값이 달라지게 된다!
			halfRotationThreeDImage[HALF_IMAGE_WIDTH * rY2 + rX2] = max(halfRotationThreeDImage[HALF_IMAGE_WIDTH * rY2 + rX2], rZ2);

			if (shiftInfoArrayCount < HALF_IMAGE_WIDTH * HALF_IMAGE_HEIGHT)
			{
				addressTable[shiftInfoArrayCount] = HALF_IMAGE_WIDTH * y + x;

				shiftInfoArray[shiftInfoArrayCount][0] = rX2;
				shiftInfoArray[shiftInfoArrayCount][1] = rY2;
				shiftInfoArray[shiftInfoArrayCount][2] = rZ2;
				shiftInfoArrayCount++;
			}
		}
	}

	{
		int shiftX, shiftY, shiftZ;
		for (int m = 0; m < shiftInfoArrayCount; m++)
		{
			tempAddress = addressTable[m];

			shiftX = shiftInfoArray[m][0];
			shiftY = shiftInfoArray[m][1];
			shiftZ = shiftInfoArray[m][2] + 10;

			tempAddress2 = HALF_IMAGE_WIDTH * shiftY + shiftX;

			// 회전된 점(shiftInfoArray)의 z값보다 halfRotationThreeDImage에 저장된 점이 더 높다면 이것은 아마도 측면의 점일 것이다.
			// 정확하게 매칭 안되는 경우를 제외하고 주변의 점들이 모두 저장된 z값이 일정 이상 크다면 삭제될 점(측면의 점)으로 지정한다.
			if (halfRotationThreeDImage[tempAddress2] > shiftZ &&
				(halfRotationThreeDImage[tempAddress2 - 1] == 0 || halfRotationThreeDImage[tempAddress2 - 1] > shiftZ) &&
				(halfRotationThreeDImage[tempAddress2 + 1] == 0 || halfRotationThreeDImage[tempAddress2 + 1] > shiftZ) &&
				(halfRotationThreeDImage[tempAddress2 - 2] == 0 || halfRotationThreeDImage[tempAddress2 - 2] > shiftZ) &&
				(halfRotationThreeDImage[tempAddress2 + 2] == 0 || halfRotationThreeDImage[tempAddress2 + 2] > shiftZ) &&
				(halfRotationThreeDImage[tempAddress2 - HALF_IMAGE_WIDTH] == 0 || halfRotationThreeDImage[tempAddress2 - HALF_IMAGE_WIDTH] > shiftZ) &&
				(halfRotationThreeDImage[tempAddress2 + HALF_IMAGE_WIDTH] == 0 || halfRotationThreeDImage[tempAddress2 + HALF_IMAGE_WIDTH] > shiftZ))
			{
				threeDEraseArea[tempAddress] = 1;
			}
		}
	}
}
//---------------------------------------------------------------------------
int PrintLabeling(unsigned char *RESTRICT(srcImage), short *RESTRICT(dstLabelImage), int startX, int endX, int startY, int endY)
{
	// 2픽셀 단위 거리를 기반으로 라벨?처리함
	int tempAddress;
	int x, y;
	int maxLabelNum;
	int currentLabelNum;
	int i, j;
	int nX, nY;
	int MaxDefectGroupSize;
	int PixelCountInDefectGroup;
	int PixelIndex;
	int breakSW;
	int m;
	int tempLabelN;

	MaxDefectGroupSize = 10000; // 1개 라벨로 결정되는 최대 불량 크기

	// maxLabelNum -> short 크기(half), 기존의 short 이미지 array를 사용하여 half 사이즈임, -값은 사용하지 않음s
	// Array가 너무 커짐, 10000으로 제한
	maxLabelNum = SMALL_SIZE_DEFECT_MAX_LABEL_N - 1;
	currentLabelNum = 0;

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = MAX_IMAGE_WIDTH * y + x;

			if (srcImage[tempAddress] && dstLabelImage[tempAddress] == 0)
			{
				memset(DefectGroup, 0, sizeof(short) * 2500 * 2);
				PixelCountInDefectGroup = 0;
				PixelIndex = 0;

				if (currentLabelNum < maxLabelNum)
				{
					currentLabelNum++;

					DefectGroup[PixelCountInDefectGroup * 2 + 0] = x;
					DefectGroup[PixelCountInDefectGroup * 2 + 1] = y;

					breakSW = 0;

					while (1)
					{
						nX = DefectGroup[PixelIndex * 2 + 0];
						nY = DefectGroup[PixelIndex * 2 + 1];

						for (i = nY - 2; i <= nY + 2; i++)
						{
							for (j = nX - 2; j <= nX + 2; j++)
							{
								tempAddress = MAX_IMAGE_WIDTH * i + j;

								if (srcImage[tempAddress] && dstLabelImage[tempAddress] == 0)
								{
									dstLabelImage[tempAddress] = currentLabelNum;

									if (PixelCountInDefectGroup < MaxDefectGroupSize - 1)
									{
										PixelCountInDefectGroup++;

										DefectGroup[PixelCountInDefectGroup * 2 + 0] = j;
										DefectGroup[PixelCountInDefectGroup * 2 + 1] = i;
									}
									else
									{
										breakSW = 1;
										break;
									}
								}
							}

							if (breakSW)
								break;
						}

						if (breakSW)
							break;
						if (PixelCountInDefectGroup == PixelIndex)
							break;

						PixelIndex++;
					}
				}
			}
		}
	}

	memset(labelingPxCount, 0, sizeof(int) * SMALL_SIZE_DEFECT_MAX_LABEL_N);

	for (m = 0; m < SMALL_SIZE_DEFECT_MAX_LABEL_N; m++)
	{
		LabelStX[m] = 640;
		LabelStY[m] = 480;
		LabelEdX[m] = 0;
		LabelEdY[m] = 0;
	}

	for (y = startY; y < endY; y++)
	{
		for (x = startX; x < endX; x++)
		{
			tempAddress = MAX_IMAGE_WIDTH * y + x;

			if (dstLabelImage[tempAddress])
			{
				tempLabelN = dstLabelImage[tempAddress];

				labelingPxCount[tempLabelN]++;

				if (LabelStX[tempLabelN] > x)
					LabelStX[tempLabelN] = x;
				if (LabelStY[tempLabelN] > y)
					LabelStY[tempLabelN] = y;
				if (LabelEdX[tempLabelN] < x)
					LabelEdX[tempLabelN] = x;
				if (LabelEdY[tempLabelN] < y)
					LabelEdY[tempLabelN] = y;
			}
		}
	}

	return currentLabelNum;
}
//---------------------------------------------------------------------------
void ImageFlipX(unsigned char *RESTRICT(colorSourceImage), unsigned char *RESTRICT(bayerImage), int startX, int endX, int startY, int endY, int currentImageWidth, int currentImageHeight)
{
	// 좌우 반전
	int x, y;
	int tempAddress, tempAddress2;

	for (y = startY; y < endY; y++)
	{
		tempAddress = (currentImageWidth * y + startX) * 3;
		tempAddress2 = currentImageWidth * (y) + currentImageWidth - 1 - startX;
		for (x = startX; x < endX; x++)
		{
			if (y & 1)
			{
				if (x & 1) // R
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														4;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

					colorSourceImage[tempAddress + 2] = bayerImage[tempAddress2];
				}
				else // G
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
														 bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														8;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;
				}
			}
			else
			{
				if (x & 1) // G
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
														 bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														8;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;
				}
				else // B
				{
					colorSourceImage[tempAddress + 0] = bayerImage[tempAddress2];

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														4;
				}
			}

			tempAddress += 3;
			tempAddress2--;
		}
	}
}
//---------------------------------------------------------------------------
void ImageFlipY(unsigned char *RESTRICT(colorSourceImage), unsigned char *RESTRICT(bayerImage), int startX, int endX, int startY, int endY, int currentImageWidth, int currentImageHeight)
{
	// 상하반전
	int x, y;
	int tempAddress, tempAddress2;
	for (y = startY; y < endY; y++)
	{
		tempAddress = (currentImageWidth * y + startX) * 3;
		tempAddress2 = currentImageWidth * (currentImageHeight - 1 - y) + startX;
		for (x = startX; x < endX; x++)
		{
			if (y & 1)
			{
				if ((x & 1) == 0) // G
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
														 bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														8;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;
				}
				else // B
				{
					colorSourceImage[tempAddress + 0] = bayerImage[tempAddress2];

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														4;
				}
			}
			else
			{
				if ((x & 1) == 0) // R
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														4;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

					colorSourceImage[tempAddress + 2] = bayerImage[tempAddress2];
				}
				else // G
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
														 bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														8;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;
				}
			}

			tempAddress += 3;
			tempAddress2++;
		}
	}
}
//---------------------------------------------------------------------------
/*
void ImageFlipXY(unsigned char *RESTRICT(colorSourceImage), unsigned char *RESTRICT(bayerImage), int startX, int endX, int startY, int endY, int currentImageWidth, int currentImageHeight)
{
  // 상하좌우반전
  int x, y;
  int tempAddress, tempAddress2;

  for(y = startY; y < endY; y++)
  {
	tempAddress = (currentImageWidth * y + startX) * 3;
	tempAddress2 = currentImageWidth * (currentImageHeight - 1 - y) + currentImageWidth - 1 - startX;
	for(x = startX; x < endX; x++)
	{
	  if (y & 1)
	  {
		if (x & 1) // G
		{
		  colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;

		  colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
											  bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
											  bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) / 8;

		  colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;
		}
		else // B
		{
		  colorSourceImage[tempAddress + 0] = bayerImage[tempAddress2];

		  colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

		  colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
											  bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) / 4;
		}
	  }
	  else
	  {
		if (x & 1) // R
		{
		  colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
											  bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) / 4;

		  colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

		  colorSourceImage[tempAddress + 2] = bayerImage[tempAddress2];
		}
		else // G
		{
		  colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;

		  colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
											  bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
											  bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) / 8;

		  colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;
		}
	  }

	  tempAddress += 3;
	  tempAddress2--;
	}
  }
}
*/
//---------------------------------------------------------------------------
void ImageFlipNone(unsigned char *RESTRICT(colorSourceImage), unsigned char *RESTRICT(bayerImage), int startX, int endX, int startY, int endY, int currentImageWidth, int currentImageHeight)
{
	int x, y;
	int tempAddress, tempAddress2;

	for (y = startY; y < endY; y++)
	{
		tempAddress = (currentImageWidth * y + startX) * 3;
		tempAddress2 = currentImageWidth * y + startX;
		for (x = startX; x < endX; x++)
		{
			if ((y & 1) == 0)
			{
				if ((x & 1) == 0) // G
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
														 bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														8;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;
				}
				else // B
				{
					colorSourceImage[tempAddress + 0] = bayerImage[tempAddress2];

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														4;
				}
			}
			else
			{
				if ((x & 1) == 0) // R
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														4;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1] + bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 4;

					colorSourceImage[tempAddress + 2] = bayerImage[tempAddress2];
				}
				else // G
				{
					colorSourceImage[tempAddress + 0] = (bayerImage[tempAddress2 - currentImageWidth] + bayerImage[tempAddress2 + currentImageWidth]) / 2;

					colorSourceImage[tempAddress + 1] = (bayerImage[tempAddress2] * 4 +
														 bayerImage[tempAddress2 - currentImageWidth - 1] + bayerImage[tempAddress2 - currentImageWidth + 1] +
														 bayerImage[tempAddress2 + currentImageWidth - 1] + bayerImage[tempAddress2 + currentImageWidth + 1]) /
														8;

					colorSourceImage[tempAddress + 2] = (bayerImage[tempAddress2 - 1] + bayerImage[tempAddress2 + 1]) / 2;
				}
			}

			tempAddress += 3;
			tempAddress2++;
		}
	}
}
//---------------------------------------------------------------------------
void ProcessingStartForTPBImage(int TabletWidth, int TabletHeight, int WhiteBalanceB, int WhiteBalanceG, int WhiteBalanceR, int InsAreaLeft, int InsAreaRight, int InsAreaTop, int InsAreaBottom, int Threshold)
{
	//  TPB

	ColorChangeForTPB(WhiteBalanceB, WhiteBalanceG, WhiteBalanceR);
	InspectionTPBImage(TabletWidth, TabletHeight, InsAreaLeft, InsAreaRight, InsAreaTop, InsAreaBottom, Threshold);
}
//---------------------------------------------------------------------------
void ColorChangeForTPB(int WhiteBalanceB, int WhiteBalanceG, int WhiteBalanceR)
{
	int x, y;
	int startX, endX, startY, endY;
	int currentImageWidth;
	int currentImageHeight;
	int tempAddress, tempAddress2;
	TWhiteBalanceInfo tempWhiteBalanceInfo;

	startX = 10;
	endX = MAX_IMAGE_WIDTH - 10;
	startY = 10;
	endY = MAX_IMAGE_HEIGHT - 10;

	currentImageWidth = MAX_IMAGE_WIDTH;
	currentImageHeight = MAX_IMAGE_HEIGHT;

	ImageFlipY(ColorSourceImage, BayerImage, startX, endX, startY, endY, currentImageWidth, currentImageHeight);

	tempWhiteBalanceInfo.BColorInfo = WhiteBalanceB;
	tempWhiteBalanceInfo.GColorInfo = WhiteBalanceG;
	tempWhiteBalanceInfo.RColorInfo = WhiteBalanceR;

	ApplyWhiteBalance(ColorSourceImage, startX, endX, startY, endY, currentImageWidth, &tempWhiteBalanceInfo);
}
//---------------------------------------------------------------------------
void InspectionTPBImage(int TabletWidth, int TabletHeight, int InsAreaLeft, int InsAreaRight, int InsAreaTop, int InsAreaBottom, int Threshold)
{
	int x, y;
	int tempAddress;
	int protoThreshold;
	int ImageWidth;
	int minY, maxY;
	int startX, startY, endX, endY;
	int maxLabelN;
	int X1, Y1, X2, Y2, X3, Y3;
	int PlusX, PlusY;
	int MaxPlusX, MaxPlusY;
	int minX, maxX;
	int sizeMinX1;
	int sizeMinY1;
	int sizeMaxX1;
	int sizeMaxY1;
	int sizeMinX2;
	int sizeMaxX2;
	int sizeMinY2, sizeMaxY2;
	int sizeMinX3, sizeMinY3, sizeMaxX3, sizeMaxY3;
	int STDWidth, STDLength;
	short *label_Image;

	minX = InsAreaLeft;
	maxX = InsAreaRight;
	minY = MAX_IMAGE_HEIGHT - InsAreaBottom;
	maxY = MAX_IMAGE_HEIGHT - InsAreaTop;

	ImageWidth = MAX_IMAGE_WIDTH;

	label_Image = RotationEdgeImage;

	memset(ShapeBinaryImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
	memset(label_Image, 0, sizeof(short) * MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

	sizeMinX1 = sizeMinY1 = sizeMinX2 = sizeMinY2 = sizeMinX3 = sizeMinY3 = 1000;
	sizeMaxX1 = sizeMaxY1 = sizeMaxX2 = sizeMaxY2 = sizeMaxX3 = sizeMaxY3 = 0;

	protoThreshold = Threshold;

	for (y = minY; y < maxY; y++)
	{
		for (x = minX; x < maxX; x++)
		{
			tempAddress = ImageWidth * y + x;
			if (*(ColorSourceImage + (ImageWidth * y + x) * 3 + 1) > protoThreshold && *(ColorSourceImage + (ImageWidth * y + x) * 3 + 2) > protoThreshold && *(ColorSourceImage + (ImageWidth * y + x) * 3 + 0) > protoThreshold)
			{
				ShapeBinaryImage[tempAddress] = 1;
			}
		}
	}

	maxLabelN = LabellingForTabletImage(label_Image, ShapeBinaryImage, minX, maxX, minY, maxY, MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT);

	for (y = minY; y < maxY; y++)
	{
		for (x = minX; x < maxX; x++)
		{
			if (label_Image[(y)*ImageWidth + (x)] == 1)
			{
				if (sizeMinX1 > x)
					sizeMinX1 = x;
				if (sizeMinY1 > y)
					sizeMinY1 = y;
				if (sizeMaxX1 < x)
					sizeMaxX1 = x;
				if (sizeMaxY1 < y)
					sizeMaxY1 = y;
			}
			else if (label_Image[(y)*ImageWidth + (x)] == 2)
			{
				if (sizeMinX2 > x)
					sizeMinX2 = x;
				if (sizeMinY2 > y)
					sizeMinY2 = y;
				if (sizeMaxX2 < x)
					sizeMaxX2 = x;
				if (sizeMaxY2 < y)
					sizeMaxY2 = y;
			}
			else if (label_Image[(y)*ImageWidth + (x)] == 3)
			{
				if (sizeMinX3 > x)
					sizeMinX3 = x;
				if (sizeMinY3 > y)
					sizeMinY3 = y;
				if (sizeMaxX3 < x)
					sizeMaxX3 = x;
				if (sizeMaxY3 < y)
					sizeMaxY3 = y;
			}
		}
	}

	// test 정제 실제 size
	// Length : 12.31mm
	// Width : 6.27mm
	// 이미지 내의 정제 Size
	// Length : 53 Pixel
	// Width : 29 Pixel
	// 12.21 mm : 53 Pixel = 0.01mm : x Pixel
	// 6.27mm : 20 Pixel = 0.01mm : y Pixel
	// x = 0.043 Pixel
	// y = 0.046 Pixel
	// 라벨링 결과에 따른 오차 발생
	// 1mm = 4.5Pixel으로 계산
	// Product정보에 기입된 실제 size * 4.5Pixel을 기준으로 설정

	STDWidth = TabletWidth * 45 / 10;
	STDLength = TabletHeight * 45 / 10;
	/*
	STDLength = 1231/100 * 45 / 10;
	STDWidth = 627/100 * 45 / 10;
	 */
	DefectSW = 0;

	X1 = sizeMaxX1 - sizeMinX1;
	X2 = sizeMaxX2 - sizeMinX2;
	X3 = sizeMaxX3 - sizeMinX3;

	Y1 = sizeMaxY1 - sizeMinY1;
	Y2 = sizeMaxY2 - sizeMinY2;
	Y3 = sizeMaxY3 - sizeMinY3;

	PlusX = STDLength * 12 / 10;
	MaxPlusX = STDLength * 16 / 10;
	PlusY = STDWidth * 12 / 10;
	MaxPlusY = STDWidth * 16 / 10;

	if ((sizeMinX1 > minX + 1) && (sizeMaxX1 < maxX - 1))
	{
		if (sizeMinX1 != 1000 && sizeMinY1 != 1000 && sizeMaxX1 != 0 && sizeMaxY1 != 0)
		{
			if ((X1 < STDLength * 7 / 10) || (Y1 < STDWidth * 7 / 10))
			{
				// X1, Y1의 길이기 기준길이의 70% 이하일때 불량
				DefectSW = 4;
			}
			else if (((X1 > PlusX) && (X1 < MaxPlusX)) || ((Y1 > PlusY) && (Y1 < MaxPlusY)))
			{
				// X1, Y1의 길이가 1.2~1.6배 사이일경우 불량 ( 깨진 정제가 양품과 함께 붙어 촬영됨을 고려 )
				DefectSW = 4;
			}
		}
	}
	if ((sizeMinX2 > minX + 1) && (sizeMaxX2 < maxX - 1))
	{
		if (sizeMinX2 != 1000 && sizeMinY2 != 1000 && sizeMaxX2 != 0 && sizeMaxY2 != 0)
		{
			if ((X2 < STDLength * 7 / 10) || (Y2 < STDWidth * 7 / 10))
			{
				DefectSW = 4;
			}
			else if (((X2 > PlusX) && (X2 < MaxPlusX)) || ((Y2 > PlusY) && (Y2 < MaxPlusY)))
			{
				DefectSW = 4;
			}
		}
	}
	if ((sizeMinX3 > minX + 1) && (sizeMaxX3 < maxX - 1))
	{
		if (sizeMinX3 != 1000 && sizeMinY3 != 1000 && sizeMaxX3 != 0 && sizeMaxY3 != 0)
		{
			if ((X3 < STDLength * 7 / 10) || (Y3 < STDWidth * 7 / 10))
			{
				DefectSW = 4;
			}
			else if (((X3 > PlusX) && (X3 < MaxPlusX)) || ((Y3 > PlusY) && (Y3 < MaxPlusY)))
			{
				DefectSW = 4;
			}
		}
	}
}
//---------------------------------------------------------------------------

/*
1. cutoffvalue
   특징추출에서 틸팅이 되지않은 이미지 선택
   해당 이미지를 틸팅시키면서 overlap이 발생되지 않는 normalized value searching
   해당 수치를 검사 진행 시 활용

2. 미검처리 관련
   위 단계에서 정제가 최대로 틸팅되었을 때 정제의 외곽선 최소값을 threshold 설정
   정제의 정면에서 윗쪽 방향 외곽선 정보와 아래쪽 방향 외곽선 정보가 모두 threshold보다 낮으면 검사를 진행하지 않고 미검처리

3. 불량 관련
   정제에 불량이 심한 경우 (ex. 동구바이오) 불량이 사라질수도 있지 않나..

4. 케이스 구분, 3d disabled, sugarcoating 등

*/
