CImageProcessView.cpp

// ImageProcessView.cpp : implementation of the CImageProcessView class
//

#include "stdafx.h"
#include "ImageProcess.h"

#include "ImageProcessDoc.h"
#include "ImageProcessView.h"

#include "MainFrm.h"

#include "afxole.h"

#include "math.h"
#include "atlimage.h"

#include "CDemoTimer.h"

// 编码表RGB数组
#include "ColorTable.inc"		//颜色表

#include "Matrix.h"
#include "LEquations.h"
#include <stack>
#include <queue>
#include <list>
#include <afxtempl.h>

#include <vector>
//using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

const double Pi=3.14159;
const int TWOVALUE_H=0x80;
const int TWOVALUE_L=0x0;


int m_ModelWidth;
int m_ModelHeight;
unsigned char* m_pModelData=NULL;

const int TIMER_AVI=0;
// CImageProcessView

IMPLEMENT_DYNCREATE(CImageProcessView, CScrollView)

BEGIN_MESSAGE_MAP(CImageProcessView, CScrollView)
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
	ON_COMMAND(ID_FILE_RE, &CImageProcessView::OnFileReOpen)
	ON_UPDATE_COMMAND_UI(ID_FILE_RE, &CImageProcessView::OnUpdateFileReOpen)
	ON_COMMAND(ID_EDIT_PASTE, &CImageProcessView::OnEditPaste)
	ON_COMMAND(ID_EDIT_COPY, &CImageProcessView::OnEditCopy)
	ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, &CImageProcessView::OnUpdateEditCopy)
	ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, &CImageProcessView::OnUpdateEditPaste)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_COMMAND(ID_EDIT_CUT, &CImageProcessView::OnEditCut)
	ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, &CImageProcessView::OnUpdateEditCut)
	ON_COMMAND(ID_VIEW_SELECTAREAMAXIMUM, &CImageProcessView::OnViewSelectareamaximum)
	ON_UPDATE_COMMAND_UI(ID_VIEW_SELECTAREAMAXIMUM, &CImageProcessView::OnUpdateViewSelectareamaximum)
	ON_COMMAND(ID_VIEW_INFORMATION, &CImageProcessView::OnViewInformation)
	ON_UPDATE_COMMAND_UI(ID_VIEW_INFORMATION, &CImageProcessView::OnUpdateViewInformation)
	ON_COMMAND(ID_HISTGRAM_GRAY, &CImageProcessView::OnHistgramGray)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_GRAY, &CImageProcessView::OnUpdateHistgramGray)
	ON_COMMAND(ID_HISTGRAM_RGB, &CImageProcessView::OnHistgramRgb)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_RGB, &CImageProcessView::OnUpdateHistgramRgb)
	ON_COMMAND(ID_HISTGRAM_HSI, &CImageProcessView::OnHistgramHsi)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_HSI, &CImageProcessView::OnUpdateHistgramHsi)
	ON_COMMAND(ID_PREPROCESS_GRAY, &CImageProcessView::OnPreprocessGray)
	ON_UPDATE_COMMAND_UI(ID_PREPROCESS_GRAY, &CImageProcessView::OnUpdatePreprocessGray)
	ON_COMMAND(ID_PREPROCESS_PSDEOCOLORDISPLAY, &CImageProcessView::OnPreprocessPsdeocolordisplay)
	ON_UPDATE_COMMAND_UI(ID_PREPROCESS_PSDEOCOLORDISPLAY, &CImageProcessView::OnUpdatePreprocessPsdeocolordisplay)
	ON_COMMAND(ID_PREPROCESS_NEGATIVEIMAGE, &CImageProcessView::OnPreprocessNegativeimage)
	ON_UPDATE_COMMAND_UI(ID_PREPROCESS_NEGATIVEIMAGE, &CImageProcessView::OnUpdatePreprocessNegativeimage)
	ON_COMMAND(ID_HISTGRAM_EQUALIZER, &CImageProcessView::OnHistgramEqualizer)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_EQUALIZER, &CImageProcessView::OnUpdateHistgramEqualizer)
	ON_COMMAND(ID_HISTGRAM_ROBUSTNORMALIZATION, &CImageProcessView::OnHistgramRobustnormalization)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_ROBUSTNORMALIZATION, &CImageProcessView::OnUpdateHistgramRobustnormalization)
	ON_COMMAND(ID_GAMM_BRIGHT, &CImageProcessView::OnGammBright)
	ON_UPDATE_COMMAND_UI(ID_GAMM_DARK, &CImageProcessView::OnUpdateGammDark)
	ON_COMMAND(ID_GAMM_DARK, &CImageProcessView::OnGammDark)
	ON_UPDATE_COMMAND_UI(ID_GAMM_BRIGHT, &CImageProcessView::OnUpdateGammBright)
	ON_COMMAND(ID_ADDNOISE_GUASS, &CImageProcessView::OnAddnoiseGuass)
	ON_COMMAND(ID_ADDNOISE_SALTPEPPER, &CImageProcessView::OnAddnoiseSaltpepper)
	ON_UPDATE_COMMAND_UI(ID_ADDNOISE_GUASS, &CImageProcessView::OnUpdateAddnoiseGuass)
	ON_UPDATE_COMMAND_UI(ID_ADDNOISE_SALTPEPPER, &CImageProcessView::OnUpdateAddnoiseSaltpepper)
	ON_COMMAND(ID_HISTGRAM_LOCAL, &CImageProcessView::OnHistgramLocal)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_LOCAL, &CImageProcessView::OnUpdateHistgramLocal)
	ON_COMMAND(ID_PREPROCESS_LAPLACESHARPEN, &CImageProcessView::OnPreprocessLaplacesharpen)
	ON_UPDATE_COMMAND_UI(ID_PREPROCESS_LAPLACESHARPEN, &CImageProcessView::OnUpdatePreprocessLaplacesharpen)
	ON_COMMAND(ID_SMOOTH_MEANFILTER, &CImageProcessView::OnSmoothMeanfilter)
	ON_UPDATE_COMMAND_UI(ID_SMOOTH_MEANFILTER, &CImageProcessView::OnUpdateSmoothMeanfilter)
	ON_COMMAND(ID_SMOOTH_GAUSSFILTER, &CImageProcessView::OnSmoothGaussfilter)
	ON_UPDATE_COMMAND_UI(ID_SMOOTH_GAUSSFILTER, &CImageProcessView::OnUpdateSmoothGaussfilter)
	ON_COMMAND(ID_SMOOTH_MEDIANFILTER, &CImageProcessView::OnSmoothMedianfilter)
	ON_UPDATE_COMMAND_UI(ID_SMOOTH_MEDIANFILTER, &CImageProcessView::OnUpdateSmoothMedianfilter)
	ON_COMMAND(ID_SMOOTH_COLORFILTER, &CImageProcessView::OnSmoothColorfilter)
	ON_UPDATE_COMMAND_UI(ID_SMOOTH_COLORFILTER, &CImageProcessView::OnUpdateSmoothColorfilter)
	ON_COMMAND(ID_FREQUENCYDOMAIN_FFT, &CImageProcessView::OnFrequencydomainFft)
	ON_UPDATE_COMMAND_UI(ID_FREQUENCYDOMAIN_FFT, &CImageProcessView::OnUpdateFrequencydomainFft)
	ON_COMMAND(ID_BUTTERWORTH_LOWFILTER, &CImageProcessView::OnButterworthLowfilter)
	ON_COMMAND(ID_BUTTERWORTH_HIGHFILTER, &CImageProcessView::OnButterworthHighfilter)
	ON_UPDATE_COMMAND_UI(ID_BUTTERWORTH_LOWFILTER, &CImageProcessView::OnUpdateButterworthLowfilter)
	ON_UPDATE_COMMAND_UI(ID_BUTTERWORTH_HIGHFILTER, &CImageProcessView::OnUpdateButterworthHighfilter)
	ON_COMMAND(ID_FREQUENCYDOMAIN_HOMOMORPHICFILTER, &CImageProcessView::OnFrequencydomainHomomorphicfilter)
	ON_UPDATE_COMMAND_UI(ID_FREQUENCYDOMAIN_HOMOMORPHICFILTER, &CImageProcessView::OnUpdateFrequencydomainHomomorphicfilter)
	ON_COMMAND(ID_FILE_GETMODAL, &CImageProcessView::OnFileGetmodal)
	ON_UPDATE_COMMAND_UI(ID_FILE_GETMODAL, &CImageProcessView::OnUpdateFileGetmodal)
	ON_COMMAND(ID_SPATIALDOMAIN_IMAGE, &CImageProcessView::OnSpatialdomainImage)
	ON_UPDATE_COMMAND_UI(ID_SPATIALDOMAIN_IMAGE, &CImageProcessView::OnUpdateSpatialdomainImage)
	ON_COMMAND(ID_CONVOLUTION_MEAN, &CImageProcessView::OnConvolutionMean)
	ON_UPDATE_COMMAND_UI(ID_CONVOLUTION_MEAN, &CImageProcessView::OnUpdateConvolutionMean)
	ON_COMMAND(ID_CONVOLUTION_GAUSS, &CImageProcessView::OnConvolutionGauss)
	ON_UPDATE_COMMAND_UI(ID_CONVOLUTION_GAUSS, &CImageProcessView::OnUpdateConvolutionGauss)
	ON_COMMAND(ID_CONVOLUTION_LAPLACE, &CImageProcessView::OnConvolutionLaplace)
	ON_UPDATE_COMMAND_UI(ID_CONVOLUTION_LAPLACE, &CImageProcessView::OnUpdateConvolutionLaplace)
	ON_COMMAND(ID_CONVOLUTION_MARR, &CImageProcessView::OnConvolutionMarr)
	ON_UPDATE_COMMAND_UI(ID_CONVOLUTION_MARR, &CImageProcessView::OnUpdateConvolutionMarr)
	ON_COMMAND(ID_CONVOLUTION_CORRELATION, &CImageProcessView::OnConvolutionCorrelation)
	ON_UPDATE_COMMAND_UI(ID_CONVOLUTION_CORRELATION, &CImageProcessView::OnUpdateConvolutionCorrelation)
	ON_COMMAND(ID_ADAPTIVE_NOISEREDUCTION, &CImageProcessView::OnAdaptiveNoisereduction)
	ON_UPDATE_COMMAND_UI(ID_ADAPTIVE_NOISEREDUCTION, &CImageProcessView::OnUpdateAdaptiveNoisereduction)
	ON_COMMAND(ID_ADAPTIVE_MEDIAN, &CImageProcessView::OnAdaptiveMedian)
	ON_UPDATE_COMMAND_UI(ID_ADAPTIVE_MEDIAN, &CImageProcessView::OnUpdateAdaptiveMedian)
	ON_COMMAND(ID_FREQUENCYDOMAIN_NOTCHPASSFILTER, &CImageProcessView::OnFrequencydomainNotchpassfilter)
	ON_UPDATE_COMMAND_UI(ID_FREQUENCYDOMAIN_NOTCHPASSFILTER, &CImageProcessView::OnUpdateFrequencydomainNotchpassfilter)
	ON_COMMAND(ID_FREQUENCYDOMAIN_OPTIMUMNOTCHFILTER, &CImageProcessView::OnFrequencydomainOptimumnotchfilter)
	ON_UPDATE_COMMAND_UI(ID_FREQUENCYDOMAIN_OPTIMUMNOTCHFILTER, &CImageProcessView::OnUpdateFrequencydomainOptimumnotchfilter)
	ON_COMMAND(ID_FREQUENCYDOMAIN_WINNERFILTER, &CImageProcessView::OnFrequencydomainWinnerfilter)
	ON_UPDATE_COMMAND_UI(ID_FREQUENCYDOMAIN_WINNERFILTER, &CImageProcessView::OnUpdateFrequencydomainWinnerfilter)
	ON_COMMAND(ID_FREQUENCYDOMAIN_LEASTSQUARESFILTER, &CImageProcessView::OnFrequencydomainLeastsquaresfilter)
	ON_UPDATE_COMMAND_UI(ID_FREQUENCYDOMAIN_LEASTSQUARESFILTER, &CImageProcessView::OnUpdateFrequencydomainLeastsquaresfilter)
	ON_COMMAND(ID_SPATIALDOMAIN_GEOMETRICTRANSFORMATIONS, &CImageProcessView::OnSpatialdomainGeometrictransformations)
	ON_UPDATE_COMMAND_UI(ID_SPATIALDOMAIN_GEOMETRICTRANSFORMATIONS, &CImageProcessView::OnUpdateSpatialdomainGeometrictransformations)
	ON_COMMAND(ID_DWT_DWT, &CImageProcessView::OnDwtDwt)
	ON_UPDATE_COMMAND_UI(ID_DWT_DWT, &CImageProcessView::OnUpdateDwtDwt)
	ON_COMMAND(ID_DWT_IDWT, &CImageProcessView::OnDwtIdwt)
	ON_UPDATE_COMMAND_UI(ID_DWT_IDWT, &CImageProcessView::OnUpdateDwtIdwt)
	ON_COMMAND(ID_EDGE_ALL, &CImageProcessView::OnEdgeAll)
	ON_UPDATE_COMMAND_UI(ID_EDGE_ALL, &CImageProcessView::OnUpdateEdgeAll)
	ON_COMMAND(ID_EDGE_H, &CImageProcessView::OnEdgeH)
	ON_UPDATE_COMMAND_UI(ID_EDGE_H, &CImageProcessView::OnUpdateEdgeH)
	ON_COMMAND(ID_EDGE_V, &CImageProcessView::OnEdgeV)
	ON_UPDATE_COMMAND_UI(ID_EDGE_V, &CImageProcessView::OnUpdateEdgeV)
	ON_COMMAND(ID_DWT_SMOTH, &CImageProcessView::OnDwtSmooth)
	ON_UPDATE_COMMAND_UI(ID_DWT_SMOTH, &CImageProcessView::OnUpdateDwtSmooth)
	ON_COMMAND(ID_MORPHOLOGICAL_DILATION, &CImageProcessView::OnMorphologicalDilation)
	ON_UPDATE_COMMAND_UI(ID_MORPHOLOGICAL_DILATION, &CImageProcessView::OnUpdateMorphologicalDilation)
	ON_COMMAND(ID_MORPHOLOGICAL_EROSION, &CImageProcessView::OnMorphologicalErosion)
	ON_UPDATE_COMMAND_UI(ID_MORPHOLOGICAL_EROSION, &CImageProcessView::OnUpdateMorphologicalErosion)
	ON_COMMAND(ID_MORPHOLOGICAL_OPEN, &CImageProcessView::OnMorphologicalOpen)
	ON_UPDATE_COMMAND_UI(ID_MORPHOLOGICAL_OPEN, &CImageProcessView::OnUpdateMorphologicalOpen)
	ON_COMMAND(ID_MORPHOLOGICAL_CLOSE, &CImageProcessView::OnMorphologicalClose)
	ON_UPDATE_COMMAND_UI(ID_MORPHOLOGICAL_CLOSE, &CImageProcessView::OnUpdateMorphologicalClose)
	ON_COMMAND(ID_SEGMENTATION_FIXEDTHRESHOLD, &CImageProcessView::OnSegmentationFixedthreshold)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_FIXEDTHRESHOLD, &CImageProcessView::OnUpdateSegmentationFixedthreshold)
	ON_COMMAND(ID_MORPHOLOGICAL_HITORMISS, &CImageProcessView::OnMorphologicalHitormiss)
	ON_UPDATE_COMMAND_UI(ID_MORPHOLOGICAL_HITORMISS, &CImageProcessView::OnUpdateMorphologicalHitormiss)
	ON_COMMAND(ID_APPLICATION_BOUNDARYEXTRACTION, &CImageProcessView::OnApplicationBoundaryextraction)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_BOUNDARYEXTRACTION, &CImageProcessView::OnUpdateApplicationBoundaryextraction)
	ON_COMMAND(ID_APPLICATION_REGIONFILLING, &CImageProcessView::OnApplicationRegionfilling)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_REGIONFILLING, &CImageProcessView::OnUpdateApplicationRegionfilling)
	ON_COMMAND(ID_APPLICATION_CONNECTEDCOMPONENTS, &CImageProcessView::OnApplicationConnectedcomponents)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_CONNECTEDCOMPONENTS, &CImageProcessView::OnUpdateApplicationConnectedcomponents)
	ON_COMMAND(ID_APPLICATION_CONVEXHULL, &CImageProcessView::OnApplicationConvexhull)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_CONVEXHULL, &CImageProcessView::OnUpdateApplicationConvexhull)
	ON_COMMAND(ID_APPLICATION_THIN, &CImageProcessView::OnApplicationThin)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_THIN, &CImageProcessView::OnUpdateApplicationThin)
	ON_COMMAND(ID_APPLICATION_PRUNED, &CImageProcessView::OnApplicationPruned)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_PRUNED, &CImageProcessView::OnUpdateApplicationPruned)
	ON_COMMAND(ID_GRAY_DILATION, &CImageProcessView::OnGrayDilation)
	ON_UPDATE_COMMAND_UI(ID_GRAY_DILATION, &CImageProcessView::OnUpdateGrayDilation)
	ON_COMMAND(ID_GRAY_EROSION, &CImageProcessView::OnGrayErosion)
	ON_UPDATE_COMMAND_UI(ID_GRAY_EROSION, &CImageProcessView::OnUpdateGrayErosion)
	ON_COMMAND(ID_GRAY_OPEN, &CImageProcessView::OnGrayOpen)
	ON_UPDATE_COMMAND_UI(ID_GRAY_OPEN, &CImageProcessView::OnUpdateGrayOpen)
	ON_COMMAND(ID_GRAY_CLOSE, &CImageProcessView::OnGrayClose)
	ON_UPDATE_COMMAND_UI(ID_GRAY_CLOSE, &CImageProcessView::OnUpdateGrayClose)
	ON_COMMAND(ID_GRAY_GRADIENT, &CImageProcessView::OnGrayGradient)
	ON_UPDATE_COMMAND_UI(ID_GRAY_GRADIENT, &CImageProcessView::OnUpdateGrayGradient)
	ON_COMMAND(ID_GRAY_TOPHAT, &CImageProcessView::OnGrayTophat)
	ON_UPDATE_COMMAND_UI(ID_GRAY_TOPHAT, &CImageProcessView::OnUpdateGrayTophat)
	ON_COMMAND(ID_EDGE_SOBEL, &CImageProcessView::OnEdgeSobel)
	ON_UPDATE_COMMAND_UI(ID_EDGE_SOBEL, &CImageProcessView::OnUpdateEdgeSobel)
	ON_COMMAND(ID_EDGE_LAPLACE, &CImageProcessView::OnEdgeLaplace)
	ON_UPDATE_COMMAND_UI(ID_EDGE_LAPLACE, &CImageProcessView::OnUpdateEdgeLaplace)
	ON_COMMAND(ID_EDGE_LOG, &CImageProcessView::OnEdgeLog)
	ON_UPDATE_COMMAND_UI(ID_EDGE_LOG, &CImageProcessView::OnUpdateEdgeLog)
	ON_COMMAND(ID_HOUGH_LINES, &CImageProcessView::OnHoughLines)
	ON_UPDATE_COMMAND_UI(ID_HOUGH_LINES, &CImageProcessView::OnUpdateHoughLines)
	ON_COMMAND(ID_SEGMENTATION_REGIONGROWING, &CImageProcessView::OnSegmentationRegiongrowing)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_REGIONGROWING, &CImageProcessView::OnUpdateSegmentationRegiongrowing)
	ON_COMMAND(ID_SEGMENTATION_WATERSHED, &CImageProcessView::OnSegmentationWatershed)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_WATERSHED, &CImageProcessView::OnUpdateSegmentationWatershed)
	ON_COMMAND(ID_APPLICATION_THINBYCONDITION, &CImageProcessView::OnApplicationThinbycondition)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_THINBYCONDITION, &CImageProcessView::OnUpdateApplicationThinbycondition)
	ON_COMMAND(ID_OBJECTRECOGNITION_CORRELATIONMATCH, &CImageProcessView::OnObjectrecognitionCorrelationmatch)
	ON_UPDATE_COMMAND_UI(ID_OBJECTRECOGNITION_CORRELATIONMATCH, &CImageProcessView::OnUpdateObjectrecognitionCorrelationmatch)
	ON_COMMAND(ID_MORPHOLOGICAL_DISTANCETRANSFORM, &CImageProcessView::OnMorphologicalDistancetransform)
	ON_UPDATE_COMMAND_UI(ID_MORPHOLOGICAL_DISTANCETRANSFORM, &CImageProcessView::OnUpdateMorphologicalDistancetransform)
	ON_COMMAND(ID_APPLICATION_SEPARATEOBJECT, &CImageProcessView::OnApplicationSeparateobject)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_SEPARATEOBJECT, &CImageProcessView::OnUpdateApplicationSeparateobject)
	ON_COMMAND(ID_WATERSHEDPROCESS_GETSEED, &CImageProcessView::OnWatershedprocessGetseed)
	ON_UPDATE_COMMAND_UI(ID_WATERSHEDPROCESS_GETSEED, &CImageProcessView::OnUpdateWatershedprocessGetseed)
	ON_COMMAND(ID_WATERSHEDPROCESS_LABELMARKED, &CImageProcessView::OnWatershedprocessLabelmarked)
	ON_UPDATE_COMMAND_UI(ID_WATERSHEDPROCESS_LABELMARKED, &CImageProcessView::OnUpdateWatershedprocessLabelmarked)
	ON_COMMAND(ID_WATERSHEDPROCESS_GETAREAS, &CImageProcessView::OnWatershedprocessGetareas)
	ON_UPDATE_COMMAND_UI(ID_WATERSHEDPROCESS_GETAREAS, &CImageProcessView::OnUpdateWatershedprocessGetareas)
	ON_COMMAND(ID_SEGMENTATION_OSTU, &CImageProcessView::OnSegmentationOstu)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_OSTU, &CImageProcessView::OnUpdateSegmentationOstu)
	ON_COMMAND(ID_SEGMENTATION_ENTROPY, &CImageProcessView::OnSegmentationEntropy)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_ENTROPY, &CImageProcessView::OnUpdateSegmentationEntropy)
	ON_COMMAND(ID_SEGMENTATION_MAXLIKELIHOOD, &CImageProcessView::OnSegmentationMaxlikelihood)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_MAXLIKELIHOOD, &CImageProcessView::OnUpdateSegmentationMaxlikelihood)
	ON_COMMAND(ID_SEGMENTATION_LOCALTHRESHOLDING, &CImageProcessView::OnSegmentationLocalthresholding)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_LOCALTHRESHOLDING, &CImageProcessView::OnUpdateSegmentationLocalthresholding)
	ON_COMMAND(ID_APPLICATION_PARALLELTHIN, &CImageProcessView::OnApplicationParallelthin)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_PARALLELTHIN, &CImageProcessView::OnUpdateApplicationParallelthin)
	ON_COMMAND(ID_HOUGH_FONTOFNORMAL, &CImageProcessView::OnHoughFontofnormal)
	ON_UPDATE_COMMAND_UI(ID_HOUGH_FONTOFNORMAL, &CImageProcessView::OnUpdateHoughFontofnormal)
	ON_COMMAND(ID_CIRCLEDETECTION_CHORDBISECTIONALG, &CImageProcessView::OnCircledetectionChordbisectionalg)
	ON_UPDATE_COMMAND_UI(ID_CIRCLEDETECTION_CHORDBISECTIONALG, &CImageProcessView::OnUpdateCircledetectionChordbisectionalg)
	ON_COMMAND(ID_CIRCLEDETECTION_ACURR, &CImageProcessView::OnCircledetectionAcurr)
	ON_UPDATE_COMMAND_UI(ID_CIRCLEDETECTION_ACURR, &CImageProcessView::OnUpdateCircledetectionAcurr)
	ON_COMMAND(ID_HISTGRAM_GRAYBAR, &CImageProcessView::OnHistgramGrayBar)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_GRAYBAR, &CImageProcessView::OnUpdateHistgramGrayBar)
	ON_COMMAND(ID_HISTGRAM_RGBBAR, &CImageProcessView::OnHistgramRgbbar)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_RGBBAR, &CImageProcessView::OnUpdateHistgramRgbbar)
	ON_COMMAND(ID_HISTGRAM_HSIBAR, &CImageProcessView::OnHistgramHsibar)
	ON_UPDATE_COMMAND_UI(ID_HISTGRAM_HSIBAR, &CImageProcessView::OnUpdateHistgramHsibar)
	ON_COMMAND(ID_OBJECTRECOGNITION_PLESSEYCORNERDETECTOR, &CImageProcessView::OnObjectrecognitionPlesseycornerdetector)
	ON_UPDATE_COMMAND_UI(ID_OBJECTRECOGNITION_PLESSEYCORNERDETECTOR, &CImageProcessView::OnUpdateObjectrecognitionPlesseycornerdetector)
	ON_COMMAND(ID_EDGE_CANNY, &CImageProcessView::OnEdgeCanny)
	ON_UPDATE_COMMAND_UI(ID_EDGE_CANNY, &CImageProcessView::OnUpdateEdgeCanny)
	ON_COMMAND(ID_SEGMENTATION_OPTIMAL, &CImageProcessView::OnSegmentationOptimal)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_OPTIMAL, &CImageProcessView::OnUpdateSegmentationOptimal)
	ON_COMMAND(ID_EDGE_NON, &CImageProcessView::OnEdgeNon)
	ON_UPDATE_COMMAND_UI(ID_EDGE_NON, &CImageProcessView::OnUpdateEdgeNon)
	ON_COMMAND(ID_EDGE_HYSTERESIS, &CImageProcessView::OnEdgeHysteresis)
	ON_UPDATE_COMMAND_UI(ID_EDGE_HYSTERESIS, &CImageProcessView::OnUpdateEdgeHysteresis)
	ON_COMMAND(ID_HOUGH_CIRCLE, &CImageProcessView::OnHoughCircle)
	ON_UPDATE_COMMAND_UI(ID_HOUGH_CIRCLE, &CImageProcessView::OnUpdateHoughCircle)
	ON_COMMAND(ID_SEGMENTATION_DYNAMIC, &CImageProcessView::OnSegmentationDynamic)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_DYNAMIC, &CImageProcessView::OnUpdateSegmentationDynamic)
	ON_COMMAND(ID_SPATIALDOMAIN_ZOOMBILINEARINTERPOLATION, &CImageProcessView::OnSpatialdomainZoombilinearinterpolation)
	ON_UPDATE_COMMAND_UI(ID_SPATIALDOMAIN_ZOOMBILINEARINTERPOLATION, &CImageProcessView::OnUpdateSpatialdomainZoombilinearinterpolation)
	ON_UPDATE_COMMAND_UI(ID_APPLICATION_CONTOURTRACE, &CImageProcessView::OnUpdateApplicationContourtrace)
	ON_COMMAND(ID_APPLICATION_CONTOURTRACE, &CImageProcessView::OnApplicationContourtrace)
	ON_COMMAND(ID_EDGE_TRACE, &CImageProcessView::OnEdgeTrace)
	ON_UPDATE_COMMAND_UI(ID_EDGE_TRACE, &CImageProcessView::OnUpdateEdgeTrace)
	ON_WM_KEYDOWN()
	ON_COMMAND(ID_SMOOTH_TRUN, &CImageProcessView::OnSmoothTrun)
	ON_UPDATE_COMMAND_UI(ID_SMOOTH_TRUN, &CImageProcessView::OnUpdateSmoothTrun)
	ON_COMMAND(ID_SMOOTH_ANISOTROPICDIFFUSION, &CImageProcessView::OnSmoothAnisotropicdiffusion)
	ON_UPDATE_COMMAND_UI(ID_SMOOTH_ANISOTROPICDIFFUSION, &CImageProcessView::OnUpdateSmoothAnisotropicdiffusion)
	ON_COMMAND(ID_GRAY_RECONSTRUCTION, &CImageProcessView::OnGrayReconstruction)
	ON_COMMAND(ID_EDGE_RELAXATION, &CImageProcessView::OnEdgeRelaxation)
	ON_UPDATE_COMMAND_UI(ID_EDGE_RELAXATION, &CImageProcessView::OnUpdateEdgeRelaxation)
	ON_COMMAND(ID_SEGMENTATION_BOUNDARYTRACE, &CImageProcessView::OnSegmentationBoundarytrace)
	ON_UPDATE_COMMAND_UI(ID_SEGMENTATION_BOUNDARYTRACE, &CImageProcessView::OnUpdateSegmentationBoundarytrace)
	ON_COMMAND(ID_FILE_OPENAVI, &CImageProcessView::OnFileOpenavi)
	ON_WM_TIMER()
	ON_COMMAND(ID_FILE_BMP2AVI, &CImageProcessView::OnFileBmp2avi)
	ON_WM_RBUTTONDOWN()
	END_MESSAGE_MAP()

// CImageProcessView construction/destruction

CImageProcessView::CImageProcessView()
{
	// TODO: add construction code here
	m_bDrag=false;
	m_bTwoValue=false;
	m_bDWT=false;
	pDlg=NULL;
	THRESHOLD=100;
	m_bWatershedProcGetSeed=false;
	m_AviBuff=NULL;

}

CImageProcessView::~CImageProcessView()
{
	if(m_pModelData)
		delete []m_pModelData;
	m_pModelData=NULL;//must do it else heap err !!! 
	m_bWatershedProcGetSeed=false;
	if(pDlg)
	{   delete []pDlg->pData;
	delete pDlg;//无模式对话框
	pDlg=NULL;
	}
}

BOOL CImageProcessView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CScrollView::PreCreateWindow(cs);
}

// CImageProcessView drawing

void CImageProcessView::OnDraw(CDC* pDC)
{
	CImageProcessDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;


	CSize sizeTotal;
	if(pDoc->m_pDib->m_lpBMIH!=NULL){

		//if< image size some image part cann't see!
		sizeTotal.cx =pDoc->m_pDib->m_lpBMIH->biWidth+4;//change it ,no use? big enough then have bar
		sizeTotal.cy= pDoc->m_pDib->m_lpBMIH->biHeight+4;//big enough then have bar
		SetScrollSizes(MM_TEXT, sizeTotal);//must have ;use scroll
		ResizeParentToFit( );   

	}
	// TODO: add draw code for native data here
	//填充底色为灰
	CRect m_rcClient;
	GetClientRect(&m_rcClient);
	CBrush m_brsBG;
	m_brsBG.CreateSolidBrush(RGB(192,192,192));//COLOR_GRAY;
	pDC->FillRect(&m_rcClient, &m_brsBG);

	if (pDoc->m_pDib->m_lpBMIH!=NULL){
		CSize sizeFileDib=pDoc->m_pDib->GetDimensions();
		pDoc->m_pDib->Draw(pDC,CPoint(0,0),sizeFileDib);
		lWidth =pDoc->m_pDib->m_lpBMIH->biWidth;          // Size of DIB - x
		lHeight= pDoc->m_pDib->m_lpBMIH->biHeight;        // Size of DIB - y

		//if Select Area is error,init 
		if(pDoc->EndPoint.x-pDoc->StartPoint.x<=5 || pDoc->EndPoint.x>lWidth-1 ||
			pDoc->EndPoint.y-pDoc->StartPoint.y<=5 || pDoc->EndPoint.y>lHeight-1 || pDoc->StartPoint.y<0 || pDoc->StartPoint.x<0)
		{
			pDoc->StartPoint.x=0;pDoc->StartPoint.y=0;
			pDoc->EndPoint.x=lWidth-1;pDoc->EndPoint.y=lHeight-1;
		}


		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8 )
		{
			lLineBytes=lWidth & 0xffc;
			if(lWidth%4) lLineBytes+=4;

			//if TwoValue?
			m_bTwoValue=true;
			unsigned char* lpSrc;
			for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
			{	lpSrc =(unsigned char *)pDoc->m_pDib->m_lpImage+  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			// 针对每行图像每列进行操作
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
			{
				if(*lpSrc & 0x70)
				{
					m_bTwoValue=false;
					i =pDoc->EndPoint.y+1;//out
					j =pDoc->EndPoint.x+1;
				}
				lpSrc++;//

			}
			}


		}else if(pDoc->m_pDib->m_lpBMIH->biBitCount==24 )
			lLineBytes =(lWidth *3+3)/4*4;
		else if(pDoc->m_pDib->m_lpBMIH->biBitCount==32 )
			lLineBytes =lWidth *4;

		if(pDoc->StartPoint.y >0 || pDoc->StartPoint.x >0 || pDoc->EndPoint.y <lHeight-1 || pDoc->EndPoint.x <lWidth-1  ){//not all area
			CPen myPen;
			myPen.CreatePen(PS_DOT, 1, RGB(255,0,0));
			pDC->SelectObject(myPen);
			pDC->SelectObject(GetStockObject(NULL_BRUSH));
			pDC->Rectangle(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y));

		}


	}
	else
	{
		pDC->SetBkMode(TRANSPARENT);
		pDC->TextOut(50,100,"Open an Image !");
	}

}


// CImageProcessView printing

BOOL CImageProcessView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CImageProcessView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CImageProcessView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}


// CImageProcessView diagnostics

#ifdef _DEBUG
void CImageProcessView::AssertValid() const
{
	CScrollView::AssertValid();
}

void CImageProcessView::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}

CImageProcessDoc* CImageProcessView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CImageProcessDoc)));
	return (CImageProcessDoc*)m_pDocument;
}
#endif //_DEBUG


// CImageProcessView message handlers

void CImageProcessView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	// TODO: Add your specialized code here and/or call the base class

	CImageProcessDoc* pDoc = GetDocument();

	static bool first=true;//do it once,must have it for DisplayNewImg()
	if (pDoc->m_pDib->m_lpBMIH==NULL && first){
		first=false;
		CString m_fileName;//=("c:\\tu\\Iris.bmp");

		char strDirName[80]; 
		GetCurrentDirectory(80, (LPSTR)strDirName);
		CString pathName;
		pathName.Format(_T("%s"),strDirName);

		m_fileName=pathName+"\\lena.bmp";


		CFile file;

		if( file.Open(m_fileName,CFile::modeRead | CFile::shareDenyWrite,NULL))
		{	
			pDoc->m_pDib->Read(&file);file.Close();
			pDoc->SetPathName(m_fileName);//if not cannot get pDoc->GetPathName

		}

	}

	CSize sizeTotal;
	if(pDoc->m_pDib->m_lpBMIH==NULL){
		sizeTotal.cx =512+4;
		sizeTotal.cy= 512+4;
	}
	else{
		//if< image size some image part cann't see!
		sizeTotal.cx =pDoc->m_pDib->m_lpBMIH->biWidth+4;//change it ,no use? big enough then have bar
		sizeTotal.cy= pDoc->m_pDib->m_lpBMIH->biHeight+4;//big enough then have bar
	}
	SetScrollSizes(MM_TEXT, sizeTotal);//must have ;use scroll
	ResizeParentToFit( );   
}

void CImageProcessView::OnFileReOpen()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	CFile file;
	if(NULL!=file.Open(pDoc->GetPathName(),CFile::modeRead | CFile::shareDenyWrite,NULL))
	{
		pDoc->m_pDib->Read(&file);
		file.Close();
	}
}

void CImageProcessView::OnUpdateFileReOpen(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnEditPaste()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	COleDataObject dataObject;
	VERIFY(dataObject.AttachClipboard());

	// Seems to be MOVEABLE memory, so we must use GlobalLock!
	//  (hDib != lpDib) GetGlobalData copies the memory, so we can
	//  hang onto it until we delete the CDib.
	HGLOBAL hDib = dataObject.GetGlobalData(CF_DIB);
	ASSERT(hDib != NULL);
	LPVOID lpDib = ::GlobalLock(hDib);
	ASSERT(lpDib != NULL);
	pDoc->m_pDib->AttachMemory(lpDib, TRUE, hDib);

	CClientDC dc(this);
	pDoc->m_pDib->UsePalette(&dc);
	pDoc->SetModifiedFlag();
	pDoc->UpdateAllViews(NULL);
}

void CImageProcessView::OnEditCopy()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	COleDataSource* pSource = new COleDataSource();
	int nHeaderSize = pDoc->m_pDib->GetSizeHeader();
	int nImageSize = pDoc->m_pDib->GetSizeImage();
	HGLOBAL hHeader = ::GlobalAlloc(GMEM_SHARE,
		nHeaderSize + nImageSize);
	LPVOID pHeader = ::GlobalLock(hHeader);
	ASSERT(pHeader != NULL);
	LPVOID pImage = (LPBYTE) pHeader + nHeaderSize;
	memcpy(pHeader, pDoc->m_pDib->m_lpBMIH, nHeaderSize); 
	memcpy(pImage, pDoc->m_pDib->m_lpImage, nImageSize);
	// Receiver is supposed to free the global memory 
	::GlobalUnlock(hHeader);
	pSource->CacheGlobalData(CF_DIB, hHeader);
	if (pSource) 
		pSource->SetClipboard(); // OLE deletes data source


}

void CImageProcessView::OnUpdateEditCopy(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnUpdateEditPaste(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	//	CImageProcessDoc* pDoc = GetDocument();
	COleDataObject dataObject;
	BOOL bAvail = dataObject.AttachClipboard() && dataObject.IsDataAvailable(CF_DIB);
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	if(!m_bDrag){
		m_LastStPoint = point+GetDeviceScrollPosition( );
		m_LastEndPoint=m_LastStPoint;
		m_bDrag = true;
	}

	//select seed
	if(m_bWatershedProcGetSeed)
	{
		CPoint pt=point+GetDeviceScrollPosition( );
		*(m_pModelData+lLineBytes * (lHeight - 1 - pt.y) + pt.x)=TWOVALUE_H;
	}
	CScrollView::OnLButtonDown(nFlags, point);
}

void CImageProcessView::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CImageProcessDoc* pDoc = GetDocument();
	m_bDrag = false;
	//比较点大小,获取区域
	CPoint pt=point+GetDeviceScrollPosition( );
	CPoint pt1,pt2;
	pt1.x=min(m_LastStPoint.x,pt.x);
	pt1.y=min(m_LastStPoint.y,pt.y);
	pt2.x=max(m_LastStPoint.x,pt.x);
	pt2.y=max(m_LastStPoint.y,pt.y);
	if(pt1.x>0 && pt2.x-pt1.x>5 && pt2.x<lWidth-1
		&& pt1.y>0 && pt2.y-pt1.y>5 && pt2.y<lHeight-1)
	{
		//change select area
		pDoc->StartPoint=pt1;
		pDoc->EndPoint=pt2;

	}



	Invalidate(true);//Draw Rect 
	CScrollView::OnLButtonUp(nFlags, point);
}

void CImageProcessView::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CImageProcessDoc* pDoc = GetDocument();

	CPoint pt=point+GetDeviceScrollPosition( );
	if(m_bDrag)//Draw select Rect
	{

		RECT	lastrect, currect;
		lastrect.top =min(m_LastStPoint.y,m_LastEndPoint.y)-GetDeviceScrollPosition( ).y;
		lastrect.left =min(m_LastStPoint.x,m_LastEndPoint.x)-GetDeviceScrollPosition( ).x;
		lastrect.right =max(m_LastStPoint.x,m_LastEndPoint.x)-GetDeviceScrollPosition( ).x;
		lastrect.bottom =max(m_LastStPoint.y,m_LastEndPoint.y)-GetDeviceScrollPosition( ).y;


		currect.top =min(pt.y,m_LastStPoint.y)-GetDeviceScrollPosition( ).y; 
		currect.left =min(pt.x,m_LastStPoint.x)-GetDeviceScrollPosition( ).x; 
		currect.right =max(pt.x,m_LastStPoint.x)-GetDeviceScrollPosition( ).x;
		currect.bottom = max(pt.y,m_LastStPoint.y)-GetDeviceScrollPosition( ).y;

		SIZE	sz;
		sz.cx = 1;
		sz.cy = 1;

		CDC *pdc = GetDC();
		CBrush m_brsBG;
		m_brsBG.CreateSolidBrush(RGB(255,255,255));//;

		pdc->DrawDragRect(&currect, sz, &lastrect, sz, &m_brsBG,&m_brsBG);//, NULL);//no corlor 

		ReleaseDC(pdc);
		CString str;

		//CMainFrame* pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;
		//CStatusBar* pStatus=&pFrame->m_wndStatusBar;
		//if(pStatus){
		//	str.Format("区域(%d:%d)-(%d:%d)",currect.left,currect.top,currect.right,currect.bottom);
		//	pStatus->SetPaneText(0,str);
		//}
		// same as:
		str.Format("区域(%d:%d)-(%d:%d)",currect.left,currect.top,currect.right,currect.bottom);
		((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar.SetPaneText(0,str);

		m_LastEndPoint = pt;
	}
	else//display point infomation
	{
		m_LastEndPoint=pt;

		//display point value
		CString str;
		str="";
		if(pDoc->m_pDib->m_lpBMIH){
			unsigned char *lpSrc;
			if((pt.x>=0) && (pt.x<lWidth) && (pt.y>=0) && (pt.y<lHeight)){
				if(pDoc->m_pDib->m_lpBMIH->biBitCount==8 ){
					lpSrc=(unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes*(lHeight - 1 -pt.y) + pt.x;
					double grad=0.0;
					double angle=0.0;
					Gradient(pt,&grad,&angle);
					str.Format("(x=%d y=%d)=%d\tGradient(%3.1f,%3.1f)",pt.x,pt.y,*lpSrc,grad,angle);
				}
				else if(pDoc->m_pDib->m_lpBMIH->biBitCount==24 ){
					lpSrc=(unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes*(lHeight - 1 -pt.y) + pt.x*3;
					RGB rgb;
					HSI hsi;
					rgb.b=*lpSrc;rgb.g=*(lpSrc+1);rgb.r=*(lpSrc+2);
					RgbtoHsi(&rgb, &hsi);
					int gray=(int)(0.114*rgb.r+0.587*rgb.g+0.299*rgb.b);

					str.Format("Pos(%d %d) RGB(%d %d %d) Gray(%d) hsi(%4.1f %3.2f %3.2f--%d %d %d)",
						point.x,point.y,rgb.r,rgb.g,rgb.b,gray,
						hsi.Hue,hsi.Saturation,hsi.Intensity,
						(int)(hsi.Hue/360.0*255.0),(int)(hsi.Saturation*255.0),(int)(hsi.Intensity*255.0));
				}else  if(pDoc->m_pDib->m_lpBMIH->biBitCount==32 ){
					lpSrc=(unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes*(lHeight - 1 -pt.y) + pt.x*4;
					RGB rgb;
					HSI hsi;
					rgb.b=*lpSrc;rgb.g=*(lpSrc+1);rgb.r=*(lpSrc+2);//*(lpSrc+3)==*(lpSrc+1)?????
					RgbtoHsi(&rgb, &hsi);
					int gray=(int)(0.114*rgb.r+0.587*rgb.g+0.299*rgb.b);

					str.Format("Pos(%d %d) RGB(%d %d %d)  Gray(%d) hsi(%4.1f %3.2f %3.2f--%d %d %d)",
						point.x,point.y,rgb.r,rgb.g,rgb.b,gray,
						hsi.Hue,hsi.Saturation,hsi.Intensity,
						(int)(hsi.Hue/360.0*255.0),(int)(hsi.Saturation*255.0),(int)(hsi.Intensity*255.0));

				}
				((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar.SetPaneText(0,str);


			}
		}
	}
	CScrollView::OnMouseMove(nFlags, point);
}

void CImageProcessView::Gradient(CPoint pt,double* grad,double* angle)
{
	CImageProcessDoc* pDoc = GetDocument();
	int pixel[8];

	if(pt.y>2 && pt.y<lHeight-2 && pt.x>2 && pt.x<lWidth-2){
		//if(pt.y>0 && pt.y<lHeight-1 && pt.x>0 && pt.x<lWidth-1){
		unsigned char *lpSrc;
		lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - pt.y) + pt.x;

		//sobel no noise Theta<1 

		pixel[0] = (int)*(lpSrc+lLineBytes-1);
		pixel[1] = (int)*(lpSrc+lLineBytes);
		pixel[2] = (int)*(lpSrc+lLineBytes+1);
		pixel[3] = (int)*(lpSrc-1);
		pixel[4] = (int)*(lpSrc+1);
		pixel[5] = (int)*(lpSrc - lLineBytes-1);
		pixel[6] = (int)*(lpSrc - lLineBytes);
		pixel[7] = (int)*(lpSrc - lLineBytes+1);
		//  1   2   1
		//  0   0   0
		// -1  -2  -1

		int gy=pixel[0]+2*pixel[1]+pixel[2]-pixel[5]-2*pixel[6]-pixel[7];

		//  -1   0   1
		//  -2   0   2
		//  -1   0   1
		int gx=pixel[2]+2*pixel[4]+pixel[7]-pixel[0]-2*pixel[3]-pixel[5];


		no noise Theta<0.2
		//double h[7][7]=
		//{
		//	{ 0.000, -0.646, -0.815, 0.000, 0.815, 0.646, 0.000},
		//	{-0.963, -1.997, -1.000, 0.000, 1.000, 1.997, 0.963},
		//	{-2.458, -2.000, -1.000, 0.000, 1.000, 2.000, 2.458},
		//	{-2.962, -2.000, -1.000, 0.000, 1.000, 2.000, 2.962},
		//	{-2.458, -2.000, -1.000, 0.000, 1.000, 2.000, 2.458},
		//	{-0.963, -1.997, -1.000, 0.000, 1.000, 1.997, 0.963},
		//	{ 0.000, -0.646, -0.815, 0.000, 0.815, 0.646, 0.000}
		//};

		//double gx=0.0;
		//double gy=0.0;
		//for(int i=-3;i<4;i++)
		//	for(int j=-3;j<4;j++){
		//		gx+=(h[i+3][j+3]*(*(lpSrc+i*lLineBytes+j)));
		//		gy-=(h[j+3][i+3]*(*(lpSrc+i*lLineBytes+j)));
		//	}

		*grad =sqrt(double(gx*gx+gy*gy));
		if(gx==0){
			if(gy>0) *angle=90;
			else if(gy<0) *angle=270;
		}else{
			if(gy==0){
				if(gx>0) *angle=0;
				else if(gx<0) *angle=180;
			}else
			{
				*angle=180.0/Pi*atan((double)gy/gx);
				if(gx<0 && gy<0)
					*angle=*angle+180; 
				else if(gx<0 && gy>0) *angle=*angle+180;
				else if(gx>0 && gy<0) 
					if((*angle)<-0.5) *angle=*angle+360;
			}
		}
	}

}

void CImageProcessView::OnEditCut()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	int w,h;
	w=pDoc->EndPoint.x-pDoc->StartPoint.x+1;
	h=pDoc->EndPoint.y-pDoc->StartPoint.y+1;
	int n;
	int l;
	int biBitCount=pDoc->m_pDib->m_lpBMIH->biBitCount;
	if(biBitCount==8)
	{n=1;l=(w+3)/4*4;}
	else if(biBitCount==24)
	{n=3;l=(w*3+3)/4*4;}
	else {n=4;l=w*4;} 

	unsigned char *lpNewDIBBits=new unsigned char [((long) h) *  l];
	// 判断是否内存分配失败
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}
	unsigned char *lpDst,*lpSrc;
	for(int i = 0; i < h; i++)
	{
		// 列
		for(int j = 0; j <w ; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + (j+pDoc->StartPoint.x)*n;
			lpDst = (unsigned char*)lpNewDIBBits +  l * (h - 1 - i) + j*n;
			*lpDst=*lpSrc;
			if(n>=3){
				*(lpDst+1)=*(lpSrc+1);
				*(lpDst+2)=*(lpSrc+2);}
			if(n==8)//32 bit
				*(lpDst+3)=*(lpSrc+3);
		}
	}
	// 复制的图像
	unsigned char  ColorTable[1024];
	if(biBitCount==8){
		lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
		memcpy(ColorTable,lpSrc,1024);
	}

	delete 	pDoc->m_pDib;
	lHeight   =h;
	lWidth    =w;
	lLineBytes=l;
	pDoc->m_pDib =new CDib(CSize(lLineBytes,lHeight) ,biBitCount);
	pDoc->m_pDib->m_lpBMIH->biWidth=lWidth;

	if(biBitCount==8){
		lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
		memcpy(lpSrc,ColorTable,1024);
	}

	memcpy(pDoc->m_pDib->m_lpImage,lpNewDIBBits,lLineBytes*lHeight);
	delete []lpNewDIBBits;
	Invalidate(true);
}

void CImageProcessView::OnUpdateEditCut(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->StartPoint.y >0 || pDoc->StartPoint.x >0 || pDoc->EndPoint.y <lHeight-1 || pDoc->EndPoint.x <lWidth-1)
		if(pDoc->m_pDib->m_lpBMIH!=NULL)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}
void CImageProcessView::RgbtoHsi(RGB *pRgb, HSI *pHsi)
{
	const double ZERO_SATURATION=0.0;
	const double UNDEFINED_HUE=0.000;
	const double DEGREES_PER_RADIAN	=180.0 / 3.14159265358979;

	double	R, G, B, Sum, Quotient;
	double	Radians, Angle, MinValue, MaxValue, TempDouble1, TempDouble2;
	R = ((double) pRgb->r) / 255.0;
	G = ((double) pRgb->g) / 255.0;
	B = ((double) pRgb->b) / 255.0;
	Sum = R + G + B;
	pHsi->Intensity = Sum / 3.0;
	MinValue = (R < G) ? R : G;
	MinValue = (B < MinValue) ? B : MinValue;
	MaxValue = (R > G) ? R : G;
	MaxValue = (B > MaxValue) ? B : MaxValue;
	if(pHsi->Intensity < 0.00001)
		pHsi->Saturation = ZERO_SATURATION;
	else
		pHsi->Saturation = 1.0 - (3.0 * MinValue) / Sum;
	if(MinValue == MaxValue)
	{
		pHsi->Hue = UNDEFINED_HUE;
		pHsi->Saturation = ZERO_SATURATION;
		return;
	}

	TempDouble1 = (((R - G) + (R - B)) / 2.0);
	TempDouble2 = (R - G) * (R - G) + (R - B) * (G - B);
	Quotient = (TempDouble1 / sqrt(TempDouble2));
	Radians = acos(Quotient);
	Angle = Radians * DEGREES_PER_RADIAN;
	pHsi->Hue =(B>G) ? 360.0 - Angle : Angle;

	return;
}
void CImageProcessView::OnViewSelectareamaximum()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	pDoc->StartPoint.x=0;pDoc->StartPoint.y=0;
	pDoc->EndPoint.x=lWidth-1;pDoc->EndPoint.y=lHeight-1;
	Invalidate(true);	
}

void CImageProcessView::OnUpdateViewSelectareamaximum(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	bool bEnable=false;
	if(pDoc->StartPoint.y >0 || pDoc->StartPoint.x >0 || pDoc->EndPoint.y <lHeight-1 || pDoc->EndPoint.x <lWidth-1)
		bEnable=true;

	pCmdUI->Enable(bEnable);
}

void CImageProcessView::OnViewInformation()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	//display info
	CString str;
	if(pDoc->m_pDib->m_lpBMIH->biBitCount==8 ){
		int hist[256]={0};
		int min=255;
		int max=0;
		int total=0;
		int num=(pDoc->EndPoint.x-pDoc->StartPoint.x+1)*(pDoc->EndPoint.y-pDoc->StartPoint.y+1);

		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			unsigned char* lpSrc =(unsigned char *)pDoc->m_pDib->m_lpImage+  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){

				lpSrc++;//
				hist[*lpSrc]++;
				if(*lpSrc<min) min=*lpSrc;
				if(*lpSrc>max) max=*lpSrc;
				total+=*lpSrc;
			}

		}
		if(num<1) num=1;
		int mean=(int)(total/num);
		int v=0;
		int k_1=0,k_10=0,k_90=255,k_99=255;
		for(int i=0;i<256;i++)
		{
			v+=hist[i];
			if(v<num/100)
				k_1=i;
			if(v<num/10)
				k_10=i;
			if(v<num*9/10)
				k_90=i;
			if(v<num*99/100)
				k_99=i;
		}

		if(num>20){
			str.Format("\npDoc->StartPoint(%d ,%d)---pDoc->EndPoint(%d ,%d)\n Size(%dx%d)\n  min=%d,max=%d,mean=%d\n\nratio\tgray\n0.01\t%d \n0.1 \t%d\n0.9 \t%d\n0.99\t%d\n",
				pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y,pDoc->EndPoint.x-pDoc->StartPoint.x+1,pDoc->EndPoint.y-pDoc->StartPoint.y+1,
				min,max,mean,
				k_1,k_10,k_90,k_99);
			//TRACE(str);

			if(pDoc->EndPoint.x-pDoc->StartPoint.x+1<=16 && pDoc->EndPoint.y-pDoc->StartPoint.y+1<=16){

				//for see edge
				if(pDoc->EndPoint.x-pDoc->StartPoint.x<20 && pDoc->StartPoint.x<10)
				{	pDoc->EndPoint.x=15;
				pDoc->StartPoint.x=0;
				}

				if(pDoc->EndPoint.x-pDoc->StartPoint.x<20 && pDoc->EndPoint.x>lWidth-10)
				{	pDoc->EndPoint.x=lWidth-1;
				pDoc->StartPoint.x=lWidth-16;
				}

				if(pDoc->EndPoint.y-pDoc->StartPoint.y<20 && pDoc->StartPoint.y<10)
				{	pDoc->EndPoint.y=15;
				pDoc->StartPoint.y=0;
				}

				if(pDoc->EndPoint.y-pDoc->StartPoint.y<20 && pDoc->EndPoint.y>lHeight-10)
				{	pDoc->EndPoint.y=lHeight-1;
				pDoc->StartPoint.y=lHeight-16;
				}

				CString tmpstr;
				str.Format("Data Size(%d x %d)[%d,%d,%d,%d]:\n",pDoc->EndPoint.x-pDoc->StartPoint.x+1,pDoc->EndPoint.y-pDoc->StartPoint.y+1,
					pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y);
				for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
					str+="\n";
					unsigned char* lpSrc =(unsigned char *)pDoc->m_pDib->m_lpImage+  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
					for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
						lpSrc++;//
						if(m_bTwoValue) tmpstr.Format("%d ",*lpSrc);
						else{
							if(*lpSrc<10)  tmpstr.Format("00%d ",*lpSrc);
							else if(*lpSrc<100) tmpstr.Format("0%d ",*lpSrc);
							else tmpstr.Format("%d ",*lpSrc);
						}
						str+=tmpstr;
					}

				}
				tmpstr.Format("\n\n  min=%d,max=%d,mean=%d\nColor=%d\n",min,max,mean,pDoc->m_pDib->m_lpBMIH->biBitCount);
				str+=tmpstr;
			}
			MessageBox(str);
		}
	}
	else{//color
		unsigned char* lpSrc;
		int mingray=255;
		int maxgray=0;
		RGB minRgb;
		RGB maxRgb;
		HSI minHsi;
		HSI maxHsi;
		long int totalgray=0;
		long int totalrgb_r=0;
		long int totalrgb_g=0;
		long int totalrgb_b=0;
		double totalHsi_Hue=0.0;
		double totalHsi_Saturation=0.0;
		double totalHsi_Intensity=0.0;

		minRgb.b=minRgb.g=minRgb.r=255;
		maxRgb.b=maxRgb.g=maxRgb.r=0;
		minHsi.Hue=360.0;
		minHsi.Saturation=minHsi.Intensity=1.0;
		maxHsi.Hue=maxHsi.Saturation=maxHsi.Intensity=0.0;

		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
			{
				lpSrc=(unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes*(lHeight - 1 -i) + j*3;
				RGB rgb;
				HSI Hsi;
				rgb.b=*lpSrc;rgb.g=*(lpSrc+1);rgb.r=*(lpSrc+2);
				RgbtoHsi(&rgb, &Hsi);
				int gray=(int)(0.114*rgb.r+0.587*rgb.g+0.299*rgb.b);

				if(gray<mingray) mingray=gray;
				if(gray>maxgray) maxgray=gray;
				totalgray+=gray;

				if(rgb.r<minRgb.r) minRgb.r=rgb.r;
				if(rgb.r>maxRgb.r) maxRgb.r=rgb.r;
				totalrgb_r+=rgb.r;

				if(rgb.g<minRgb.g) minRgb.g=rgb.g;
				if(rgb.g>maxRgb.g) maxRgb.g=rgb.g;
				totalrgb_g+=rgb.g;

				if(rgb.b<minRgb.b) minRgb.b=rgb.b;
				if(rgb.b>maxRgb.b) maxRgb.b=rgb.b;
				totalrgb_b+=rgb.b;

				if(Hsi.Hue<minHsi.Hue) minHsi.Hue=Hsi.Hue;
				if(Hsi.Hue>maxHsi.Hue) maxHsi.Hue=Hsi.Hue;
				totalHsi_Hue+=Hsi.Hue;

				if(Hsi.Saturation<minHsi.Saturation) minHsi.Saturation=Hsi.Saturation;
				if(Hsi.Saturation>maxHsi.Saturation) maxHsi.Saturation=Hsi.Saturation;
				totalHsi_Saturation+=Hsi.Saturation;

				if(Hsi.Intensity<minHsi.Intensity) minHsi.Intensity=Hsi.Intensity;
				if(Hsi.Intensity>maxHsi.Intensity) maxHsi.Intensity=Hsi.Intensity;
				totalHsi_Intensity+=Hsi.Intensity;

			}
			long int num=(long(pDoc->EndPoint.x-pDoc->StartPoint.x+1))*(pDoc->EndPoint.y-pDoc->StartPoint.y+1);

			if(num>20){
				CString tmpStr;
				str.Format("pDoc->StartPoint(%d ,%d)---pDoc->EndPoint(%d ,%d)\n Size(%d x %d)\nColor=%d\n",
					pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y,pDoc->EndPoint.x-pDoc->StartPoint.x+1,
					pDoc->EndPoint.y-pDoc->StartPoint.y+1,pDoc->m_pDib->m_lpBMIH->biBitCount);
				tmpStr.Format("\n \tmin  \tmax \tmean\n");
				str+=tmpStr;
				tmpStr.Format("R\t%d \t%d \t%d\n",minRgb.r,maxRgb.r,(int)(totalrgb_r/num));	
				str+=tmpStr;
				tmpStr.Format("G\t%d \t%d \t%d\n",minRgb.g,maxRgb.g,(int)(totalrgb_g/num));	
				str+=tmpStr;
				tmpStr.Format("B\t%d \t%d \t%d\n",minRgb.b,maxRgb.b,(int)(totalrgb_b/num));	
				str+=tmpStr;

				tmpStr.Format("H\t%3.2f \t%3.2f \t%3.2f\n",minHsi.Hue,maxHsi.Hue,totalHsi_Hue/num);	
				str+=tmpStr;
				tmpStr.Format("S\t%3.2f \t%3.2f \t%3.2f\n",minHsi.Saturation,maxHsi.Saturation,totalHsi_Saturation/num);	
				str+=tmpStr;
				tmpStr.Format("I\t%3.2f \t%3.2f \t%3.2f\n",minHsi.Intensity,maxHsi.Intensity,totalHsi_Intensity/num);	
				str+=tmpStr;

				tmpStr.Format("\nGray\t%d \t%d \t%d\n",mingray,maxgray,(int)(totalgray/num));	
				str+=tmpStr;
				//TRACE(str);
				MessageBox(str);
			}
	}
}

void CImageProcessView::OnUpdateViewInformation(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramGray()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	int Hist[256]={0};
	GetHistgram(Hist,false);


	DisplayDlg dlg;
	dlg.pData=&Hist[0];
	dlg.m_Sizex=256;
	dlg.m_LinePos=100;
	dlg.m_Title=_T("灰度直方图");
	dlg.m_Level=1;

	dlg.DoModal();
}

void CImageProcessView::GetHistgram(int* pHistgram,bool bSmooth)
{
	CImageProcessDoc* pDoc = GetDocument();


	//获得直方图
	int iMaxGrayValue = 0;
	int iMinGrayValue = 255;

	unsigned char* lpSrc;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			int pixel = (int)*lpSrc;

			pHistgram[pixel]++;
			//修改最大,最小灰度值
			if(iMinGrayValue > pixel)
				iMinGrayValue = pixel;
			if(iMaxGrayValue < pixel)
				iMaxGrayValue = pixel;
		}
	}
	if(!bSmooth) return;

	int tmpH[256];
	memcpy(tmpH,pHistgram,256*sizeof(int));

	//Gauss filter[7]2.0
	//[32,60,88,100,88,60,32]

	/*double d1=exp(-1/(2.0*2.0*2.0));
	double d2=exp(-4/(2.0*2.0*2.0));
	double d3=exp(-9/(2.0*2.0*2.0));
	*/

	for (int i = max(iMinGrayValue-2,2); i < min(iMaxGrayValue+2,253);i++){
		int tmp=0;
		tmp=(tmpH[i-2]+tmpH[i+2])*32+(tmpH[i-2]+tmpH[i+2])*60+(tmpH[i-1]+tmpH[i+1])*88+tmpH[i]*100;
		pHistgram[i]=tmp/460;

	}

	return ;
}
void CImageProcessView::OnUpdateHistgramGray(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramRgb()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int m_nHistRGB[256*3]={0};
	unsigned char *lpSrc;

	// 计算各个灰度值的计数,即得到直方图
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
		{
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes*(lHeight-1-i) + j*3;//down -up
			// 计数加1
			m_nHistRGB[*(lpSrc+2)]++;//R
			m_nHistRGB[256+*(lpSrc+1)]++;//G
			m_nHistRGB[256*2+*(lpSrc)]++;//B
		}
		DisplayDlg dlg;
		dlg.pData=&m_nHistRGB[0];
		dlg.m_Sizex=256;
		dlg.m_Title="彩色RGB直方图";
		dlg.m_Level=3;//draw number
		dlg.m_LinePos=0;
		dlg.DoModal();

}

void CImageProcessView::OnUpdateHistgramRgb(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==24)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramHsi()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int m_nHistHSI[256*3]={0};
	unsigned char *lpSrc;

	// 计算各个灰度值的计数,即得到直方图
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
		{
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes*(lHeight-1-i) + j*3;//down -up

			RGB Rgb;
			HSI Hsi;
			Rgb.b=*lpSrc;Rgb.g=*(lpSrc+1);Rgb.r=*(lpSrc+2);
			RgbtoHsi(&Rgb, &Hsi);
			unsigned int H,S,I;
			H=(unsigned int) (Hsi.Hue/360.0*255.0);
			S=(unsigned int) (Hsi.Saturation*255.0);
			I=(unsigned int) (Hsi.Intensity*255.0);
			// 计数加1
			m_nHistHSI[H]++;//H
			m_nHistHSI[256+S]++;//S
			m_nHistHSI[256*2+I]++;//I
		}
		DisplayDlg dlg;
		dlg.pData=&m_nHistHSI[0];
		dlg.m_Sizex=256;
		dlg.m_Title="彩色HSI直方图";
		dlg.m_Level=3;//draw number
		dlg.m_LinePos=0;
		dlg.DoModal();

}

void CImageProcessView::OnUpdateHistgramHsi(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==24)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnPreprocessGray()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	// 更改光标形状
	BeginWaitCursor();


	// 获取指向BITMAPINFO结构的指针(Win3.0)
	if(pDoc->m_pDib->m_lpBMIH->biBitCount==8 ){
		//8bit to Gray
		// 灰度映射表
		BYTE bMap[256];

		// 计算灰度映射表(保存各个颜色的灰度值),并更新DIB调色板
		LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
		for (int i = 0; i < 256; i ++)
		{
			// 计算该颜色对应的灰度值
			bMap[i] = (BYTE)(0.299 * pDibQuad->rgbRed +
				0.587 * pDibQuad->rgbGreen +
				0.114 * pDibQuad->rgbBlue + 0.5);

			// 更新DIB调色板红色分量
			pDibQuad->rgbRed = (BYTE)i;

			// 更新DIB调色板绿色分量
			pDibQuad->rgbGreen =(BYTE)i;

			// 更新DIB调色板蓝色分量
			pDibQuad->rgbBlue = (BYTE)i;

			// 更新DIB调色板保留位
			pDibQuad->rgbReserved = 0;
			pDibQuad++;

		}

		// 更换每个象素的颜色索引(即按照灰度映射表换成灰度值)
		// 每行
		unsigned char *lpSrc;
		for(int i = 0; i < lHeight; i++)
		{
			// 每列
			for(int j = 0; j < lWidth; j++)
			{
				// 指向DIB第i行,第j个象素的指针
				lpSrc = pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i) + j;
				*lpSrc=bMap[*lpSrc];
			}
		}
	}
	else if(pDoc->m_pDib->m_lpBMIH->biBitCount>=24){
		//24bit to gray image
		unsigned char*	lpSrc;

		// 指向转置图像对应象素的指针
		unsigned char*	lpDst;

		lLineBytes =(lWidth *pDoc->m_pDib->m_lpBMIH->biBitCount/8+3)/4*4;
		long int lNewLineBytes=(lWidth +3)/4*4;


		// 指向转置图像的指针
		unsigned char*	lpNewDIBBits;
		// 暂时分配内存,以保存新图像
		lpNewDIBBits=new unsigned char [lHeight * lNewLineBytes];
		memset(lpNewDIBBits,0,lHeight * lNewLineBytes);
		// 判断是否内存分配失败
		if (lpNewDIBBits == NULL)
		{
			// 分配内存失败
			return ;
		}


		// 针对图像每行进行操作
		for(int i = 0; i < lHeight; i++)
		{
			// 针对每行图像每列进行操作
			for(int j = 0; j < lWidth; j++)
			{

				// 指向源DIB第i行,第j个象素的指针
				lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes*(lHeight - 1 - i) + j*pDoc->m_pDib->m_lpBMIH->biBitCount/8;

				lpDst =lpNewDIBBits + lNewLineBytes * (lHeight - 1 - i) + j;

				// 复制象素
				double v;
				v=0.299*(*lpSrc)+0.587*(*(lpSrc+1))+0.114*(*(lpSrc+2));//bgr

				*lpDst=(unsigned char)v;//GBR?
			}

		}
		lLineBytes=lNewLineBytes;


		CString str=pDoc->GetTitle();
		pDoc->SetTitle(str+"--Color");
		DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"Gray");
		delete []lpNewDIBBits;

	}
	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdatePreprocessGray(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount>=24)
			bAvail=true;
		else if(pDoc->m_pDib->m_lpBMIH->biBitCount==8){//it's gray image?
			LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
			bAvail=false;
			for (int i = 0; i < 256; i ++)
			{
				if((pDibQuad->rgbRed != pDibQuad->rgbGreen) ||  (pDibQuad->rgbRed !=pDibQuad->rgbBlue)
					|| (pDibQuad->rgbGreen !=pDibQuad->rgbBlue) || (pDibQuad->rgbRed != i))
				{
					bAvail=true;
					break;
				}
				pDibQuad++;
			}

		}
		pCmdUI->Enable(bAvail);
}

void CImageProcessView::DisplayNewImg(unsigned char* lpNewImg,int Lines,int Height,CString strTitle,bool bColor)
{
	CImageProcessDoc* pDoc = GetDocument();

	//建立一个新视图,显示分割结果
	CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);

	//发送新建文件的消息,创建一个新的文档-视图
	pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
	pFrame->SendMessage(WM_COMMAND, ID_WINDOW_CASCADE);

	//获取新建视图指针
	CImageProcessView* pView=(CImageProcessView*)pFrame->MDIGetActive()->GetActiveView();

	//获取相关联的新的文档类指针
	CImageProcessDoc* pDocNew=pView->GetDocument();
	delete 	pDocNew->m_pDib;
	if(bColor==false){
		pDocNew->m_pDib =new CDib(CSize(Lines,Height ) ,8);
		unsigned char * lpSrc;
		lpSrc=(unsigned char*)pDocNew->m_pDib->m_lpvColorTable;
		for(int i=0;i<256;i++){
			*lpSrc=(unsigned char)i;lpSrc++;
			*lpSrc=(unsigned char)i;lpSrc++;
			*lpSrc=(unsigned char)i;lpSrc++;
			*lpSrc=0;lpSrc++;
		}

		memcpy(pDocNew->m_pDib->m_lpImage, lpNewImg, Lines * Height);

	}
	else{
		pDocNew->m_pDib =new CDib(CSize(Lines,Height ) ,24);
		memcpy(pDocNew->m_pDib->m_lpImage, lpNewImg, (Lines*3) * Height);

	}

	pDocNew->SetTitle(strTitle);
	//display select Area
	pDocNew->StartPoint=pDoc->StartPoint;
	pDocNew->EndPoint=pDoc->EndPoint;

}

// 编码表含义
//******************************************
//COLOR_SCALE_COUNT=
// 		 "  0   常规灰度编码", 
//		 "  1   逆灰度编码",
//		 "  2   红色饱和度编码",
//		 "  3   绿色饱和度编码",
//		 "  4   蓝色饱和度编码",
//		 "  5   黄色饱和度编码",
//		 "  6   青色饱和度编码",
//       "  7   紫色饱和度编码", 
//       "  8   彩虹编码 1", 
//		 "	9   彩虹编码 2",
//		 "	10   热金属编码 1",
//       "	11   热金属编码 2",
//*******************************************
void CImageProcessView::OnPreprocessPsdeocolordisplay()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	// 更改光标形状
	BeginWaitCursor();
	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str+"Gray");

	const int CHARACT= 11;

	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
	for (int i = 0; i < 256; i ++)
	{

		// 更新DIB调色板蓝色分量
		pDibQuad->rgbBlue = ColorsTable[CHARACT][i][0];

		// 更新DIB调色板红色分量
		pDibQuad->rgbRed = ColorsTable[CHARACT][i][1];

		// 更新DIB调色板绿色分量
		pDibQuad->rgbGreen =ColorsTable[CHARACT][i][2];

		pDibQuad++;

	}

	//draw display table
	//color bar in bottom
	unsigned char*	lpSrc;
	for (int i =0; i <20; i ++)
	{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* i -1;
	for (int j =0; j <lWidth; j ++)
	{
		lpSrc++;
		*lpSrc=(BYTE)(j*256/lWidth);
	}
	}


	pDoc->SetTitle(str+"--PsdeoColor");

	// 更新视图

	Invalidate(true);

	// 恢复光标
	EndWaitCursor();	

}

void CImageProcessView::OnUpdatePreprocessPsdeocolordisplay(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8){//it's gray image?
			LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
			bAvail=true;
			for (int i = 0; i < 256; i ++)
			{
				if((pDibQuad->rgbRed != pDibQuad->rgbGreen) ||  (pDibQuad->rgbRed !=pDibQuad->rgbBlue)
					|| (pDibQuad->rgbGreen !=pDibQuad->rgbBlue))
				{
					bAvail=false;
					break;
				}
				pDibQuad++;
			}

		}
		pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnPreprocessNegativeimage()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	// 更改光标形状
	BeginWaitCursor();
	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str);

	unsigned char *lpSrc;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +pDoc->StartPoint.x;
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{
		if(!m_bTwoValue) 
			*lpSrc=255-*lpSrc;
		else *lpSrc=TWOVALUE_H-*lpSrc;
		lpSrc++;
	}
	}

	pDoc->SetTitle(str+"--Negative");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);



}

void CImageProcessView::OnUpdatePreprocessNegativeimage(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramEqualizer()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int Hist[256]={0};

	GetHistgram(Hist,false);

	for(int k=1;k<256;k++) Hist[k]+=Hist[k-1];


	//计算对应的灰度值
	int Num=pDoc->EndPoint.y-pDoc->StartPoint.y+1;
	Num*=(pDoc->EndPoint.x-pDoc->StartPoint.x+1);
	for(int k=0;k<256;k++) Hist[k]=Hist[k]*255/Num;//look table

	method1  Histogram equalization变换
	//unsigned char *lpSrc;
	//for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	//{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
	//for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	//{	
	//	*lpSrc=(unsigned char)(Hist[*lpSrc]);
	//	lpSrc++;
	//}
	//}

	//method2 change lut table
	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
	for (int i = 0; i < 256; i ++)
	{

		int v=Hist[i];
		pDibQuad->rgbBlue = (BYTE)v;
		pDibQuad->rgbRed =(BYTE)v;
		pDibQuad->rgbGreen =(BYTE)v;
		pDibQuad++;

	}
	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"--直方图均衡化");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

}

void CImageProcessView::OnUpdateHistgramEqualizer(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramRobustnormalization()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int Hist[256]={0};

	GetHistgram(Hist,false);

	for(int k=1;k<256;k++) Hist[k]+=Hist[k-1];


	const double Th1=0.2;
	const double Th2=0.8;


	int g_min=0;
	int g_max=255;

	int size=(pDoc->EndPoint.x-pDoc->StartPoint.x+1)*(pDoc->EndPoint.y-pDoc->StartPoint.y+1);
	while(Hist[g_min]<(int)(size*Th1))
		g_min++;

	while(Hist[g_max]>(int)(size*Th2))
		g_max--;

	g_min=min(g_min,100);
	g_max=min(max(g_max,128),220);

	double a=255.0/(g_max-g_min);
	double b=-a*g_min;

	//change lut table
	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
	for (int i = 0; i < 256; i ++)
	{

		int v=min(max((int)(a*i+b+0.5),0),255);
		pDibQuad->rgbBlue = (BYTE)v;
		pDibQuad->rgbRed =(BYTE)v;
		pDibQuad->rgbGreen =(BYTE)v;
		pDibQuad++;

	}


	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"--直方图归一化");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

}

void CImageProcessView::OnUpdateHistgramRobustnormalization(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);

}

void CImageProcessView::OnGammBright()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	const double r=.2;
	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
	for (int i = 0; i < 256; i ++)
	{

		//double tmp=(i+1)/256.0;//only one times
		double tmp=(pDibQuad->rgbBlue+1)/256.0;//can do it again
		if(tmp<0.9999)
			tmp=exp(r*log(tmp));
		int v=(int)(tmp*256);
		pDibQuad->rgbBlue = (BYTE)v;
		pDibQuad->rgbRed =(BYTE)v;
		pDibQuad->rgbGreen =(BYTE)v;
		pDibQuad++;

	}
	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"--伽马校正(r<0)");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
}


void CImageProcessView::OnGammDark()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	const double r=2.0;
	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable;
	for (int i = 0; i < 256; i ++)
	{

		//double tmp=(i+1)/256.0;//only one times
		double tmp=(pDibQuad->rgbBlue+1)/256.0;//can do it again
		if(tmp<0.9999)
			tmp=exp(r*log(tmp));
		int v=(int)(tmp*256);
		pDibQuad->rgbBlue = (BYTE)v;
		pDibQuad->rgbRed =(BYTE)v;
		pDibQuad->rgbGreen =(BYTE)v;
		pDibQuad++;

	}
	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"--伽马校正(r>0)");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
}

void CImageProcessView::OnUpdateGammBright(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}
void CImageProcessView::OnUpdateGammDark(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnAddnoiseGuass()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();



	const double Mean=0;
	const double Dev=20;

	//Method1:
	//1、获取概率分布
	//2、求累积
	double p[256];
	p[0]=0.0;
	for(int i=-127;i<128;i++)
		p[i+128]=p[i+128-1]+(double)(exp(double(-(i-Mean)*(i-Mean)/(2*Dev*Dev)))/(Dev*sqrt(2.0*Pi)));

	srand( (unsigned)time( NULL ) );
	double N=0.0;
	double S=0.0;
	unsigned char* lpSrc;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +pDoc->StartPoint.x;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){

			//3、获取均匀分布值
			double q=(double)rand();
			q/=RAND_MAX;
			//4、获取对应值
			int k;
			for(k=0;k<256;k++)//q==p[k]
				if(q<=p[k])break;
			int v;
			//5、添加噪声
			v=((int)*lpSrc)+128-k;//
			if(v<0) v=0;
			else if(v>255) v=255;
			S+=v*v;//定义如此:  not ((*lpSrc)*(*lpSrc));
			N+=((v-*lpSrc)*(v-*lpSrc));
			*lpSrc=(unsigned char)v;

			lpSrc++;
		}
	}


	Method2:
	//
	//srand( (unsigned)time( NULL ) );
	//double N=0.0;
	//double S=0.0;
	//unsigned char* lpSrc;
	//for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
	//	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +pDoc->StartPoint.x;
	//	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x-1; j +=2){
	//           
	//		//1、获取均匀分布值
	//		double q=(double)rand();
	//		double r=q/RAND_MAX;
	//		
	//		q=(double)rand();
	//		double theta=q/RAND_MAX;
	//		
	//		//3、获取对应值
	//		double z1=Dev*cos(2*Pi*theta)*sqrt(-2*log(r));//log10
	//		double z2=Dev*sin(2*Pi*theta)*sqrt(-2*log(r));
	//		
	//		//4、添加噪声
	//		
	//		int v=((int)*lpSrc)+(int)z1;//
	//		if(v<0) v=0;
	//		else if(v>255) v=255;
	//		
	//		S+=(v*v);N+=((v-*lpSrc)*(v-*lpSrc));
	//		*lpSrc=(unsigned char)v;
	//		
	//		lpSrc++;
	//		
	//		v=((int)*lpSrc)+(int)z2;//
	//		if(v<0) v=0;
	//		else if(v>255) v=255;
	//		
	//		S+=(v*v);N+=((v-*lpSrc)*(v-*lpSrc));
	//		*lpSrc=(unsigned char)v;

	//		lpSrc++;
	//		
	//		
	//	}
	//}

	CString str=pDoc->GetTitle();
	CString str1;
	str1.Format("--+高斯噪声(SNR:%3.1f)",S/N);
	str+=str1;
	pDoc->SetTitle(str);

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
}

void CImageProcessView::OnAddnoiseSaltpepper()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();


	srand( (unsigned)time( NULL ) );


	double N=0.0;
	double S=0.0;
	unsigned char* lpSrc;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +pDoc->StartPoint.x;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			float dtmp= (float)rand();
			dtmp/=RAND_MAX;
			double v=*lpSrc;
			if(dtmp<0.1)  //10%
			{
				if(rand()%2) *lpSrc = 0;
				else *lpSrc = 255;
			}
			S+=((*lpSrc) * (*lpSrc));N+=((v-*lpSrc)*(v-*lpSrc));

			lpSrc++;
		}
	}

	CString str=pDoc->GetTitle();
	CString str1;
	str1.Format("--+椒盐噪声(SNR:%3.1f)",S/N);
	str+=str1;
	pDoc->SetTitle(str);

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
}

void CImageProcessView::OnUpdateAddnoiseGuass(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnUpdateAddnoiseSaltpepper(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramLocal()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);


	//获得直方图
	int Hist[256]={0};
	GetHistgram(Hist,false);

	//get mean,segma
	double Mean=0;
	for (int i = 0; i < 256;i++)
	{

		Mean+=(i*Hist[i]);
	}
	Mean=Mean/(pDoc->EndPoint.x-pDoc->StartPoint.x+1)/(pDoc->EndPoint.y-pDoc->StartPoint.y+1);

	double Segma=0;
	for (int i = 0; i < 256;i++)
	{

		Segma+=((i-Mean)*(i-Mean)*Hist[i]);
	}
	Segma=sqrt(Segma/(pDoc->EndPoint.x-pDoc->StartPoint.x+1)/(pDoc->EndPoint.y-pDoc->StartPoint.y+1));

	double E=4.0,k0=0.4,k1=0.02,k2=0.4;
	int M=3,N=3;
	double mean,segma;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			if(i>M/2 && i<lHeight-1-M/2 && j>M/2 && j<lWidth-1-M/2){
				//Get M*N mean
				mean=0.0;
				for(int m=-M/2;m<=M/2;m++)
					for(int n=-N/2;n<=N/2;n++)
						mean+=*(lpSrc+ lLineBytes* m+n);

				mean/=(M*N);
				if(mean<k0*Mean){
					segma=0.0;
					for(int m=-M/2;m<=M/2;m++)
						for(int n=-N/2;n<=N/2;n++)
							segma+=((*(lpSrc+ lLineBytes* m+n)-mean)*
							(*(lpSrc+ lLineBytes*m+n)-mean));
					segma=sqrt(segma/(M*N));
					double dtmp;
					if(segma>=k1*Segma && segma<=k2*Segma)
					{
						dtmp=E*(*lpSrc);
						if(dtmp>255) dtmp=255;
						*lpDst=(unsigned char)dtmp;//
					}
				}
			}

		}

	}



	CString str=pDoc->GetTitle();

	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"局部增强");

	// 恢复光标
	EndWaitCursor();	
	// 释放内存
	delete []lpNewDIBBits;

}

void CImageProcessView::OnUpdateHistgramLocal(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnPreprocessLaplacesharpen()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	BeginWaitCursor();



	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);


	int pixel[8];
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;			
			if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
				pixel[0] = (int)*(lpSrc+lLineBytes-1);
				pixel[1] = (int)*(lpSrc+lLineBytes);
				pixel[2] = (int)*(lpSrc+lLineBytes+1);
				pixel[3] = (int)*(lpSrc+1);
				pixel[4] = (int)*(lpSrc - lLineBytes+1);
				pixel[5] = (int)*(lpSrc - lLineBytes);
				pixel[6] = (int)*(lpSrc - lLineBytes-1);
				pixel[7] = (int)*(lpSrc-1);
				int Tmp=0;
				for(int k=0;k<8;k++)
					Tmp+=pixel[k];
				Tmp-=8*((int)*lpSrc);
				if(Tmp>0) Tmp=*lpSrc+Tmp;
				else Tmp=*lpSrc-Tmp;
				if(Tmp>255) Tmp=255;
				*lpDst=(unsigned char)Tmp;

			}
		}
	}

	CString str=pDoc->GetTitle();

	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"Laplace 锐化");

	// 恢复光标
	EndWaitCursor();	
	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdatePreprocessLaplacesharpen(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnSmoothMeanfilter()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();
	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);


	const int M=5;//odd
	const int N=5;//odd

	MeanFilter(M,N);

	CString str=pDoc->GetTitle();
	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str+"--+均值滤波");//display orignal image

	//get img back
	pDoc->SetTitle(str);
	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);

	delete []lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	

}

void CImageProcessView::OnUpdateSmoothMeanfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//不计算图像边界(选择的区域边界要计算!)
//利用两次卷积合成,递归完成卷积
void CImageProcessView::MeanFilter(int M,int N)
{
	CImageProcessDoc* pDoc = GetDocument();

	int*	lpNewDIBBits;
	lpNewDIBBits=new int [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;

	int*	lpDst;

	int v;
	int half_M=M/2;
	int half_N=N/2;
	//若选择区域,顶、低部需要多算几行
	for (int i = max(pDoc->StartPoint.y-half_N,0); i <=min(pDoc->EndPoint.y+half_N,lHeight-1); i ++){	
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +max(pDoc->StartPoint.x,half_M);//get first point
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+max(pDoc->StartPoint.x,half_M);

		v=0;
		for(int k=-half_M;k<=half_M;k++){//add
			v+=*(lpSrc+k);
		}
		*lpDst=v;

		for (int j =max(pDoc->StartPoint.x,half_M)+1; j <min(pDoc->EndPoint.x,lWidth-half_M); j ++){

			lpSrc++;
			lpDst++;
			v+=(*(lpSrc+half_M)-*(lpSrc-half_M-1));
			*lpDst=v;

		}
	}	

	int size=M*N;
	for (int j =max(pDoc->StartPoint.x,half_M); j <min(pDoc->EndPoint.x,lWidth-half_M); j ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-max(pDoc->StartPoint.y,half_N)) + j;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - max(pDoc->StartPoint.y,half_N))+ j;
		v=0;
		for(int k=-half_N;k<=half_N;k++)
			v+=*(lpDst+k*lLineBytes);
		*lpSrc=(BYTE)(v/size);
		for (int i = max(pDoc->StartPoint.y,half_N)+1; i <min(pDoc->EndPoint.y,lHeight-half_N); i ++){	
			lpDst-=lLineBytes;
			v+=(*(lpDst-(half_N)*lLineBytes)-*(lpDst+(half_N+1)*lLineBytes));
			lpSrc-=lLineBytes;
			*lpSrc=(BYTE)(v/size);
		}

	}	

	// 释放内存
	delete []lpNewDIBBits;


}

void CImageProcessView::OnSmoothGaussfilter()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();


	BeginWaitCursor();
	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);



	const int M=7;//odd
	const int N=7;//odd
	const double Sigma=1.414;
	GaussFilter(M,N,Sigma);

	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str+"--+高斯滤波");//display orignal image


	//get img back
	pDoc->SetTitle(str);
	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);

	delete []lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSmoothGaussfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//利用两次卷积合成,M!=N 模板计算(方差也不同?不考虑)
void CImageProcessView::GaussFilter(int M,int N,double Sigma)
{
	CImageProcessDoc* pDoc = GetDocument();

	int*	lpNewDIBBits;
	lpNewDIBBits=new int [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;

	int*	lpDst;

	int* model;


	if(Sigma<0.3) Sigma=0.3;
	if(M<3) M=3;
	if(N<3) N=3;
	N=M;

	model=new int [M];

	int half_M=M/2;
	int half_N=N/2;

	for(int i=-half_M;i<=half_M;i++){
		double G=exp(-(i*i)/(2.0*Sigma*Sigma))/ (sqrt(2 * Pi) * Sigma);
		model[i+half_M]=(int)(G*100+0.5);
	}

	int num=0;
	for(int i=0;i<M;i++)
		num+=model[i];

	num*=num;

	for (int i = max(pDoc->StartPoint.y-half_N,0); i <=min(pDoc->EndPoint.y+half_N,lHeight-1); i ++){	
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +max(pDoc->StartPoint.x,half_M);//get first point
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+max(pDoc->StartPoint.x,half_M);
		for (int j =max(pDoc->StartPoint.x,half_M); j <min(pDoc->EndPoint.x,lWidth-half_M); j ++){

			int v=0;
			for(int k=-half_M;k<=half_M;k++){//add
				v+=(*(lpSrc+k)*model[k+half_M]);
			}
			*lpDst=v;

			lpSrc++;
			lpDst++;

		}
	}	

	for (int j =max(pDoc->StartPoint.x,half_M); j <min(pDoc->EndPoint.x,lWidth-half_M); j ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-max(pDoc->StartPoint.y,half_N)) + j;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - max(pDoc->StartPoint.y,half_N))+ j;
		for (int i = max(pDoc->StartPoint.y,half_N); i <min(pDoc->EndPoint.y,lHeight-half_N); i ++){	
			int v=0;
			for(int k=-half_N;k<=half_N;k++)
				v+=(*(lpDst+k*lLineBytes)*model[k+half_N]);
			*lpSrc=(BYTE)(v/num);
			lpDst-=lLineBytes;
			lpSrc-=lLineBytes;

		}

	}	

	// 释放内存
	delete []lpNewDIBBits;
	delete []model;


}

void CImageProcessView::GaussFilter(double* pData,int M,int N,double Sigma)
{
	CImageProcessDoc* pDoc = GetDocument();

	double*	lpNewDIBBits;
	lpNewDIBBits=new double [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	memcpy(lpNewDIBBits,pData,lLineBytes*lHeight*sizeof(double));

	double*	lpSrc;

	double*	lpDst;

	double* model;


	if(Sigma<0.3) Sigma=0.3;
	if(M<3) M=3;
	if(N<3) N=3;
	N=M;

	model=new double [M];

	int half_M=M/2;
	int half_N=N/2;

	for(int i=-half_M;i<=half_M;i++){
		double G=exp(-(i*i)/(2.0*Sigma*Sigma))/ (sqrt(2 * Pi) * Sigma);
		model[i+half_M]=G;
	}



	for (int i = max(pDoc->StartPoint.y-half_N,0); i <=min(pDoc->EndPoint.y+half_N,lHeight-1); i ++){	
		lpSrc =pData  +  lLineBytes* (lHeight-1-i) +max(pDoc->StartPoint.x,half_M);//get first point
		lpDst =lpNewDIBBits+ lLineBytes * (lHeight - 1 - i)+max(pDoc->StartPoint.x,half_M);
		for (int j =max(pDoc->StartPoint.x,half_M); j <min(pDoc->EndPoint.x,lWidth-half_M); j ++){

			double v=0;
			for(int k=-half_M;k<=half_M;k++){//add
				v+=(*(lpSrc+k)*model[k+half_M]);
			}
			*lpDst=v;

			lpSrc++;
			lpDst++;

		}
	}	


	for (int j =max(pDoc->StartPoint.x,half_M); j <min(pDoc->EndPoint.x,lWidth-half_M); j ++){
		lpSrc = pData +  lLineBytes* (lHeight-1-max(pDoc->StartPoint.y,half_N)) + j;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - max(pDoc->StartPoint.y,half_N))+ j;
		for (int i = max(pDoc->StartPoint.y,half_N); i <min(pDoc->EndPoint.y,lHeight-half_N); i ++){	
			double v=0;
			for(int k=-half_N;k<=half_N;k++)
				v+=(*(lpDst+k*lLineBytes)*model[k+half_N]);
			*lpSrc=v;
			lpDst-=lLineBytes;
			lpSrc-=lLineBytes;

		}

	}	



	// 释放内存
	delete []lpNewDIBBits;
	delete []model;


}

void CImageProcessView::OnSmoothMedianfilter()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();
	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);


	CDemoTimer exeTimer;
	exeTimer.Reset();

	const int M=3;//odd
	const int N=3;//odd
	

	MedianFilter(M,N);


	TRACE("\nUsed Time is %.3f ms\n",exeTimer.GetTime(false)*1000);



	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str+"--+中值滤波");//display orignal image


	//get img back
	pDoc->SetTitle(str);
	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);

	delete []lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSmoothMedianfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}
void CImageProcessView::MedianFilter(int M,int N)
{
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);



	//unsigned char *v=new unsigned char[M*N];//[N*M];//line N Column M not rect (int err) 
	vector<unsigned char> v(M*N,0);
	const int Th=(M*N)/2;//Mid Pos

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;

		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			lpDst++;
			if(i>=M/2 && i<lHeight-M/2 && j>=N/2 && j<lWidth-N/2){
				//Get M*N data to v[]
				int vSize=0;
				for(int m=-M/2;m<=M/2;m++)
					for(int n=-N/2;n<=N/2;n++)
					{	v[vSize]=*(lpSrc+lLineBytes*m+n);
				vSize++;}

				//sort v[]
				for(int m=0;m<M*N-1;m++)
					for(int n=m+1;n<M*N;n++)
					{
						if(v[m]>v[n]){
							//swap
							BYTE tmp=v[m];
							v[m]=v[n];
							v[n]=tmp;
						}
					}

					*(lpDst)=(unsigned char)v[Th];

			}
		}
	}


	// 释放内存
	delete []lpNewDIBBits;
	//delete []v;

}

//邻域内求与其它点距离最短的色点替代该点
void CImageProcessView::OnSmoothColorfilter()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	// 更改光标形状
	BeginWaitCursor();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lHeight * lLineBytes];
	if (lpNewDIBBits == NULL)
		return ;

	memcpy(lpNewDIBBits,pDoc->m_pDib->m_lpImage,lHeight * lLineBytes);


	// 针对图像每行进行操作
	for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){	

			// 指向源DIB第i行,第j个象素的指针
			lpSrc =lpNewDIBBits  + lLineBytes*(lHeight-1-i)+ j*3;
			double d;
			double mind=10000;
			int mm=0;
			int mn=0;
			for(int m=-1;m<=1;m++)
				for(int n=-1;n<=1;n++)
				{
					d=0.0;
					unsigned char*	lpDst1=lpSrc+lLineBytes*n+m*3;
					for(int s=-1;s<=1;s++)
						for(int t=-1;t<=1;t++)
						{   unsigned char*	lpDst2=lpSrc+lLineBytes*t+s*3;
					double dtmp=(double)((*(lpDst1)-*(lpDst2))*(*(lpDst1)-*(lpDst2))+//^ is't Pow(x,y)
						(*(lpDst1+1)-*(lpDst2+1))*(*(lpDst1+1)-*(lpDst2+1))+
						(*(lpDst1+2)-*(lpDst2+2))*(*(lpDst1+2)-*(lpDst2+2)));
					d+=sqrt(dtmp);
					}
					if(d<mind){
						mind=d;
						mm=m;mn=n;
					}
				}

				lpSrc=lpSrc+ lLineBytes*mn+ mm*3;


				lpDst =pDoc->m_pDib->m_lpImage+ lLineBytes *(lHeight-1-i) + j*3;
				*lpDst=*lpSrc;*(lpDst+1)=*(lpSrc+1);*(lpDst+2)=*(lpSrc+2);


		}

	}


	DisplayNewImg(lpNewDIBBits,(lWidth+3)/4*4,lHeight,"原图",true);//display orignal image

	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"--Color Filtering");


	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
	delete []lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSmoothColorfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==24)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnFrequencydomainFft()
{
	// TODO: Add your command handler code here
	//CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];
	TD[0]=complex<double>(1.0,2.0);;


	DoFFT( TD,  FD, w,h);


	DisplayFw(FD,w, h,0.6,"|F(u,v)|");

	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete []TD;
	delete []FD;

}
void CImageProcessView::DisplayFw(complex<double> * FD, int w, int h,double c,CString title)
{
	//显示 F(jw)
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [w*h];
	unsigned char*	lpSrc;

	if (lpNewDIBBits == NULL)
		return ;

	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			// 计算频谱

			double dTemp =c*log(1+ sqrt((double)FD[i *w  + j].real() * FD[i *w  + j].real() + 
				FD[i *w  + j].imag() * FD[i *w  + j].imag()));// c ln(1+r)  

			dTemp=exp(dTemp*log(2.0));//log | log10
			if(dTemp>255) 
				dTemp=255;
			//freq
			lpSrc = lpNewDIBBits + w * (h - 1 - i) + j;
			* (lpSrc) = (BYTE)(dTemp);
		}
	}

	DisplayNewImg(lpNewDIBBits,w,h,title);
	delete []lpNewDIBBits;

}
void CImageProcessView::OnUpdateFrequencydomainFft(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);

}

CPoint CImageProcessView::FrequencydomainSelectarea(){
	//获取付立叶变换的宽度和高度(2的整数次方)
	CImageProcessDoc* pDoc = GetDocument();
	int	w;
	int	h;

	int wp=int(log((double) pDoc->EndPoint.x-pDoc->StartPoint.x+1)/log(2.0));
	int hp=int(log((double) pDoc->EndPoint.y-pDoc->StartPoint.y+1)/log(2.0));

	w=(int)pow(2.0,wp);
	h=(int)pow(2.0,hp);


	if((pDoc->EndPoint.x-pDoc->StartPoint.x+1==lWidth) && (pDoc->EndPoint.y-pDoc->StartPoint.y+1==lHeight))
	{  //整幅图像处理
		if(w<lWidth) w*=2;//add 0
		if(h<lHeight) h*=2;
	}
	else{

		if(w<256 && w<(pDoc->EndPoint.x-pDoc->StartPoint.x+1)){
			w *= 2;

		}

		if(h<256 && h<(pDoc->EndPoint.y-pDoc->StartPoint.y+1)){
			h *= 2;
		}
		//若非取全区域,修正区域使满足w、h整数次方
		int dy=(pDoc->EndPoint.y-pDoc->StartPoint.y+1-h)/2-1;
		pDoc->StartPoint.y+=dy;
		if(pDoc->StartPoint.y<0) pDoc->StartPoint.y=0;
		pDoc->EndPoint.y=pDoc->StartPoint.y+h-1;

		int dx=(pDoc->EndPoint.x-pDoc->StartPoint.x+1-w)/2;
		pDoc->StartPoint.x+=dx;
		//若不在区域内,补0
		if(pDoc->StartPoint.x<0) pDoc->StartPoint.x=0;
		pDoc->EndPoint.x=pDoc->StartPoint.x+w-1;
		if(pDoc->EndPoint.x>lWidth-1){
			pDoc->EndPoint.x=lWidth-1;
			pDoc->StartPoint.x=max(0,lWidth-1-w);
		}
		if(pDoc->EndPoint.y>lHeight-1){
			pDoc->EndPoint.y=lHeight-1;
			pDoc->StartPoint.y=max(0,lHeight-1-h);
		}
	}
	//display select area change
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	return(CPoint(w,h));
}

void CImageProcessView::DoFFT(complex<double> * TD, complex<double> * FD, int w, int h)
{

	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	// 行
	for(int i = 0; i < h; i++)
	{
		// 列
		for(int j = 0; j < w; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			if(i+pDoc->StartPoint.y<lHeight && pDoc->StartPoint.x+j<lWidth)
			{
				lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + pDoc->StartPoint.x+j;

				// 给时域赋值
				TD[j + w * i] = complex<double>(*(lpSrc), 0);//w*h
			}else{
				TD[j + w * i] = complex<double>(0,0);
			}
		}
	}
	FFT2(TD,FD, w, h);
}
void CImageProcessView::FFT2(complex<double> * TD, complex<double> * FD, int w,int h)
{
	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));

	//1: move to center
	for(int y=0; y<h; y++)
		for(int x=0; x<w; x++)
			if((x+y)%2) TD[y*w + x]=-TD[y*w + x];
	//2:FFT
	for(int i = 0; i < h; i++)
	{
		// 对y方向进行快速付立叶变换
		FFT(&TD[w * i], &FD[w * i], wp);//w
	}

	// 保存变换结果
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			TD[i + h * j] = FD[j + w * i];//转置
		}
	}

	for(int i = 0; i < w; i++)
	{
		// 对x方向进行快速付立叶变换
		FFT(&TD[i * h], &FD[i * h], hp);//h
	}

	//再转置还原
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			TD[j + w * i] = FD[i + h * j];//转置
		}
	}
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i] = TD[j + w * i];
		}
	}
	//FD=TD;  err!!

}
void CImageProcessView::FFT(complex<double> * TD, complex<double> * FD, int r)
{
	// 付立叶变换点数
	LONG	count;
	const double PI=3.14159;

	// 中间变量
	int		bfsize,p;

	// 角度
	double	angle;

	complex<double> *W,*X1,*X2,*X;

	// 计算付立叶变换点数
	count = 1 << r;

	// 分配运算所需存储器
	W  = new complex<double>[count / 2];
	X1 = new complex<double>[count];
	X2 = new complex<double>[count];

	// 计算加权系数
	for(int i = 0; i < count / 2; i++)
	{
		angle = -i * PI * 2 / count;
		W[i] = complex<double> (cos(angle), sin(angle));
	}

	// 将时域点写入X1
	memcpy(X1, TD, sizeof(complex<double>) * count);

	// 采用蝶形算法进行快速付立叶变换
	for(int k = 0; k < r; k++)
	{
		for(int j = 0; j < 1 << k; j++)
		{
			bfsize = 1 << (r-k);
			for(int i = 0; i < bfsize / 2; i++)
			{
				p = j * bfsize;
				X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2];
				X2[i + p + bfsize / 2] = (X1[i + p] - X1[i + p + bfsize / 2]) * W[i * (1<<k)];
			}
		}
		X  = X1;
		X1 = X2;
		X2 = X;
	}

	// 重新排序
	for(int j = 0; j < count; j++)
	{
		p = 0;
		for(int i = 0; i < r; i++)
		{
			if (j&(1<<i))
			{
				p+=1<<(r-i-1);
			}
		}
		FD[j]=X1[p];
	}

	// 释放内存
	delete [] W;
	delete [] X1;
	delete [] X2;
}
void CImageProcessView::IFFT(complex<double> * FD, complex<double> * TD, int r)
{// 付立叶变换点数
	LONG	count;


	complex<double> *X;

	// 计算付立叶变换点数
	count = 1 << r;

	// 分配运算所需存储器
	X = new complex<double>[count];

	// 将频域点写入X
	memcpy(X, FD, sizeof(complex<double>) * count);

	// 求共轭
	for(int i = 0; i < count; i++)
	{
		X[i] = complex<double> (X[i].real(), -X[i].imag());
	}

	// 调用快速付立叶变换
	FFT(X, TD, r);

	// 求时域点的共轭
	for(int i = 0; i < count; i++)
	{
		TD[i] = complex<double> (TD[i].real() / count, -TD[i].imag() / count);
	}

	// 释放内存
	delete [] X;

}

void CImageProcessView::OnButterworthLowfilter()
{
	// TODO: Add your command handler code here
	//CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	//DisplayFw(FD,w, h,0.6,"|F(u,v)|");

	//filter
	const double D0=30;
	for(int y=0; y<h; y++)
	{
		for(int x=0; x<w; x++)
		{

			double	D = (double)((y-h/2)*(y-h/2)+(x-w/2)*(x-w/2)) ; 

			D = D / (D0 * D0);//(D/D0)^2

			//ButterWorth低通滤波
			double H = 1/(1+D*D);//n=2

			FD[x + y*w]=complex<double>(FD[x + y*w].real()*H,FD[x + y*w].imag()*H);//h*w

		}
	}

	//DisplayFw(FD,w, h,0.6,"|F(u,v)H(u,v)|");

	DoIFFT( TD,  FD, w,h,"ButtWorth低通",CPoint(0,0));



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
}

void CImageProcessView::OnButterworthHighfilter()
{
	// TODO: Add your command handler code here
	//CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	//filter
	const double D0=30;
	for(int y=0; y<h; y++)
	{
		for(int x=0; x<w; x++)
		{

			double	D = (double)((y-h/2)*(y-h/2)+(x-w/2)*(x-w/2)) ; 

			D = (D0 * D0)/D;//(D0/D)^2
			if(D<0.00001) D=0.00001;
			//ButterWorth高通滤波
			double H = 1/(1+D*D);//n=2

			FD[x + y*w]=complex<double>(FD[x + y*w].real()*H,FD[x + y*w].imag()*H);//h*w

		}
	}


	DoIFFT( TD,  FD, w,h,"ButtWorth低通",CPoint(0,0));



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
}

void CImageProcessView::OnUpdateButterworthLowfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnUpdateButterworthHighfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::DoIFFT(complex<double>* TD, complex<double>* FD, int w, int h,CString title,CPoint startP)//del 0,0-startP-1 
{
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));

	for(int i = 0; i < h; i++)
	{
		// 对x方向进行快速付立叶变换
		IFFT( &FD[i * w],&TD[i * w], wp);
	}

	// 保存变换结果
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[i + h * j] = TD[j + w * i];//w*h 

		}
	}
	for(int i = 0; i < w; i++)
	{
		// 对y方向进行快速付立叶变换
		IFFT(&FD[h * i],&TD[h * i],hp);
	}


	//TD hxw //转置

	double dTemp;
	double dmax=0.0;
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			dTemp=TD[j * h + i].real();
			//move back
			if((i+j)%2) dTemp=-dTemp;
			if(dTemp>dmax) dmax=dTemp;
		}
	}
	if(dmax<255) dmax=255;//no make bright 
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			dTemp=TD[j * h + i].real();
			//move back
			if((i+j)%2) dTemp=-dTemp;
			dTemp=dTemp/dmax*255.0;
			if (dTemp<0)
				dTemp=0;

			if(j<lWidth-pDoc->StartPoint.x && i<lHeight-pDoc->StartPoint.y)
			{
				lpSrc =lpNewDIBBits + lLineBytes* (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

				// 更新源图像
				if(j<startP.x || i<startP.y)
					*(lpSrc) =0;//错误处置0
				else
					*(lpSrc) = (BYTE)(dTemp);
			}
		}
	}

	CString str=pDoc->GetTitle();
	str+=title;

	DisplayNewImg(lpNewDIBBits, lLineBytes,lHeight,str);
	delete []lpNewDIBBits;
	return ;
}

void CImageProcessView::OnFrequencydomainHomomorphicfilter()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);


	//process
	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	//1 lnf(x,y)
	unsigned char*	lpSrc;
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			if(i+pDoc->StartPoint.y<lHeight && pDoc->StartPoint.x+j<lWidth)
			{
				lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + pDoc->StartPoint.x+j;

				// 给时域赋值
				TD[j + w * i] = complex<double>(log((double)(max(*lpSrc,1))), 0);//w*h
			}else{
				TD[j + w * i] = complex<double>(0,0);
			}
		}
	}


	//2:FFT

	//move to center
	for(int y=0; y<h; y++)
		for(int x=0; x<w; x++)
			if((x+y)%2) TD[y*w + x]=-TD[y*w + x];

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));

	for(int i = 0; i < h; i++)
	{
		// 对y方向进行快速付立叶变换
		FFT(&TD[w * i], &FD[w * i], wp);//w
	}

	// 保存变换结果
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			TD[i + h * j] = FD[j + w * i];//h*w
		}
	}

	for(int i = 0; i < w; i++)
	{
		// 对x方向进行快速付立叶变换
		FFT(&TD[i * h], &FD[i * h], hp);//h
	}

	//3. filter
	const double D0=5;
	const double rH=2.0;
	const double rL=.5;
	const double c=1.0;

	for(int y=0; y<h; y++)
	{
		for(int x=0; x<w; x++)
		{

			double	D = (double)((y-h/2)*(y-h/2)+(x-w/2)*(x-w/2)) ; 

			D = D/(D0 * D0);
			double H =(rH-rL)*(1-exp(-c*D))+rL;
			if(D==0.0) H=1.0;//get bright
			FD[y + x*h]=complex<double>(FD[y + x*h].real()*H,FD[y + x*h].imag()*H);//h*w

		}
	}

	//4.IFFT
	for(int i = 0; i < w; i++)
	{
		// 对x方向进行快速付立叶变换
		IFFT( &FD[i * h],&TD[i * h], hp);
	}

	// 保存变换结果
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i] = TD[i + h * j];//w*h 

		}
	}
	for(int i = 0; i < h; i++)
	{
		// 对y方向进行快速付立叶变换
		IFFT(&FD[w * i],&TD[w * i],wp);
	}

	//5.exp

	double dTemp;
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			dTemp=TD[i * w + j].real();
			//move back
			if((i+j)%2) dTemp=-dTemp;

			dTemp=exp(dTemp);

			if (dTemp > 255)
				dTemp = 255;

			if(j<lWidth-pDoc->StartPoint.x && i<lHeight-pDoc->StartPoint.y)
			{
				lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

				// 更新源图像
				* (lpSrc) = (BYTE)dTemp;
			}
		}
	}


	CString str=pDoc->GetTitle();
	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str+"--+同态滤波");//display orignal image


	//get img back
	pDoc->SetTitle(str);
	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);

	delete [] lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
}

void CImageProcessView::OnUpdateFrequencydomainHomomorphicfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnFileGetmodal()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	m_ModelWidth=pDoc->EndPoint.x-pDoc->StartPoint.x+1;
	m_ModelWidth=(m_ModelWidth+3)/4*4;
	m_ModelHeight=pDoc->EndPoint.y- pDoc->StartPoint.y+1;

	if(m_pModelData)
		delete []m_pModelData;

	m_pModelData=new unsigned char [m_ModelWidth*m_ModelHeight];

	unsigned char*	lpSrc;
	unsigned char* lpDst;
	lpDst=m_pModelData;;

	for (int i = 0; i <m_ModelHeight; i ++)
	{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i-pDoc->StartPoint.y) + pDoc->StartPoint.x-1;
	for (int j =0; j <m_ModelWidth; j ++)
	{
		lpSrc++;
		*lpDst=*lpSrc;
		lpDst++;
	}
	}
	//DisplayNewImg(m_pModelData,m_ModelWidth,m_ModelHeight,"Moda");

}

void CImageProcessView::OnUpdateFileGetmodal(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnSpatialdomainImage()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	for (int i = pDoc->StartPoint.y; i <=min(pDoc->EndPoint.y,m_ModelHeight-1+pDoc->StartPoint.y); i ++){
		lpSrc = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst = m_pModelData+ m_ModelWidth * (i-pDoc->StartPoint.y)-1;
		for (int j =pDoc->StartPoint.x; j <=min(pDoc->EndPoint.x,m_ModelWidth-1+pDoc->StartPoint.x); j ++){
			lpSrc++;lpDst++;			
			int Tmp=128+*(lpSrc)-*lpDst;
			if(Tmp>255) Tmp=255;
			else if(Tmp<0)Tmp=0;
			*lpSrc=(unsigned char)Tmp;
		}
	}

	CString str=pDoc->GetTitle();

	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"-Moda");

	// 恢复光标
	EndWaitCursor();	
	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdateSpatialdomainImage(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_pModelData)
				bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnConvolutionMean()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	complex<double> *HTD = new complex<double>[w * h];
	complex<double> *HFD = new complex<double>[w * h];

	for(int i = 0; i < h; i++)
		for(int j = 0; j < w; j++)
			HTD[j + w * i]=0.0;

	for(int i = 0; i < 3; i++)
		for(int j = 0; j < 3; j++)
			HTD[j + w * i]=1.0/9;

	FFT2( HTD, HFD, w,h);	

	DisplayFw(HFD,w, h,20.0,"均值滤波|H(u,v)|");

	//proc
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i]*=HFD[j + w * i];
		}
	}


	DoIFFT( TD,  FD, w,h,"频域均值滤波",CPoint(2,2));//0,1 err



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
	delete [] HTD;
	delete [] HFD;
}

void CImageProcessView::OnUpdateConvolutionMean(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnConvolutionGauss()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	complex<double> *HTD = new complex<double>[w * h];
	complex<double> *HFD = new complex<double>[w * h];

	for(int i = 0; i < h; i++)
		for(int j = 0; j < w; j++)
			HTD[j + w * i]=0.0;

	//Gauss 5*5
	HTD[2 + w * 2]=12.0/76.0;
	HTD[1 + w * 2]=HTD[3 + w * 2]=HTD[2 + w * 1]=HTD[2 + w * 3]=7.0/76.0;
	HTD[1 + w * 1]=HTD[1 + w * 3]=HTD[3 + w * 1]=HTD[3 + w * 3]=5.0/76.0;
	HTD[0 + w * 2]=HTD[2 + w * 0]=HTD[4 + w * 2]=HTD[2 + w * 4]=2.0/76.0;
	HTD[0 + w * 1]=HTD[1 + w * 0]=HTD[0 + w * 3]=HTD[3 + w * 0]=1.0/76.0;
	HTD[1 + w * 4]=HTD[4 + w * 1]=HTD[4 + w * 3]=HTD[3 + w * 4]=1.0/76.0;

	FFT2( HTD, HFD, w,h);	

	DisplayFw(HFD,w, h,20.0,"高斯滤波|H(u,v)|");

	//proc
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i] *=HFD[j + w * i];
		}
	}


	DoIFFT( TD,  FD, w,h,"频域高斯滤波",CPoint(4,4));



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
	delete [] HTD;
	delete [] HFD;
}

void CImageProcessView::OnUpdateConvolutionGauss(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnConvolutionLaplace()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	complex<double> *HTD = new complex<double>[w * h];
	complex<double> *HFD = new complex<double>[w * h];

	for(int i = 0; i < h; i++)
		for(int j = 0; j < w; j++)
			HTD[j + w * i]=0.0;

	//Laplace
	HTD[1 + w * 1]=4.0;
	HTD[1 + w * 0]=HTD[0 + w * 1]=HTD[2 + w * 1]=HTD[1 + w * 2]=-1.0;

	FFT2( HTD, HFD, w,h);	

	DisplayFw(HFD,w, h,20.0,"Laplace滤波|H(u,v)|");

	//proc
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i]*=HFD[j + w * i];
		}
	}


	DoIFFT( TD,  FD, w,h,"频域Laplace滤波",CPoint(2,2));//0,1 err



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
	delete [] HTD;
	delete [] HFD;
}

void CImageProcessView::OnUpdateConvolutionLaplace(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnConvolutionMarr()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	complex<double> *HTD = new complex<double>[w * h];
	complex<double> *HFD = new complex<double>[w * h];

	for(int i = 0; i < h; i++)
		for(int j = 0; j < w; j++)
			HTD[j + w * i]=0.0;

	//Marr 5*5
	HTD[2 + w * 2]=24.0;
	HTD[1 + w * 2]=HTD[3 + w * 2]=HTD[2 + w * 1]=HTD[2 + w * 3]=8.0;
	HTD[1 + w * 1]=HTD[1 + w * 3]=HTD[3 + w * 1]=HTD[3 + w * 3]=0.0;
	HTD[0 + w * 1]=HTD[0 + w * 2]=HTD[0 + w * 3]=-4.0;
	HTD[1 + w * 0]=HTD[2 + w * 0]=HTD[3 + w * 0]=-4.0;
	HTD[4 + w * 1]=HTD[4 + w * 2]=HTD[4 + w * 3]=-4.0;
	HTD[1 + w * 4]=HTD[2 + w * 4]=HTD[3 + w * 4]=-4.0;
	HTD[0 + w * 0]=HTD[4 + w * 0]=HTD[0 + w * 4]=HTD[4 + w * 4]=-2.0;

	FFT2( HTD, HFD, w,h);	

	DisplayFw(HFD,w, h,10.0,"Marr滤波|H(u,v)|");

	//proc
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i] *=HFD[j + w * i];
		}
	}


	DoIFFT( TD,  FD, w,h,"频域Marr滤波",CPoint(4,4));



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
	delete [] HTD;
	delete [] HFD;
}

void CImageProcessView::OnUpdateConvolutionMarr(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnConvolutionCorrelation()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	complex<double> *HTD = new complex<double>[w * h];
	complex<double> *HFD = new complex<double>[w * h];

	unsigned char *lpSrc;
	for(int i = 0; i < h; i++){
		for(int j = 0; j < w; j++){
			if(i<m_ModelHeight && j<m_ModelWidth)
			{
				lpSrc = m_pModelData + m_ModelWidth * i + j;

				// 给时域赋值
				HTD[j + w * i] = complex<double>(*(lpSrc), 0);//
			}else{
				HTD[j + w * i] = complex<double>(0,0);
			}
		}
	}

	FFT2( HTD, HFD, w,h);	

	//DisplayFw(FD,w, h,.6,"|F(u,v)|");
	//DisplayFw(HFD,w, h,.6,"|H(u,v)|");
	//DoIFFT( TD,  FD, w,h,"F(x,y)",CPoint(0,0));

	//proc
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{   
			HFD[j + w * i]=complex<double>(HFD[j + w * i].real(), -HFD[j + w * i].imag());//共轭
			FD[j + w * i]*=HFD[j + w * i];//FD[j + w * i]=FD[j + w * i]*HFD[j + w * i] ; 错!
			//	FD[j + w * i]=complex<double>(FD[j + w * i].real(), -FD[j + w * i].imag());//共轭
			//	FD[j + w * i]*=HFD[j + w * i];//FD[j + w * i]=FD[j + w * i]*HFD[j + w * i] ; 错!
		}
	}

	//DisplayFw(FD,w, h,.6,"|F*(u,v)H(u,v)|");

	//DoIFFT( HTD,  HFD, w,h,"h(x,y)",CPoint(0,0));

	DoIFFT( TD,  FD, w,h,"频域相关运算",CPoint(m_ModelWidth/2,m_ModelHeight/2));



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
	delete [] HTD;
	delete [] HFD;
}

void CImageProcessView::OnUpdateConvolutionCorrelation(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_pModelData)
				bAvail=true;

	pCmdUI->Enable(bAvail);
}

//利用噪声方差,判断局部方差,噪声处进行平滑,边缘处不处理
void CImageProcessView::OnAdaptiveNoisereduction()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();
	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);


	const int M=7;//odd
	const int N=7;//odd

	double mean;
	double Dev2;
	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	const double Dev_Noise2=1000.0;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;

		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			lpDst++;
			if(i>=M/2 && i<lHeight-M/2 && j>=N/2 && j<lWidth-N/2){
				//Get M*N mean
				mean=0.0;
				for(int m=-M/2;m<=M/2;m++)
					for(int n=-N/2;n<=N/2;n++)
						mean+=*(lpSrc+ lLineBytes* m+n);

				mean/=(M*N);
				Dev2=0.0;
				for(int m=-M/2;m<=M/2;m++)
					for(int n=-N/2;n<=N/2;n++)
						Dev2+=((*(lpSrc+ lLineBytes* m+n)-mean)*
						(*(lpSrc+ lLineBytes*m+n)-mean));
				Dev2/=(M*N);
				double dtmp;
				if(Dev_Noise2>Dev2)
					dtmp=mean;
				else
					dtmp=*lpSrc-Dev_Noise2/Dev2*(*lpSrc-mean);
				if(dtmp<0) {
					dtmp=0;//can get min adjust 
				}
				else if(dtmp>255) dtmp=255;
				*lpDst=(unsigned char)dtmp;//

			}
		}
	}

	CString str=pDoc->GetTitle();
	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"--+自适应局部噪声消除滤波");//


	delete [] lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateAdaptiveNoisereduction(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//判断某点是否为脉冲,若是,其中值是否为脉冲,y,扩大(小于最大值)邻域使其非脉冲
void CImageProcessView::OnAdaptiveMedian()
{
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	const int Mmax=7;//max
	const int Nmax=7;//odd
	const int Mmin=5;//max
	const int Nmin=5;//odd
	const int PluseL=20;
	const int PluseH=220;



	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);



	unsigned char *v=new unsigned char[Mmax*Nmax];//[N*M];//line N Column M not rect (int err) 

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;

		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			lpDst++;
			if(*lpSrc>PluseL && *lpSrc<PluseH) continue;
			int M=Mmin;
			int N=Nmin;
			bool bOver=false;
			while(!bOver){

				//Get M*N data to v[]
				int vSize=0;
				for(int m=-M/2;m<=M/2;m++){
					for(int n=-N/2;n<=N/2;n++){
						if(i-m>=0 && i-m<lHeight && j+n>=0 && j+n<lWidth)
						{	
							v[vSize]=*(lpSrc+lLineBytes*m+n);
							vSize++;
						}
					}
				}

				//sort v[]
				for(int m=0;m<vSize-1;m++){
					for(int n=m+1;n<vSize;n++)
						if(v[m]>v[n]){
							//swap
							BYTE tmp=v[m];
							v[m]=v[n];
							v[n]=tmp;
						}
				}
				int Th=vSize/2;
				if(v[Th]>max(v[0],PluseL) && v[Th]<min(v[vSize-1],PluseH)){
					*lpDst=v[Th];
					bOver=true;
				}
				else
				{//need change M,N bigger
					M+=2;
					N+=2;
					if(M>Mmax)
					{
						bOver=true;
						*lpDst=v[Th];
					}


				}
			}
		}
	}



	CString str=pDoc->GetTitle();
	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"--+自适应中值滤波");//

	// 释放内存
	delete []lpNewDIBBits;
	delete []v;


	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateAdaptiveMedian(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}


void CImageProcessView::OnFrequencydomainNotchpassfilter()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	//DisplayFw(FD,w, h,0.6,"|F(u,v)|");

	//filter
	//去除水平扫描线
	//	const double D0=30.0;
	for(int y=0; y<h; y++)
	{
		for(int x=w/2-3; x<=w/2+3; x++)
		{

			if(y<h/2-10 || y>h/2+10)
				FD[x + y*w]=complex<double>(0,0);//h*w

		}
	}

	//DisplayFw(FD,w, h,0.6,"|F(u,v)H(u,v)|");

	DoIFFT( TD,  FD, w,h,"陷波滤波器",CPoint(0,0));



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;

}

void CImageProcessView::OnUpdateFrequencydomainNotchpassfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//不太理想,无书中图像
//提取噪声图像,利用方差最小获取比例参数w,f=g-w*n
void CImageProcessView::OnFrequencydomainOptimumnotchfilter()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	//DisplayFw(FD,w, h,0.6,"|F(u,v)|");

	//filter

	//	const double F0=FD[h/2*w + w/2].real();

	for(int y=0; y<h; y++)
	{
		for(int x=0; x<w; x++)
		{

			//if((y-h/2)*(y-h/2)+(x-w/2)*(x-w/2)<400)
			if(!((y<h/2-20 || y>h/2+20) && (x>w/2-5 && x<w/2+5)))
				FD[x + y*w]=complex<double>(0,0);

		}
	}

	//DisplayFw(FD,w, h,0.6,"|F(u,v)H(u,v)|");

	//IFFT
	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));

	for(int i = 0; i < w; i++)
	{
		// 对x方向进行快速付立叶变换
		IFFT( &FD[i * h],&TD[i * h], hp);
	}

	// 保存变换结果
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i] = TD[i + h * j];//w*h 

		}
	}
	for(int i = 0; i < h; i++)
	{
		// 对y方向进行快速付立叶变换
		IFFT(&FD[w * i],&TD[w * i],wp);
	}
	//再转置还原
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			FD[j + w * i] = TD[i + h * j];//转置
		}
	}
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			TD[j + w * i] = FD[j + w * i];
		}
	}

	//1.noise

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	unsigned char* lpSrc;
	unsigned char* lpSrc1;
	double dTemp;
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			dTemp=TD[i * w + j].real();
			//move back
			if((i+j)%2) dTemp=-dTemp;

			if (dTemp > 255)
				dTemp = 255;
			if (dTemp < 0) dTemp=0;

			if(j<lWidth-pDoc->StartPoint.x && i<lHeight-pDoc->StartPoint.y)
			{
				lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;
				lpSrc1 =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

				// 更新源图像
				* (lpSrc) = (BYTE)dTemp;
			}
		}
	}

	//2.方差最小
	unsigned char*	lpNewDIBBits1;
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits1 == NULL)
		return ;
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits1,lpSrc, lLineBytes * lHeight);

	unsigned char* lpDst;
	const int M=15;
	const int N=15;
	int size=M*N;

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc1 =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpSrc1++;lpDst++;	
			if(i>M/2 && i<lHeight-M/2 && j>N/2 && j<lWidth-N/2){//
				double gAv=0.0,nAv=0.0,gnAv=0.0,n2Av=0.0; 
				for(int m=-M/2;m<=M/2;m++){
					for(int n=-N/2;n<=N/2;n++){
						gAv+=*(lpSrc-lLineBytes*m+n);
						nAv+=*(lpSrc1-lLineBytes*m+n);
						gnAv+=(*(lpSrc-lLineBytes*m+n)*(*(lpSrc1-lLineBytes*m+n)));
						n2Av+=(*(lpSrc1-lLineBytes*m+n)*(*(lpSrc1-lLineBytes*m+n)));
					}
				}

				gAv/=size;
				nAv/=size;
				gnAv/=size;
				n2Av/=size;
				double wi=n2Av-nAv*nAv;
				if(wi>0.001 || wi<-0.001)
					wi=(gnAv-gAv*nAv)/wi;
				else wi=0.0;
				int v=(int)(*lpSrc-wi*(*lpSrc1));
				if(v>255) v=255;
				else if(v<0) v=0;
				*lpDst=(BYTE) v;
			}

		}
	}

	CString str=pDoc->GetTitle();

	DisplayNewImg(lpNewDIBBits1,lLineBytes,lHeight,str+"最佳陷波滤波器");

	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"噪声图像");



	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
	delete [] lpNewDIBBits;
	delete [] lpNewDIBBits1;

}

void CImageProcessView::OnUpdateFrequencydomainOptimumnotchfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//最小均方误差
//已知退化系统函数,添加噪声(假设为白噪声),恢复图像
//K很难调,K=0为逆滤波
void CImageProcessView::OnFrequencydomainWinnerfilter()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	//DisplayFw(FD,w, h,0.6,"|F(u,v)|");

	//filter
	double c1=0.1;
	double c2=0.1;
	double T=1.0;
	double K=.025;//chg
	double minH=0.001;
	for(int y=0; y<h; y++)
	{
		for(int x=0; x<w; x++)
		{

			double	uv=Pi*(c1*(x-w/2)+c2*(y-h/2)) ; 
			complex<double> H ;
			if(uv==0.0)
				H= complex<double>(T,0.0);
			else 
				H= complex<double>(T/(uv)*sin(uv)*cos(uv),-T/(uv)*sin(uv)*sin(uv)); 

			if(H.real()>=0 && H.real()<=minH)
				H= complex<double>(minH,H.imag());

			if(H.imag()>=0 && H.imag()<=minH)
				H= complex<double>(H.real(),minH);

			if(H.real()<0 && H.real()>=-minH)
				H= complex<double>(-minH,H.imag());

			if(H.imag()<0 && H.imag()>=-minH)
				H= complex<double>(H.real(),-minH);

			// |H(u,v)|*|H(u,v)|
			double norm = abs(H);

			// |H(u,v)|*|H(u,v)|/(|H(u,v)|*|H(u,v)|+K)
			double temp  = (norm*norm ) / (norm*norm +K);

			// 求得f(u,v)

			FD[y*w + x]*=temp;
			FD[y*w + x]/=H;



		}
	}


	//DisplayFw(FD,w, h,0.6,"|F(u,v)H(u,v)|");

	DoIFFT( TD,  FD, w,h,"维纳滤波器",CPoint(0,0));

	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
}

void CImageProcessView::OnUpdateFrequencydomainWinnerfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnFrequencydomainLeastsquaresfilter()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	// 分配内存
	complex<double> *TD = new complex<double>[w * h];
	complex<double> *FD = new complex<double>[w * h];

	DoFFT( TD,  FD, w,h);

	//DisplayFw(FD,w, h,0.6,"|F(u,v)|");

	complex<double> *PTD = new complex<double>[w * h];
	complex<double> *PFD = new complex<double>[w * h];

	//Laplace
	for(int y=0; y<h; y++)
		for(int x=0; x<w; x++)
			PTD[x + w * y]=0.0;
	PTD[1 + w * 1]=4.0;
	PTD[1 + w * 0]=PTD[0 + w * 1]=PTD[2 + w * 1]=PTD[1 + w * 2]=-1.0;
	FFT2(PTD,PFD, w, h);

	//filter
	double c1=0.1;
	double c2=0.1;
	double T=1.0;
	double r=0.2;		
	double minH=0.001;
	for(int y=0; y<h; y++)
	{
		for(int x=0; x<w; x++)
		{

			double	uv=Pi*(c1*(x-w/2)+c2*(y-h/2)) ; 
			complex<double> H ;
			if(uv==0.0)
				H= complex<double>(T,0.0);
			else 
				H= complex<double>(T/(uv)*sin(uv)*cos(uv),-T/(uv)*sin(uv)*sin(uv)); 

			if(H.real()>=0 && H.real()<=minH)
				H= complex<double>(minH,H.imag());

			if(H.imag()>=0 && H.imag()<=minH)
				H= complex<double>(H.real(),minH);

			if(H.real()<0 && H.real()>=-minH)
				H= complex<double>(-minH,H.imag());

			if(H.imag()<0 && H.imag()>=-minH)
				H= complex<double>(H.real(),-minH);

			// |H(u,v)|
			double norm = abs(H);
			// |P(u,v)|
			double Pnorm = abs(PFD[y*w+x]);

			// H*(u,v)/(|H(u,v)|^2+r|p(u,v)|^2)
			complex<double> temp( complex<double>(H.real(),-H.imag()));
			temp=temp/(norm*norm+r*Pnorm*Pnorm);

			// 求得f(u,v)

			FD[y*w + x]*=temp;

		}
	}


	//DisplayFw(FD,w, h,0.6,"|F(u,v)H(u,v)|");

	DoIFFT( TD,  FD, w,h,"约束最小二乘法滤波器",CPoint(0,0));

	// 恢复光标
	EndWaitCursor();	

	// 删除临时变量
	delete [] TD;
	delete [] FD;
	delete [] PTD;
	delete [] PFD;
}

void CImageProcessView::OnUpdateFrequencydomainLeastsquaresfilter(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//设定多个畸变点,获得其校正后坐标
//将图像分成多个区域,对应区域满足线性平面
//解方程获得线性参数,对图像进行几何变换,可完成图像畸变、畸变校正
void CImageProcessView::OnSpatialdomainGeometrictransformations()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	//1.获得对应点
	//4x4 对称区域
	const int N=3; 
	CPoint pt1[(N+1)*(N+1)];
	CPoint pt2[(N+1)*(N+1)];

	int h=(pDoc->EndPoint.y-pDoc->StartPoint.y+1)/N;
	int w=(pDoc->EndPoint.x-pDoc->StartPoint.x+1)/N;

	int k=0;
	使图像畸变
	//for(int j=pDoc->StartPoint.y;j<pDoc->EndPoint.y;j+=h)
	//	for(int i=pDoc->StartPoint.x;i<pDoc->EndPoint.x;i+=w)
	//	{
	//		pt1[k]=CPoint(i,j);
	//		k++;
	//	}
	//
	//for(int i=0;i<(N+1)*(N+1);i++)
	//	pt2[i]=pt1[i]+CPoint(2,2);
	//
	//pt2[N+2]+=CPoint(-40,-10);
	//pt2[N+3]+=CPoint(20,40);
	//
	//pt2[2*N+3]+=CPoint(-25,-10);
	//pt2[2*N+4]+=CPoint(15,25);
	//

	//使畸变图像校正
	for(int j=pDoc->StartPoint.y;j<pDoc->EndPoint.y;j+=h)
		for(int i=pDoc->StartPoint.x;i<pDoc->EndPoint.x;i+=w)
		{
			pt2[k]=CPoint(i,j);
			k++;
		}

		for(int i=0;i<(N+1)*(N+1);i++)
			pt1[i]=pt2[i]+CPoint(2,2);

		pt1[N+2]+=CPoint(-40,-10);
		pt1[N+3]+=CPoint(20,40);

		pt1[2*N+3]+=CPoint(-25,-10);
		pt1[2*N+4]+=CPoint(15,25);


		//2.获得对应变换系数(8)
		double c[N*N][8];

		for(int k=0;k<N*N;k++){
			// 构造矩阵
			CMatrix mtxA(8,8), mtxB(8,1),mtxC(8,1);

			double value[64]={0};
			double value1[8]={0};

			value[0] =pt1[k+k/3+0].x; value[1]=pt1[k+k/3+0].y;  value[2]=pt1[k+k/3+0].x*pt1[k+k/3+0].y;   value[3]=1;
			value[12]=pt1[k+k/3+0].x; value[13]=pt1[k+k/3+0].y; value[14]=pt1[k+k/3+0].x*pt1[k+k/3+0].y;  value[15]=1;

			value[16] =pt1[k+k/3+1].x; value[17]=pt1[k+k/3+1].y;  value[18]=pt1[k+k/3+1].x*pt1[k+k/3+1].y;  value[19]=1;
			value[28]=pt1[k+k/3+1].x; value[29]=pt1[k+k/3+1].y; value[30]=pt1[k+k/3+1].x*pt1[k+k/3+1].y;    value[31]=1;

			value[32] =pt1[k+k/3+1+N].x; value[33]=pt1[k+k/3+1+N].y;  value[34]=pt1[k+k/3+1+N].x*pt1[k+k/3+1+N].y;  value[35]=1;
			value[44]=pt1[k+k/3+1+N].x; value[45]=pt1[k+k/3+1+N].y; value[46]=pt1[k+k/3+1+N].x*pt1[k+k/3+1+N].y;    value[47]=1;

			value[48] =pt1[k+k/3+2+N].x; value[49]=pt1[k+k/3+2+N].y;  value[50]=pt1[k+k/3+2+N].x*pt1[k+k/3+2+N].y;  value[51]=1;
			value[60]=pt1[k+k/3+2+N].x; value[61]=pt1[k+k/3+2+N].y; value[62]=pt1[k+k/3+2+N].x*pt1[k+k/3+2+N].y;    value[63]=1;

			value1[0]=pt2[k+k/3+0].x;value1[1]=pt2[k+k/3+0].y;
			value1[2]=pt2[k+k/3+1].x;value1[3]=pt2[k+k/3+1].y;
			value1[4]=pt2[k+k/3+1+N].x;value1[5]=pt2[k+k/3+1+N].y;
			value1[6]=pt2[k+k/3+2+N].x;value1[7]=pt2[k+k/3+2+N].y;

			mtxA.SetData(value);

			mtxB.SetData(value1);


			// 构造线性方程组
			CLEquations leqs(mtxA, mtxB);


			// 全选主元高斯消去法
			CString m_strResult;

			if (leqs.GetRootsetGauss(mtxC))
				m_strResult = mtxC.ToString(" ");
			else
			{
				m_strResult ="求解失败";

				// 显示数据
				AfxMessageBox(m_strResult, MB_OK|MB_ICONINFORMATION);
				return;
			}

			memcpy(c[k],mtxC.GetData(),8*sizeof(double));

		}


		//3.几何校正

		unsigned char*	lpNewDIBBits;
		lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

		if (lpNewDIBBits == NULL)
		{
			return ;
		}

		unsigned char*	lpSrc;

		unsigned char*	lpDst;

		lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
		memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);



		for (int i = pDoc->StartPoint.y+2; i <pDoc->EndPoint.y-2; i ++){
			for (int j =pDoc->StartPoint.x+2; j <pDoc->EndPoint.x-2; j ++){
				lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j;

				//为了方便,不去判断具体区域,忍让边界处错误
				int k=min(((i-pDoc->StartPoint.y)/h),N-1)*3+min((j-pDoc->StartPoint.x)/w,N);

				double x=c[k][0]*j+c[k][1]*i+c[k][2]*i*j+c[k][3];
				double y=c[k][4]*j+c[k][5]*i+c[k][6]*i*j+c[k][7];

				int x1=(int)x;
				int y1=(int)y;
				if(x1>=0 && x1<lWidth-1 && y1>=0 && y1<lHeight-1){//in
					lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - y1) + x1;
					int v=(unsigned char)((y1+1-y)*((x1+1-x)*(*lpSrc)+(x-x1)*(*(lpSrc+1)))
						+(y-y1)*((x1+1-x)*(*(lpSrc-lLineBytes))+(x-x1)*(*(lpSrc-lLineBytes+1))));//a=x-x1 b=y-y1 
					if(v<0) v=0;
					else if(v>255) v=255;
					*lpDst=(BYTE)v;
					//	*lpDst=*(pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - (int)(y+0.5)) + (int)(x+0.5));//近邻插值

				}

			}

		}


		CString str=pDoc->GetTitle();
		DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"--+运用角点几何校正");//


		delete [] lpNewDIBBits;

		// 恢复光标
		EndWaitCursor();	

}

void CImageProcessView::OnUpdateSpatialdomainGeometrictransformations(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnDwtDwt()
{

	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	CPoint wh=FrequencydomainSelectarea();

	int w=wh.x;
	int h=wh.y;
	const int LEVEL=2;

	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage, lLineBytes,lHeight,str);

	m_bDWT=!m_bDWT;

	DoDWT(w,h,LEVEL);

	// 恢复光标
	EndWaitCursor();
}
void CImageProcessView::DoDWT(int w,int h,int LEVEL)
{

	CImageProcessDoc* pDoc = GetDocument();

	//input data
	// 分配内存
	double *image = new double [w * h];
	unsigned char* lpSrc;
	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			if(i+pDoc->StartPoint.y<lHeight && pDoc->StartPoint.x+j<lWidth)
			{
				lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + pDoc->StartPoint.x+j;

				image[j + w * i] = (double)*(lpSrc);//w*h

			}else
				image[j + w * i] = 0;//out of image:add 0
		}
	}

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));

	int nDWTCurDepth=0;	

	int nCurWLevel=wp;
	int nCurHLevel=hp;

	while( min(nCurWLevel,nCurHLevel)>min(wp,hp)-LEVEL)
	{// 进行小波变换
		// 计算当前分解的图象的长度和宽度
		int CurW = 1<<nCurWLevel, CurH = 1<<nCurHLevel;

		// 对行进行一维DWT
		for (int i=0; i<CurH; i++)
			DWTStep_1D(image+w*i, nCurWLevel, 0, 1,2);
		// 对列进行一维DWT
		for (int i=0; i<CurW; i++)
			DWTStep_1D(image+i, nCurHLevel, 0, w,2);

		nDWTCurDepth ++;
		nCurWLevel=wp-nDWTCurDepth;
		nCurHLevel=hp-nDWTCurDepth;

	}



	// 然后,将数据拷贝回原CDib中,并进行相应的数据转换


	int lfw;
	int lfh;
	lfw = w>>nDWTCurDepth, lfh = h>>nDWTCurDepth;

	for(int i = 0; i < h; i++)
	{
		// 列
		for(int j = 0; j < w; j++)
		{
			double f=image[i * w + j];
			unsigned char tmp;
			if (i<lfh && j<lfw)
			{//FloatToByte
				if (f<=0) tmp=(BYTE)0;
				else if (f>=255) tmp=(BYTE)255;
				else tmp=(BYTE)(f+0.5);
			}
			else{
				//FloatToChar
				char temp;
				if (f>=0){
					if (f>=127.5)
						temp= (char)127;
					else temp=(char)(f+0.5);}
				else{
					if (f<=-128)
						temp= (char)-128;
					else temp= -(char)(-f+0.5);
				}
				tmp=(BYTE)(temp ^0x80);//+128
			}

			if(j<lWidth-pDoc->StartPoint.x && i<lHeight-pDoc->StartPoint.y)
			{
				lpSrc =  pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;
				* (lpSrc) = tmp;
			}
		}
	}

	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"DWT");


	// 删除临时变量
	delete [] image;

}

/*************************************************************************
*
* \函数名称:
*   DWTStep_1D()
*
* \输入参数:
*   double * pDbSrc		- 指向源数据的指针
*   int nCurLevel		- 当前分界的层数
*   int nInv			- 是否为DWT,1表示为IDWT,0表示DWT
*   int nStep			- 当前的计算层数
*   int nSupp			- 小波基的紧支集的长度
*
* \返回值:
*   BOOL			- 成功则返回TRUE,否则返回FALSE
*
* \说明:
*   该函数用对存放在pDBSrc中的数据进行一层的一维DWT或者IDWT。其中,nInv为表示进行
*   DWT或者IDWT的标志。nCurLevel为当前需要进行分界的层数。nStep为已经分界的层数
*   计算后数据仍存放在pDbSrc中
*
*************************************************************************
*/
BOOL  CImageProcessView::DWTStep_1D(double* pDbSrc, int nCurLevel,
									int nInv, int nStep,int nSupp)
{
	// 小波变换函数原型
	// Daubechies紧致正交小波基
	//不同支撑区间长度下的滤波器系数如下
	//only use hCoef[0][]
	const double hCoef[10][20] =
	{
		{ .707106781187,  .707106781187},

		{ .482962913145,  .836516303738,  .224143868042, -.129409522551 },//use 

		{ .332670552950,  .806891509311,  .459877502118, -.135011020010, -.085441273882,  .035226291882 },

		{ .230377813309,  .714846570553,  .630880767930, -.027983769417,
		-.187034811719,  .030841381836,  .032883011667, -.010597401785 },

		{ .160102397974,  .603829269797,  .724308528438,  .138428145901, -.242294887066,
		-.032244869585,  .077571493840, -.006241490213, -.012580751999,  .003335725285 },

		{ .111540743350,  .494623890398,  .751133908021,  .315250351709, -.226264693965,
		-.129766867567,  .097501605587,  .027522865530, -.031582039318,  .000553842201,
		.004777257511, -.001077301085 },

		{ .077852054085,  .396539319482,  .729132090846,  .469782287405, -.143906003929,
		-.224036184994,  .071309219267,  .080612609151, -.038029936935, -.016574541631,
		.012550998556,  .000429577973, -.001801640704,  .000353713800 },

		{ .054415842243,  .312871590914,  .675630736297,  .585354683654, -.015829105256,
		-.284015542962,  .000472484574,  .128747426620, -.017369301002, -.044088253931,
		.013981027917,  .008746094047, -.004870352993, -.000391740373,  .000675449406,
		-.000117476784 },

		{ .038077947364,  .243834674613,  .604823123690,  .657288078051,  .133197385825,
		-.293273783279, -.096840783223,  .148540749338,  .030725681479, -.067632829061,
		.000250947115,  .022361662124, -.004723204758, -.004281503682,  .001847646883,
		.000230385764, -.000251963189,  .000039347320 },

		{ .026670057901,  .188176800078,  .527201188932,  .688459039454,  .281172343661,
		-.249846424327, -.195946274377,  .127369340336,  .093057364604, -.071394147166,
		-.029457536822,  .033212674059,  .003606553567, -.010733175483,  .001395351747,
		.001992405295, -.000685856695, -.000116466855,  .000093588670, -.000013264203 }
	};
	double s = sqrt(2.0);

	// 获得小波基的指针
	double* h = (double*)hCoef[nSupp-1];

	// 确认当前层数有效
	ASSERT(nCurLevel>=0);

	// 计算当前层数的长度
	int CurN = 1<<nCurLevel;
	if (nInv) CurN <<= 1;

	// 确认所选择的小波基和当前层数的长度有效
	if (nSupp<1 || nSupp>10 || CurN<2*nSupp) 
		return FALSE;

	// 分配临时内存用于存放结果
	double *ptemp = new double[CurN];
	if (!ptemp) return FALSE;

	double	s1, s2;
	int	Index1, Index2;

	// 判断是进行DWT还是IDWT
	if (!nInv)
	{	// DWT
		Index1=0;
		Index2=2*nSupp-1;

		// 进行卷积,其中s1为低频部分,s2为高频部分的结果
		for (int i=0; i<CurN/2; i++)
		{	
			s1 = s2 = 0;
			double t = -1;
			for (int j=0; j<2*nSupp; j++, t=-t)
			{
				s1 += h[j]*pDbSrc[(Index1 & CurN-1) * nStep];
				s2 += t*h[j]*pDbSrc[(Index2 & CurN-1) * nStep];

				Index1++;
				Index2--;
			}

			// 将结果存放在临时内存中
			ptemp[i] = s1/s;
			ptemp[i+CurN/2] = s2/s;

			Index1 -= 2*nSupp;
			Index2 += 2*nSupp;
			Index1 += 2;
			Index2 += 2;
		}
	}

	// 否则进行IDWT
	else
	{	// IDWT
		Index1 = CurN/2;
		Index2 = CurN/2-nSupp+1;

		// 进行卷积,其中其中s1为低频部分,s2为高频部分的结果
		for (int i=0; i<CurN/2; i++)
		{
			s1 = s2 = 0;
			int Index3 = 0;
			for (int j=0; j<nSupp; j++)
			{
				s1 += h[Index3]*pDbSrc[(Index1 & CurN/2-1) * nStep]
				+h[Index3+1]*pDbSrc[((Index2 & CurN/2-1) + CurN/2) * nStep];
				s2 += h[Index3+1]*pDbSrc[(Index1 & CurN/2-1) * nStep]
				-h[Index3]*pDbSrc[((Index2 & CurN/2-1) + CurN/2) * nStep];

				Index3+=2;
				Index1--,		Index2++;
			}

			// 将结果存入临时内存
			ptemp[2*i] = s1*s;
			ptemp[2*i+1] = s2*s;

			Index1 += nSupp;
			Index2 -= nSupp;
			Index1++;
			Index2++;
		}
	}

	// 将结果存入源图象中
	for (long int i=0; i<CurN; i++)
		pDbSrc[i*nStep] = ptemp[i];

	// 释放临时内存,并返回
	delete[] ptemp;
	return TRUE;
}

void CImageProcessView::OnUpdateDwtDwt(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(!m_bDWT)
				bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnDwtIdwt()
{

	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage, lLineBytes,lHeight,str);

	m_bDWT=!m_bDWT;

	const int LEVEL=2;
	int w=pDoc->EndPoint.x-pDoc->StartPoint.x+1;
	int h=pDoc->EndPoint.y-pDoc->StartPoint.y+1;
	DoIDWT(w,h,LEVEL);

	// 恢复光标
	EndWaitCursor();

}
void CImageProcessView::DoIDWT(int w,int h,int LEVEL)
{

	CImageProcessDoc* pDoc = GetDocument();

	//input data
	// 分配内存
	double *image = new double [w * h];
	unsigned char* lpSrc;

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));

	int nDWTCurDepth=LEVEL;	
	int lfw = 1<<(wp-nDWTCurDepth), lfh = 1<<(hp-nDWTCurDepth);


	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

			if (i>=lfh || j>=lfw)
			{
				//CharToFloat
				image[j + w * i] = (double)*(lpSrc)-128;//高频
			}else
				image[j + w * i] = (double)*(lpSrc);//低频

		}
	}

	int nCurWLevel=wp-nDWTCurDepth;
	int nCurHLevel=hp-nDWTCurDepth;


	while(nDWTCurDepth>0)
	{// 进行小波反变换
		// 计算当前分解的图象的长度和宽度
		int CurW = 1<<nCurWLevel, CurH = 1<<nCurHLevel;

		CurW <<= 1;
		CurH <<= 1;

		// 对列进行IDWT
		for (int i=0; i<CurW; i++)
			DWTStep_1D(image+i, nCurHLevel, 1, w,2);
		// 对行进行IDWT
		for (int i=0; i<CurH; i++)
			DWTStep_1D(image+w*i, nCurWLevel, 1,1,2);

		nDWTCurDepth --;
		nCurWLevel=wp-nDWTCurDepth;
		nCurHLevel=hp-nDWTCurDepth;

	}



	// 然后,将数据拷贝回原CDib中,并进行相应的数据转换


	for(int i = 0; i < h; i++)
	{
		// 列
		for(int j = 0; j < w; j++)
		{
			double f=image[i * w + j];
			unsigned char tmp;
			if (f<=0) tmp=(BYTE)0;
			else if (f>=255) tmp=(BYTE)255;
			else tmp=(BYTE)(f+0.5);

			if(j<lWidth-pDoc->StartPoint.x && i<lHeight-pDoc->StartPoint.y)
			{
				lpSrc =  pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;
				* (lpSrc) = tmp;
			}
		}
	}

	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"IDWT");

	// 删除临时变量
	delete [] image;

}

void CImageProcessView::OnUpdateDwtIdwt(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_bDWT)
				bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnEdgeAll()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char* lpSrc;

	int w=pDoc->EndPoint.x-pDoc->StartPoint.x+1;
	int h=pDoc->EndPoint.y-pDoc->StartPoint.y+1;

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));
	const int LEVEL=2;
	int nDWTCurDepth=LEVEL;	
	int lfw = 1<<(wp-nDWTCurDepth), lfh = 1<<(hp-nDWTCurDepth);


	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

			if (i<lfh && j<lfw)
				*lpSrc = 128;//0

		}
	}
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

}

void CImageProcessView::OnUpdateEdgeAll(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_bDWT)
				bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnEdgeH()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char* lpSrc;

	int w=pDoc->EndPoint.x-pDoc->StartPoint.x+1;
	int h=pDoc->EndPoint.y-pDoc->StartPoint.y+1;

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));
	const int LEVEL=2;
	int nDWTCurDepth=LEVEL;	
	int lfw = 1<<(wp-nDWTCurDepth), lfh = 1<<(hp-nDWTCurDepth);


	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

			if (i<lfh && j<lfw)
				*lpSrc = 64;//0
			else if (j<lfw || (j>=lfw  && j<lfw*2 && i>lfh*2))
				*lpSrc = 128;

		}
	}
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

}

void CImageProcessView::OnUpdateEdgeH(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_bDWT)
				bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnEdgeV()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char* lpSrc;

	int w=pDoc->EndPoint.x-pDoc->StartPoint.x+1;
	int h=pDoc->EndPoint.y-pDoc->StartPoint.y+1;

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));
	const int LEVEL=2;
	int nDWTCurDepth=LEVEL;	
	int lfw = 1<<(wp-nDWTCurDepth), lfh = 1<<(hp-nDWTCurDepth);


	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

			if (i<lfh && j<lfw)
				*lpSrc = 64;//0
			else if (i<lfh || (i>=lfh  && i<lfh*2 && j>lfw*2))
				*lpSrc = 128;

		}
	}
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

}

void CImageProcessView::OnUpdateEdgeV(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_bDWT)
				bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnDwtSmooth()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char* lpSrc;

	int w=pDoc->EndPoint.x-pDoc->StartPoint.x+1;
	int h=pDoc->EndPoint.y-pDoc->StartPoint.y+1;

	int wp=int(log((double) w)/log(2.0));
	int hp=int(log((double) h)/log(2.0));
	const int LEVEL=2;
	int nDWTCurDepth=LEVEL;	
	int lfw = 1<<(wp-nDWTCurDepth), lfh = 1<<(hp-nDWTCurDepth);
	const int  Th=20;

	for(int i = 0; i < h; i++)
	{
		for(int j = 0; j < w; j++)
		{
			lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i-pDoc->StartPoint.y) + j+pDoc->StartPoint.x;

			if (!(i<lfh && j<lfw))
				if(*lpSrc>128-Th && *lpSrc<128+Th) 
					*lpSrc = 128;
				else if(*lpSrc>128)
					*lpSrc-=Th;
				else
					*lpSrc+=Th;

		}
	}
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

}

void CImageProcessView::OnUpdateDwtSmooth(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_bDWT)
				bAvail=true;

	pCmdUI->Enable(bAvail);

}

void CImageProcessView::OnMorphologicalDilation()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int Obj=TWOVALUE_H;
	int Back=TWOVALUE_L;

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=1;

	Dilation(S,M,N,Obj,Back);

	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"膨胀运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}
void CImageProcessView::Dilation(int** S, int M, int N, int Object, int Back)
{
	// TODO: 在此添加命令处理程序代码
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			if(*lpSrc==Back){//obj no need process
				for (int m = 0; m < M; m++)
				{
					for (int n = 0; n < N; n++)
					{
						if (S[m][n] == 0)
							continue;
						if(i+m-M/2>=0 && i+m-M/2<lHeight && j+n -N/2>=0 && j+n-N/2<lWidth)
							if (*(lpSrc - lLineBytes*(m-M/2)  +(n-N/2) ) ==Object)//R and ~St != Null
							{  	*lpDst=(BYTE)Object;
						break;
						}

					}

				}
			}

		}
	}

	// 释放内存
	delete []lpNewDIBBits;

}

void CImageProcessView::OnUpdateMorphologicalDilation(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);

}

void CImageProcessView::OnMorphologicalErosion()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	//	int Obj=TWOVALUE_H;
	int Back=TWOVALUE_L;

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=1;

	Erosion(S,M,N,Back);

	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"腐蚀运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;

}
void CImageProcessView::Erosion(int** S,int M,int N,  int Back)
{
	// TODO: 在此添加命令处理程序代码
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}



	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;						


			if (*lpSrc !=Back){
				for (int m = 0; m < M; m++)
				{
					for (int n = 0; n < N; n++)
					{
						if (S[m][n] == 0)
							continue;
						else if(i+m-M/2>=0 && i+m-M/2<lHeight && j+n -N/2>=0 && j+n-N/2<lWidth){
							if (*(lpSrc - lLineBytes*(m-M/2)  +(n-N/2) ) ==Back)//t St in R
							{ 
								*(lpDst)=(BYTE) Back;
								break;
							}

						}

					}
				}
			}
		}
	}


	// 释放内存
	delete []lpNewDIBBits;

}
void CImageProcessView::OnUpdateMorphologicalErosion(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);

}

void CImageProcessView::OnMorphologicalOpen()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int Obj=TWOVALUE_H;
	int Back=TWOVALUE_L;

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=1;

	Erosion(S,M,N,Back);
	Dilation(S,M,N,Obj,Back);


	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"开运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}

void CImageProcessView::OnUpdateMorphologicalOpen(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);

}

void CImageProcessView::OnMorphologicalClose()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int Obj=TWOVALUE_H;
	int Back=TWOVALUE_L;

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=1;

	Dilation(S,M,N,Obj,Back);
	Erosion(S,M,N,Back);

	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"闭运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}

void CImageProcessView::OnUpdateMorphologicalClose(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);

}
//显示直方图,选择阈值
void CImageProcessView::OnSegmentationFixedthreshold()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	int Hist[256]={0};
	GetHistgram(Hist,false);

	DisplayDlg dlg;
	dlg.pData=&Hist[0];
	dlg.m_Sizex=256;
	dlg.m_LinePos=THRESHOLD;
	dlg.m_Title=_T("选择阈值");
	dlg.m_Level=1;

	if(dlg.DoModal()==IDOK)
		THRESHOLD=dlg.m_LinePos;

	Fixedthreshold();

}
void CImageProcessView::Fixedthreshold()
{
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpDst;
	unsigned char* lpSrc;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +pDoc->StartPoint.x;
		lpDst = lpNewDIBBits +  lLineBytes* (lHeight-1-i) +pDoc->StartPoint.x;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			if(*lpSrc>THRESHOLD)
				*lpDst=TWOVALUE_H;
			else
				*lpDst=TWOVALUE_L;
			lpSrc++;lpDst++;
		}
	}

	CString str=pDoc->GetTitle();
	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"--+二值化");//display orignal image

	delete [] lpNewDIBBits;

}
void CImageProcessView::OnUpdateSegmentationFixedthreshold(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(!m_bTwoValue) bAvail=true;

	pCmdUI->Enable(bAvail);
}
//A Erosion B1 (原点为1)&&  A~ Erosion B2 (原点为X);(满足 1.不满足0)
//同于结构中所有点相同,结构应该含有1和0(查询速度慢)
void CImageProcessView::OnMorphologicalHitormiss()
{

	CImageProcessDoc* pDoc = GetDocument();
	BeginWaitCursor();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);//备份

	int Obj=TWOVALUE_H;
	int Back=TWOVALUE_L;

	const int M=m_ModelHeight;
	const int N=m_ModelWidth;

	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}

	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			if(m_pModelData[i*m_ModelWidth+j])
				S[i][j]=1;
			else
				S[i][j]=0;

	//1 A Erosion B1
	Erosion(S,M,N,Back);


	unsigned char*	lpNewDIBBits1;
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return ;
	}


	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits1,lpSrc, lLineBytes * lHeight);///A Erosion B1
	memcpy( lpSrc,lpNewDIBBits, lLineBytes * lHeight);//备份还原


	//B2
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=1-S[i][j];
	//A~
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +pDoc->StartPoint.x;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			*lpSrc=TWOVALUE_H-*lpSrc;
			lpSrc++;
		}
	}

	//if use lpNewDIBBits1==true,we can get fast!
	//2 A~ Erosion B2
	//Erosion(S,M,N,Obj,Back);

	//for fast
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;						
			if(*lpDst==Obj)//A Erosion B1==Obj
			{
				bool bBack=false;//
				for (int m = 0; m < M; m++)
				{
					for (int n = 0; n < N; n++)
					{
						if (S[m][n] == 0)
							continue;
						else if(i-m+M/2>=0 && i-m+M/2<lHeight && j+n -N/2>=0 && j+n -N/2<lWidth){
							if (*(lpSrc - lLineBytes*(m-M/2)  +(n-N/2) ) ==Back)//t St in R
							{   bBack=true;;
							m=M;n=N;//out
							}

						}

					}
				}
				if(bBack) *(lpDst)= (BYTE)Back;
			}
		}
	}

	//display
	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable+TWOVALUE_H+1;//
	pDibQuad->rgbRed = 255;	pDibQuad->rgbGreen =0;pDibQuad->rgbBlue = 0;

	pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable+TWOVALUE_L+1;//
	pDibQuad->rgbRed = 0;	pDibQuad->rgbGreen =0;pDibQuad->rgbBlue = 255;


	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc =lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;//A
		lpDst =lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;//击中或击不中
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpDst++;lpSrc++;
			if(*lpDst == Obj) 
			{

				for (int m = 0; m < m_ModelHeight; m++)
				{
					for (int n = 0; n <m_ModelWidth; n++)
					{

						*(lpSrc+ lLineBytes*(m_ModelHeight/2 - m)  +(n - m_ModelWidth/2) )+=1; //=m_ModelData[m*m_ModelWidth+n];

					}
				}

			}

		}

	}

	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);//显示结果


	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"击中或击不中运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	// 恢复光标
	EndWaitCursor();	

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
	delete [] lpNewDIBBits;
	delete [] lpNewDIBBits1;
}

void CImageProcessView::OnUpdateMorphologicalHitormiss(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	BOOL bAvail=false;
	if(m_bTwoValue)
		if(m_pModelData)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}

//利用3x3结构B腐蚀
//A-(A腐蚀B)
//在原图上显示边缘
void CImageProcessView::OnApplicationBoundaryextraction()
{
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
		return ;


	//copy img
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//int Obj=TWOVALUE_H;
	int Back=TWOVALUE_L;

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=1;
	//S[0][0]=0;S[0][2]=0;S[2][0]=0;S[2][2]=0;

	Erosion(S,M,N,Back);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;


	//A-A Erosion B
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{ 
		lpSrc++;lpDst++;						
		*lpSrc=(*lpDst-*lpSrc);
		if(*lpSrc) (*lpDst)+=1;//for display
	}
	}



	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpSrc,lpNewDIBBits, lLineBytes * lHeight);

	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable+TWOVALUE_H+1;//
	pDibQuad->rgbRed = 255;pDibQuad->rgbGreen =0;pDibQuad->rgbBlue = 0;

	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"边缘提取");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdateApplicationBoundaryextraction(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);

}

//将背景提取出来,则可以填充非背景区域,利用4个角点为可能背景点,利用十字结构膨胀,将背景填满
void CImageProcessView::OnApplicationRegionfilling()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	BeginWaitCursor();
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//set init seed 背景(4 角点)
	lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 -pDoc->StartPoint.y-1)+pDoc->StartPoint.x+1;
	if(*lpSrc==TWOVALUE_L)		
		*(lpNewDIBBits + lLineBytes * (lHeight - 1 -pDoc->StartPoint.y-1)+pDoc->StartPoint.x+1)=0x1;

	lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 -pDoc->StartPoint.y-1)+pDoc->EndPoint.x-1;
	if(*lpSrc==TWOVALUE_L)		
		*(lpNewDIBBits + lLineBytes * (lHeight - 1 -pDoc->StartPoint.y-1)+pDoc->EndPoint.x-1)=0x1;

	lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 -pDoc->EndPoint.y+1)+pDoc->StartPoint.x+1;
	if(*lpSrc==TWOVALUE_L)		
		*(lpNewDIBBits + lLineBytes * (lHeight - 1 -pDoc->EndPoint.y+1)+pDoc->StartPoint.x+1)=0x1;

	lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 -pDoc->EndPoint.y+1)+pDoc->EndPoint.x-1;
	if(*lpSrc==TWOVALUE_L)		
		*(lpNewDIBBits + lLineBytes * (lHeight - 1 -pDoc->EndPoint.y+1)+pDoc->EndPoint.x-1)=0x1;


	bool bchg=true;
	//提取背景
	while(bchg){
		bchg=false;

		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
				lpDst++;lpSrc++;
				if(((*lpSrc)==TWOVALUE_L) && ((*lpDst)==0x1))
				{   bchg=true;
				*lpSrc|=0x1;//visited

				//若边缘为1个像数,可能出错
				//for(int m=-1;m<2;m++)
				//	for(int n=-1;n<2;n++)
				//	if((*(lpSrc+m*lLineBytes+n))==TWOVALUE_L) (*(lpDst+m*lLineBytes+n))=0x1;

				//十字结构
				if((*(lpSrc+lLineBytes))==TWOVALUE_L) *(lpDst+lLineBytes)=0x1;
				if((*(lpSrc-lLineBytes))==TWOVALUE_L) *(lpDst-lLineBytes)=0x1;
				if((*(lpSrc+1))==TWOVALUE_L) *(lpDst+1)=0x1;
				if((*(lpSrc-1))==TWOVALUE_L) *(lpDst-1)=0x1;

				}
			}
		}
	}

	//非背景0置128
	//change all black to white
	for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
		for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ j;

			if(*lpDst==TWOVALUE_L){
				*lpDst=TWOVALUE_H;

			}

		}
	}

	//display 
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){ 
			lpSrc++;lpDst++;	
			if(!*lpSrc && *lpDst>=TWOVALUE_H)
				(*lpDst)+=1;

		}
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpSrc,lpNewDIBBits, lLineBytes * lHeight);

	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable+TWOVALUE_H+1;//out
	pDibQuad->rgbRed = 255;pDibQuad->rgbGreen =0;pDibQuad->rgbBlue = 0;

	EndWaitCursor();	
	// 释放内存
	delete []lpNewDIBBits;

	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"区域填充");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);


}

void CImageProcessView::OnUpdateApplicationRegionfilling(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);

}

//顺序扫描,找到一未访问的物体点,No++,利用膨胀获取相连部分,全设置为N,且设置为访问过;直到全部访问过
//统计每个区域面积;可以求区域中心、周长、矩等
void CImageProcessView::OnApplicationConnectedcomponents()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	int ObjNum=Connectedcomponents();

	DisplayObjLabel(ObjNum+1);


}

int CImageProcessView::Connectedcomponents(){

	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
		return 0;

	memset( lpNewDIBBits,0, lLineBytes * lHeight);


	int No=0;

	bool bProcOver=false;
	while(!bProcOver){
		bProcOver=true;
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
				lpDst++;lpSrc++;
				if(((*lpSrc)==TWOVALUE_H) && (!*lpDst))
				{   No++;
				*lpDst=(BYTE)No;//set first pt
				bProcOver=false;
				break;
				}
			}
			if(!bProcOver)break;
		}

		if(bProcOver) break;
		bool bchg=true;
		while(bchg){
			bchg=false;

			for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
				lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
				lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
				for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
					lpDst++;lpSrc++;
					if(((*lpSrc)==TWOVALUE_H) && ((*lpDst)==No))
					{   bchg=true;
					*lpSrc|=0x1;//visited
					//must be 8 point
					for(int m=-1;m<2;m++)
						for(int n=-1;n<2;n++)
							if((*(lpSrc+m*lLineBytes+n))==TWOVALUE_H) (*(lpDst+m*lLineBytes+n))=(BYTE)No;

					}
				}
			}
		}


	}

	memcpy(pDoc->m_pDib->m_lpImage, lpNewDIBBits, lLineBytes * lHeight);

	// 释放内存
	delete []lpNewDIBBits;

	return No;//object number
}


void CImageProcessView::OnUpdateApplicationConnectedcomponents(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}

//凸壳:区域内任意两点落在区域内
//该方法不是最小区域
//获取包含区域最小长方形区域,限制在该区域
//4个结构,击中点包含,反复运算直到不改变
//仅进行一个凸壳运算,故先选择区域,可以方便的求取多个凸壳
void CImageProcessView::OnApplicationConvexhull()
{
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	unsigned char*	lpNewDIBBits1;
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return ;
	}

	BeginWaitCursor();
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);
	memcpy( lpNewDIBBits1,lpNewDIBBits, lLineBytes * lHeight);

	//Get max area
	CRect rectArea(512,512,0,0);

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{ 
		lpSrc++;
		if(*lpSrc & TWOVALUE_H) //
		{
			if(i<rectArea.top)rectArea.top=i;
			else if(i>rectArea.bottom)rectArea.bottom=i;
			if(j<rectArea.left)rectArea.left=j;
			else if(j>rectArea.right)rectArea.right=j;

		}
	}
	}

	pDoc->StartPoint.x=rectArea.left-1;
	pDoc->EndPoint.x=rectArea.right+1;
	pDoc->StartPoint.y=rectArea.top-1;
	pDoc->EndPoint.y=rectArea.bottom+1;

	// |
	// |o
	// | 
	bool bOver=false;
	while(!bOver){
		bOver=true;
		for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
			for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
				lpDst=lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ j;
				if(*lpDst == TWOVALUE_L)
					if (*(lpDst-1) ==TWOVALUE_H && *(lpDst-1+ lLineBytes) ==TWOVALUE_H && *(lpDst-1- lLineBytes) ==TWOVALUE_H)
					{
						*lpDst = TWOVALUE_H;
						lpDst=lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ j;;	
						*lpDst = TWOVALUE_H;
						bOver=false;
					}
			}
		}
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//---
	// o
	bOver=false;
	while(!bOver){
		bOver=true;
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
				lpDst=lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ j;;	
				if(*lpDst == TWOVALUE_L)
					if (*(lpDst-1+lLineBytes) ==TWOVALUE_H && *(lpDst+ lLineBytes) ==TWOVALUE_H && *(lpDst+1+ lLineBytes) ==TWOVALUE_H)
					{
						*lpDst = TWOVALUE_H;
						lpDst=lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ j;;	
						*lpDst = TWOVALUE_H;
						bOver=false;
					}
			}
		}
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//  |
	// o|
	//  | 
	bOver=false;
	while(!bOver){
		bOver=true;
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			for (int j =pDoc->EndPoint.x-1; j >pDoc->StartPoint.x; j --){ 
				lpDst=lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ j;;	
				if(*lpDst == TWOVALUE_L)
					if (*(lpDst+1) ==TWOVALUE_H && *(lpDst+1+ lLineBytes) ==TWOVALUE_H && *(lpDst+1- lLineBytes) ==TWOVALUE_H)
					{
						*lpDst = TWOVALUE_H;
						lpDst=lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ j;;	
						*lpDst = TWOVALUE_H;
						bOver=false;
					}

			}
		}
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	// o
	//---
	bOver=false;
	while(!bOver){
		bOver=true;
		for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
			for (int i =pDoc->EndPoint.y-1 ; i >pDoc->StartPoint.y; i --){
				lpDst=lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ j;;	
				if(*lpDst == TWOVALUE_L)
					if (*(lpDst-1-lLineBytes) ==TWOVALUE_H && *(lpDst-lLineBytes) ==TWOVALUE_H && *(lpDst+1- lLineBytes) ==TWOVALUE_H)
					{
						*lpDst = TWOVALUE_H;
						lpDst=lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ j;;	
						*lpDst = TWOVALUE_H;
						bOver=false;
					}
			}
		}
	}

	CString str=pDoc->GetTitle();
	DisplayNewImg(lpNewDIBBits1,lLineBytes,lHeight,str+"凸壳");//

	EndWaitCursor();	


	// 释放内存
	delete []lpNewDIBBits;
	delete []lpNewDIBBits1;
}

void CImageProcessView::OnUpdateApplicationConvexhull(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}

//利用8结构进行击中运算,重复直到没有改变
//删除击中点
//不是单像数,利用保持连通性的结构删除多余像数

void CImageProcessView::OnApplicationThin()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	// 更改光标形状
	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//击中 0--0   1---1  2--X(0\1)
	// 3×3的结构元素
	int B[8][9] = {
		{ 0, 0, 0,
		2, 1, 2,
		1, 1, 1},
		{ 2, 0, 0,
		1, 1, 0,
		1, 1, 2},
		{ 1, 2, 0,
		1, 1, 0,
		1, 2, 0},
		{ 1, 1, 2,
		1, 1, 0,
		2, 0, 0},
		{ 1, 1, 1,
		2, 1, 2,
		0, 0, 0},
		{ 2, 1, 1,
		0, 1, 1,
		0, 0, 2},
		{ 0, 2, 1,
		0, 1, 1,
		0, 2, 1},
		{ 0, 0, 2,
		0, 1, 1,
		2, 1, 1},
	};
	BOOL bOver=false;
	while(!bOver){
		bOver=true;
		for(int si=0;si<8;si++){	
			for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
				lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
				lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
				for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){

					lpDst++;lpSrc++;						
					if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
						if(*lpSrc == TWOVALUE_H) //
						{   bool bchg=true;
						for (int m = 0; m < 3; m++)
						{
							for (int n = 0; n < 3; n++)
							{
								if (B[si][m *3+ n] == 2)
									continue;
								else
									if (B[si][m *3+ n] == 0){
										if (*(lpSrc + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_H)
										{
											bchg=false;
											m=3;n=3;//out
										}
									}
									else
										if (B[si][m *3+ n] == 1)
											if (*(lpSrc + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_L)
											{
												bchg=false;
												m=3;n=3;//out
											}

							}
						}
						if(bchg) {
							*lpDst = TWOVALUE_L;
							bOver=false;
						}
						}

					}
				}

			}

			//
			lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
			memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);

		}
	}

	//	不是单像数,删除多余像数

	//m-connectivity
	int B4[4][9] = {
		{ 0, 1, 2,
		1, 1, 0,
		2, 0, 0},
		{ 2, 1, 0,
		0, 1, 1,
		0, 0, 2},
		{ 0, 0, 2,
		0, 1, 1,
		2, 1, 0},
		{ 2, 0, 0,
		1, 1, 0,
		0, 1, 2}
	};
	for(int si=0;si<4;si++){	
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpDst =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpDst++;						
				if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
					if(*lpDst == TWOVALUE_H) //
					{   bool bchg=true;
					for (int m = 0; m < 3; m++)
					{
						for (int n = 0; n < 3; n++)
						{
							if (B4[si][m *3+ n] == 2)
								continue;
							else
								if (B4[si][m *3+ n] == 0){
									if (*(lpDst + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_H)
									{
										bchg=false;
										m=3;n=3;//out
									}
								}
								else
									if (B4[si][m *3+ n] == 1)
										if (*(lpDst + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_L)
										{
											bchg=false;
											m=3;n=3;//out
										}

						}
					}
					if(bchg) 
						*lpDst = TWOVALUE_L;
					}

				}
			}

		}
	}

	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"击中击不中-细化");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	EndWaitCursor();	


	// 释放内存
	delete []lpNewDIBBits;

}

void CImageProcessView::OnUpdateApplicationThin(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}

//细化后图像有毛刺,利用选择的模板进行3次细化,去除小毛刺,同时对端点处影响
//获取端点,在此处进行膨胀,与原图取交集恢复端点处,如毛刺距端点处大于3则消除
void CImageProcessView::OnApplicationPruned()
{
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	unsigned char*	lpNewDIBBits1;
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return ;
	}
	// 更改光标形状
	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);
	memcpy( lpNewDIBBits1,lpSrc, lLineBytes * lHeight);

	//细化
	//击中 0--0   1---1  2--X(0\1)
	// 3×3的结构元素
	int B[8][9] = {
		{ 2, 0, 0,
		1, 1, 0,
		2, 0, 0},
		{ 2, 1, 2,
		0, 1, 0,
		0, 0, 0},
		{ 0, 0, 2,
		0, 1, 1,
		0, 0, 2},
		{ 0, 0, 0,
		0, 1, 0,
		2, 1, 2},
		{ 1, 0, 0,
		0, 1, 0,
		0, 0, 0},
		{ 0, 0, 1,
		0, 1, 0,
		0, 0, 0},
		{ 0, 0, 0,
		0, 1, 0,
		0, 0, 1},
		{ 0, 0, 0,
		0, 1, 0,
		1, 0, 0},
	};

	//去除3点毛刺
	int  Num=3;
	while(Num){
		Num--;
		for(int si=0;si<8;si++){	
			for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
				lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
				lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
				for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
					lpDst++;lpSrc++;						
					if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
						if(*lpSrc == TWOVALUE_H) //
						{   bool bchg=true;
						for (int m = 0; m < 3; m++)
						{
							for (int n = 0; n < 3; n++)
							{
								if (B[si][m *3+ n] == 2)
									continue;
								else
									if (B[si][m *3+ n] == 0){
										if (*(lpSrc + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_H)
										{
											bchg=false;
											m=3;n=3;//out
										}
									}
									else
										if (B[si][m *3+ n] == 1)
											if (*(lpSrc + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_L)
											{
												bchg=false;
												m=3;n=3;//out
											}

							}
						}
						if(bchg) 
							*lpDst = TWOVALUE_L;
						}

					}
				}

			}

			//
			lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
			memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);

		}
	}

	//set 0
	memset(pDoc->m_pDib->m_lpImage,0, lLineBytes * lHeight);			

	//获取端点 
	//lpNewDIBBits---X1=A细化{B}
	//pDoc->m_pDib->m_lpImage--端点X2=X1击中{B}
	for(int si=0;si<8;si++){	
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpSrc = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			lpDst = pDoc->m_pDib->m_lpImage+ lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpDst++;lpSrc++;	
				if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
					if(*lpSrc == TWOVALUE_H) //
					{   bool bchg=true;
					for (int m = 0; m < 3; m++)
					{
						for (int n = 0; n < 3; n++)
						{
							if (B[si][m *3+ n] == 2)
								continue;
							else
								if (B[si][m *3+ n] == 0){
									if (*(lpSrc + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_H)
									{
										bchg=false;
										m=3;n=3;//out
									}
								}
								else
									if (B[si][m *3+ n] == 1)
										if (*(lpSrc + lLineBytes*(1 - m) +(n - 1) ) ==TWOVALUE_L)
										{
											bchg=false;
											m=3;n=3;//out
										}

						}
					}
					if(bchg) 
						*lpDst = TWOVALUE_H;
					}
				}
			}
		}
	}

	//膨胀3次

	// 3×3的结构元素
	int **S;
	int M=3;
	int N=3;
	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=1;

	Dilation(S,M,N,TWOVALUE_H,TWOVALUE_L);
	Dilation(S,M,N,TWOVALUE_H,TWOVALUE_L);
	Dilation(S,M,N,TWOVALUE_H,TWOVALUE_L);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;

	//端点延伸3次U X1
	unsigned char * lpSrc1;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = lpNewDIBBits1 +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc1 = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst = pDoc->m_pDib->m_lpImage+ lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpDst++;lpSrc++;
			if(*lpDst){
				if(!(*lpSrc)) *lpDst=TWOVALUE_L;
			}
			(*lpSrc1)|=(*lpDst);
		}
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy(lpSrc, lpNewDIBBits1, lLineBytes * lHeight);

	CString str=pDoc->GetTitle();
	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"裁剪");//


	EndWaitCursor();	


	// 释放内存
	delete []lpNewDIBBits;
	delete []lpNewDIBBits1;


}

void CImageProcessView::OnUpdateApplicationPruned(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}

void CImageProcessView::OnGrayDilation()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=0;

	GrayDilation(S,M,N);


	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"膨胀运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}

void CImageProcessView::OnUpdateGrayDilation(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnGrayErosion()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=0;

	GrayErosion(S,M,N);


	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"腐蚀运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}

void CImageProcessView::GrayDilation(int** S, int M, int N)
{
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		return ;
	}



	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	膨胀运算
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			for (int m = 0; m < M; m++)
			{
				for (int n = 0; n < N; n++)
				{   if(S[m][n]<0) continue;
				if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth){
					int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2))+S[m][n];
					if(tmp>gray) gray=tmp;//max
				}
				}
			}
			if(gray>255) gray=255;
			*lpDst=(BYTE)gray;

		}
	}

	// 释放内存
	delete []lpNewDIBBits;

}
void CImageProcessView::GrayErosion(int** S, int M, int N)
{
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		return ;
	}



	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//腐蚀运算,定义域内输入数据减对应模板数据,并求最小值,该最小值便是该点输出
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			for (int m = 0; m < M; m++)
			{
				for (int n = 0; n < N; n++)
				{   if(S[m][n]<0) continue;
				if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth)
				{
					int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2))-S[m][n];
					if(tmp<gray) gray=tmp;//min

				}
				}
			}

			*lpDst=(BYTE)gray;

		}
	}


	// 释放内存
	delete []lpNewDIBBits;

}
void CImageProcessView::OnUpdateGrayErosion(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnGrayOpen()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=0;

	GrayErosion(S,M,N);
	GrayDilation(S,M,N);


	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"开运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}

void CImageProcessView::OnUpdateGrayOpen(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here	
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnGrayClose()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=0;

	GrayDilation(S,M,N);

	GrayErosion(S,M,N);


	CString str=pDoc->GetTitle();

	pDoc->SetTitle(str+"闭运算");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}

void CImageProcessView::OnUpdateGrayClose(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnGrayGradient()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpNewDIBBits1;
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits1 == NULL)
	{
		return ;
	}

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=0;

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits1,lpSrc, lLineBytes * lHeight);

	GrayDilation(S,M,N);

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//load
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy(lpSrc, lpNewDIBBits1, lLineBytes * lHeight);

	GrayErosion(S,M,N);


	//形态学梯度为膨胀的结果减腐蚀的结果

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			*lpDst=max(*lpDst-*lpSrc,0);

		}
	}


	CString str=pDoc->GetTitle();

	DisplayNewImg(lpNewDIBBits, lLineBytes ,lHeight,str+"形态学梯度");

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy(lpSrc, lpNewDIBBits1, lLineBytes * lHeight);

	// 释放内存
	delete []lpNewDIBBits;
	delete []lpNewDIBBits1;

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;

}

void CImageProcessView::OnUpdateGrayGradient(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnGrayTophat()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	const int M=3;
	const int N=3;

	// 3×3的结构元素
	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}
	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
			S[i][j]=0;

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);


	GrayErosion(S,M,N);
	GrayDilation(S,M,N);


	//原图减开运算的结果

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			*lpSrc=max(*lpDst-*lpSrc,0);

		}
	}


	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage, lLineBytes ,lHeight,str+"Top-hat变换");

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);

	// 释放内存
	delete []lpNewDIBBits;

	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;
}

void CImageProcessView::OnUpdateGrayTophat(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

//获取梯度大小,低2位包含方向信息 0| 、1\、 2--、 3/
//存放于原图,可以调用
void CImageProcessView::OnEdgeSobel()
{
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	int pixel[8];
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc  =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;			
			if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
				pixel[0] = (int)*(lpSrc+lLineBytes-1);
				pixel[1] = (int)*(lpSrc+lLineBytes);
				pixel[2] = (int)*(lpSrc+lLineBytes+1);
				pixel[3] = (int)*(lpSrc-1);
				pixel[4] = (int)*(lpSrc+1);
				pixel[5] = (int)*(lpSrc - lLineBytes-1);
				pixel[6] = (int)*(lpSrc - lLineBytes);
				pixel[7] = (int)*(lpSrc - lLineBytes+1);
				//  1   2   1
				//  0   0   0
				// -1  -2  -1

				int tmp1=pixel[0]+2*pixel[1]+pixel[2]-pixel[5]-2*pixel[6]-pixel[7];

				//  -1   0   1
				//  -2   0   2
				//  -1   0   1
				int tmp2=pixel[2]+2*pixel[4]+pixel[7]-pixel[0]-2*pixel[3]-pixel[5];

				int result =(int)(sqrt(double(tmp1*tmp1+tmp2*tmp2))+0.5);//>>255 
				if(result>255) result=255;
				*lpDst = (unsigned char)result;
				//add edge infomation
				*lpDst&=0xfc;
				if(tmp2==0) tmp2=1;
				double tha=atan((double(tmp1))/tmp2);
				//if(result>10)
				//	TRACE("\n %3.2f",tha);
				if(abs(tha)<Pi/8)//   |  0
					*lpDst=*lpDst;
				else
					if(tha>Pi/8 && tha<Pi*3/8)//  \   1
						*lpDst=*lpDst+1;
					else
						if(tha<-Pi/8 && tha>-Pi*3/8)//  /  3
							*lpDst=*lpDst+3;
						else                   //  -    2
							*lpDst=*lpDst+2;
			}else *lpDst=0;
		}
	}

	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"--Sobe");
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	// 恢复光标
	EndWaitCursor();	

	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdateEdgeSobel(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

//显示-127---127(0--128)
//高值反映边缘偏亮处、低值为边缘偏暗处,不显示边缘处(过零点)
//跳跃变换如二值图像无过零点
void CImageProcessView::OnEdgeLaplace()
{
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	int pixel[8];
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;			
			if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
				pixel[0] = (int)*(lpSrc+lLineBytes-1);
				pixel[1] = (int)*(lpSrc+lLineBytes);
				pixel[2] = (int)*(lpSrc+lLineBytes+1);
				pixel[3] = (int)*(lpSrc-1);
				pixel[4] = (int)*(lpSrc+1);
				pixel[5] = (int)*(lpSrc - lLineBytes-1);
				pixel[6] = (int)*(lpSrc - lLineBytes);
				pixel[7] = (int)*(lpSrc - lLineBytes+1);
				//   -1   -1  -1
				//   -1   8   -1 
				//   -1   -1  -1
				int Tmp=0;
				for(int k=0;k<8;k++)
					Tmp+=pixel[k];
				Tmp=8*((int)*lpSrc)-Tmp;

				Tmp+=128;
				//Tmp=abs(Tmp);
				if(Tmp>255) Tmp=255;
				if(Tmp<0) Tmp=0;

				*lpDst=(BYTE)Tmp;

			}else *lpDst=128;
		}
	}

	CString str=pDoc->GetTitle();
	DisplayNewImg(lpNewDIBBits, lLineBytes ,lHeight,"--Laplace");
	// 恢复光标
	EndWaitCursor();	

	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdateEdgeLaplace(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

// LOG
void CImageProcessView::OnEdgeLog()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	unsigned char*	lpDst;


	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);
	const int M=11;
	const int N=11;

	float **H;

	H =  new float * [M];

	for (int i = 0; i < M; i++) {
		H[i] = new float[N] ;
	}

	/*
	H[2][2]=16;
	H[2][1]=H[1][2]=H[2][3]=H[3][2]=-2;
	H[0][2]=H[2][0]=H[4][2]=H[2][4]=-1;
	H[1][1]=H[3][1]=H[1][3]=H[3][3]=-1;*/


	float sigma=.8f;
	float fsum=0.0f;



	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
		{
			float ftmp=((i-M/2)*(i-M/2)+(j-N/2)*(j-N/2))/(sigma*sigma);
			H[i][j]=(ftmp-2)/(sigma*sigma)*exp(-ftmp/2);
			fsum+=H[i][j];
		}
		for (int i = 0; i < M; i++) 
		{  // TRACE("\n");
			for (int j = 0; j < N; j++)
			{
				H[i][j]/=fsum;
				//	TRACE("%3.2f\t",H[i][j]);
			}
		}

		MaskCount(H,M,N,true);

		CString str=pDoc->GetTitle();
		DisplayNewImg(pDoc->m_pDib->m_lpImage, lLineBytes ,lHeight,str+"--LOG");

		lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
		memcpy( lpSrc,lpNewDIBBits, lLineBytes * lHeight);

		DisplayNewImg(pDoc->m_pDib->m_lpImage, lLineBytes ,lHeight,str);

		//判断过零点
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpSrc++;lpDst++;			
				if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
					int v=*lpDst+*(lpDst-1)+*(lpDst+lLineBytes)+*(lpDst-1+lLineBytes)-4*128;
					int min=v;
					int max=v;
					v=*lpDst+*(lpDst+1)+*(lpDst+lLineBytes)+*(lpDst+1+lLineBytes)-4*128;
					if(v>max)max=v;
					else if(v<min) min=v;
					v=*lpDst+*(lpDst-1)+*(lpDst-lLineBytes)+*(lpDst-1-lLineBytes)-4*128;
					if(v>max)max=v;
					else if(v<min) min=v;
					v=*lpDst+*(lpDst+1)+*(lpDst-lLineBytes)+*(lpDst+1-lLineBytes)-4*128;
					if(v>max)max=v;
					else if(v<min) min=v;

					if(max>=0 && min<=0)
						*lpSrc=0x80;
					else
						*lpSrc=0;
				}
				else *lpSrc=0;
			}
		}

		pDoc->SetTitle(str+"--LOG过零点");
		InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);


		// 恢复光标
		EndWaitCursor();	

		// 释放内存
		delete []lpNewDIBBits;
		for(int i=0;i<M;i++)
			delete []H[i];
		delete []H;

}

void CImageProcessView::OnUpdateEdgeLog(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::MaskCount(float** H,int M,int N,bool bEdge)
{
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;			
			if(i>=N/2 && i<lHeight-N/2 && j>=M/2 && j<lWidth-M/2){
				float Tmp=0.0f;
				for(int m=0;m<M;m++)
					for(int n=0;n<N;n++)
						Tmp+=*(lpSrc+lLineBytes*(N/2-n)+m-M/2)*H[m][n] ; 
				if(bEdge) Tmp+=128;
				if(Tmp>255) Tmp=255;
				if(Tmp<0) Tmp=0;

				*lpDst=(unsigned char)Tmp;

			}else *lpDst=0;
		}
	}

	// 释放内存
	delete []lpNewDIBBits;

}

//获取直线参数(最大值),删除该值附近值,再取最大值为下一条直线
//显示直线为图像点为边缘且满足方向的约束,若无满足点查看邻域(1,-1)是否满足,可去掉一些断点,
//对于角度变化求可能的距离,故速度较快,不考虑方向对角度的限制,提高速度有限
//针对一般图像OnEdgeLog();
//二值Sobel边缘-细化后运行
//图像较大时,由于原点(0,0) 误差较大,改为(cx/2,cy/2)

void CImageProcessView::OnHoughLines()
{
	// TODO: Add your command handler code here

	CImageProcessDoc* pDoc = GetDocument();
	BeginWaitCursor();

	//1 save image	
	unsigned char*	lpSrc;
	unsigned char*	lpDst;
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	for (int i =0; i <lHeight; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) -1;
		lpDst = lpNewDIBBits +  lLineBytes* (lHeight-1-i) -1;
		for (int j =0; j <lWidth; j ++){
			lpSrc++;lpDst++;
			*lpDst=*lpSrc;
			if(*lpDst>=220) *lpDst=220;//  for display line
		}
	}


	//2 Get edge
	if(!m_bTwoValue)
		OnEdgeLog();
	else
		OnEdgeSobel();

	//3 Hough transform

	//极半径检测分辨率和角度检测分辨率
	int radiusResolution=2;
	int angleResolution=1;

	//线与原点的距离最大
	int houghWidth=(int)(sqrt((double)(lWidth*lWidth+lHeight*lHeight)));//+/-
	houghWidth /= radiusResolution;

	//线的角度在[-90,90]之间,所以申请的累加数组高度为181/angleResolution
	int houghHeight=181/angleResolution;

	//申请累加数组缓冲区
	int *houghBuf=new int[houghWidth*houghHeight];

	//init  
	//清理变换空间累加数组
	for(int i=0;i<houghHeight;i++){
		for(int j=0;j<houghWidth;j++){
			*(houghBuf+i*houghWidth+j)=0;
		}
	}

	const double Deg_Rad=3.1415926/180;
	//遍历图像数据
	for (int i =max(pDoc->StartPoint.y,1); i <=pDoc->EndPoint.y; i ++){//start: 1
		// 指向源图像倒数第j行,第i个象素的指针
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + max(pDoc->StartPoint.x,1)-1;
		// 针对每行图像每列进行操作
		for (int j =max(pDoc->StartPoint.x,1); j <=pDoc->EndPoint.x; j ++){
			// 指向源DIB第i行,第j个象素的指针
			lpSrc++;
			//如果是edge,则在变换域的对应各点上加1

			if(*lpSrc>=TWOVALUE_H)
				//if(i+j==500 && j>=200 && j<=300 )
			{
				//出现一个目标点
				//a代表角度的循环变量,在变换空间累加数组的垂直方向上
				for(int a=0;a<houghHeight;a++){

					//按照给定变换角度的分辨率,求取角度
					double tempA=Deg_Rad*(a-houghHeight/2)*angleResolution;

					//double tempA=Deg_Rad*(a)*angleResolution;

					//可以建立表,查表;提高速度
					//根据当前遍历的角度及x,y值求取对应极半径
					double tempR=(i*cos(tempA)+j*sin(tempA))/radiusResolution;//r=xcosa+ysina

					//double tempR=((i-houghHeight/2)*cos(tempA)+(houghWidth/2-j)*sin(tempA))/radiusResolution;//r=xcosa+ysina

					//与冈萨雷斯书一致,与习惯不同
					int r;
					if(tempR>0)
						r=(int)(tempR+0.5);
					else
						r=(int)(tempR-0.5);

					if(r>=-houghWidth/2 && r<houghWidth/2)
						//累加数组累加
						*(houghBuf+a*houghWidth+r+houghWidth/2)+=1;//[r][a]
				}
			}
		}
	}



	//4.save for display Hough Result
	int line=houghWidth/4*4;
	unsigned char  *pHoughImg=new unsigned char[line*houghHeight];
	memset(pHoughImg,0,line*houghHeight);
	for(int r=0;r<line;r++){
		for(int a=0;a<houghHeight;a++){
			if(*(houghBuf+a*houghWidth+r)>255)
				*(pHoughImg+(houghHeight-a-1)*line+r)=255;
			else
				*(pHoughImg+(houghHeight-a-1)*line+r)=(BYTE)(*(houghBuf+a*houghWidth+r));
		}
	}

	//display center
	for(int i=-5;i<=5;i++)
		*(pHoughImg+(houghHeight/2)*line+houghWidth/2+i)=255;
	for(int i=-5;i<=5;i++)
		*(pHoughImg+(houghHeight/2+i)*line+houghWidth/2)=255;


	DisplayNewImg(pHoughImg, line ,houghHeight,"HoughImg:a:(-90,90) r:(-rMax/2,rMax/2)");


	//5 累加数组的极大值

	const int N_MaxVal=60;
	vector< LineInfo> L_Info;

	for(int a=5;a<houghHeight;a++){//-90 r == 90 -r 
		for(int r=0;r<houghWidth;r++){
			if(*(houghBuf+a*houghWidth+r)>N_MaxVal){
				bool btrue=true;
				//判断极值
				for(int m=-2;m<=2;m++)
				{  
					for(int n=-2;n<=2;n++)//
					{
						if(m==0 && n==0)
							continue;
						if(a+n>=0 && a+n<houghHeight && r+m>=0 && r+m<houghWidth) {
							if(*(houghBuf+(a+n)*houghWidth+r+m)>*(houghBuf+a*houghWidth+r))
							{
								btrue=false;
								break;
							}
							else
								if(*(houghBuf+(a+n)*houghWidth+r+m)==*(houghBuf+a*houghWidth+r))
									*(houghBuf+(a+n)*houghWidth+r+m)=*(houghBuf+(a+n)*houghWidth+r+m)-1;

						}
					}
					if(!btrue)
						break;
				}
				if(btrue){
					LineInfo line;
					line.pt=CPoint((a-houghHeight/2)*angleResolution,(r-houghWidth/2)*radiusResolution);
					//line.pt=CPoint((a)*angleResolution,(r-houghWidth/2)*radiusResolution);
					line.num=*(houghBuf+a*houghWidth+r);
					L_Info.push_back(line);
				}
			}
		}
	}

	//sort
	TRACE("\n Edge Infomation:\n");
	if(L_Info.size()){
		for(int i=0;i<(int)L_Info.size()-1;i++)
		{   
			for(int j=i+1;j<(int)L_Info.size();j++)	
				if(L_Info[i].num<L_Info[j].num)
				{
					LineInfo line;
					line=L_Info[i];
					L_Info[i]=L_Info[j];
					L_Info[j]=line;
				}
		}

		for(int i=0;i<(int)L_Info.size() && i<100;i++)
		{
			CString str;
			str.Format("%d: (R: %d  theta: %d  MaxNum: %d)\n",
				i+1,L_Info[i].pt.y,	L_Info[i].pt.x,L_Info[i].num);
			TRACE("%s\n",str);
		}


		const int displayN=20;
		int no=0;
		for(int i=0;i<(int)L_Info.size() && no<displayN;i++)
		{
			no++;
			double angle=L_Info[i].pt.x;
			double radius=L_Info[i].pt.y;

			//angle的单位是度,此处转换为弧度进行计算
			double alfa=angle*Deg_Rad;
			if(angle<-45 || angle>45){

				for(int x= pDoc->StartPoint.y+1;x<pDoc->EndPoint.y-2;x++){//|
					int y=(int)(radius/sin(alfa)-x/tan(alfa)+0.5);
					if(y>pDoc->StartPoint.x && y<pDoc->EndPoint.x){
						lpSrc=pDoc->m_pDib->m_lpImage+lLineBytes* (lHeight-1-x) +y; 
						if(*lpSrc>=TWOVALUE_H || *(lpSrc+1)>=TWOVALUE_H || *(lpSrc-1)>=TWOVALUE_H)
							*(lpNewDIBBits+lLineBytes* (lHeight-1-x) +y)=220+(BYTE)no;//
					}
			 }
			}
			else{

				for( int y= pDoc->StartPoint.x+1;y<pDoc->EndPoint.x-2;y++){
					int x=(int)(radius/cos(alfa)-y*tan(alfa)+0.5);
					if(x>pDoc->StartPoint.y && x<pDoc->EndPoint.y){
						lpSrc=pDoc->m_pDib->m_lpImage+lLineBytes* (lHeight-1-x) +y; 
						if(*lpSrc>=TWOVALUE_H || *(lpSrc+lLineBytes)>=TWOVALUE_H || *(lpSrc-lLineBytes)>=TWOVALUE_H)
							*(lpNewDIBBits+lLineBytes* (lHeight-1-x) +y)=220+(BYTE)no;
					}
				}
			}

		}

	}	
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpSrc,lpNewDIBBits, lLineBytes * lHeight);

	lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
	for (int i=221;i<=255;i++)//
	{
		*(lpSrc+i*4+1)=((i-220)*20)%256;
		*(lpSrc+i*4)=(BYTE)max(255-(i-220)*20,0);
		*(lpSrc+i*4+2)=255;//(i-220)*20%255;
	}



	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"--Hough Lines");
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);


	// 释放内存
	delete []lpNewDIBBits;
	delete []houghBuf;
	delete []pHoughImg;

	// 恢复光标
	EndWaitCursor();	

}

void CImageProcessView::OnUpdateHoughLines(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}




//适应于多峰图像
void CImageProcessView::OnSegmentationRegiongrowing()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();
	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;
	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);
	unsigned char* lpSrc;

	stack <CPoint> ptStack;

	//1.获取种子点图像,取亮点(255)
	//set 0
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = lpNewDIBBits  +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			if(*lpSrc>254) {
				ptStack.push(CPoint(j,i)); //255 种子
				*lpSrc=TWOVALUE_H;     
			}else
				*lpSrc=0;
		}
	}

	//2.显示种子图像

	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,"种子");//display orignal image

	unsigned char* lpDst;
	const int DIFF=65;
	//3.邻域生长
	//栈出列,3x3邻域点未处理(0),若与种子点灰度差小则标记(TWOVALUE_H)、进栈;否则设访问过(0x1)
	while(!ptStack.empty()){
		CPoint Point;
		Point=ptStack.top();
		ptStack.pop();

		//set area
		for(int m=1;m>-2;m--)
			for(int n=1;n>-2;n--) {
				if(m!=0 || n!=0){
					int x=Point.x+m;
					int y=Point.y+n;
					if(y>=pDoc->StartPoint.y && y<=pDoc->EndPoint.y && x>=pDoc->StartPoint.x && x<=pDoc->EndPoint.x){
						lpDst =lpNewDIBBits  +  lLineBytes*(lHeight-1-y) + x;
						if(!(*lpDst)){//no visit
							lpSrc = pDoc->m_pDib->m_lpImage+  lLineBytes*(lHeight-1-y) + x;
							if(*lpSrc>255-DIFF){//
								//limit in  
								ptStack.push(CPoint(x,y));
								*lpDst=TWOVALUE_H;   
							}
						}
						(*lpDst)|= 0x1;//visted
					}
				}
			}

	}

	//4.显示结果
	CString str=pDoc->GetTitle();
	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,str+"区域生长");//display orignal image


	delete [] lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	

}

void CImageProcessView::OnUpdateSegmentationRegiongrowing(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnSegmentationWatershed()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	unsigned char*	pMarker;
	pMarker=new unsigned char [lLineBytes*lHeight];

	if (pMarker == NULL)
	{
		return ;
	}
	unsigned char* pOrgIMg;
	pOrgIMg=new unsigned char [lLineBytes*lHeight];

	if (pOrgIMg == NULL)
	{
		return ;
	}

	//save 
	memcpy( pOrgIMg,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);

	//获取目标亮度阈值(取大一些,保证每个目标都有值即可,无需一个目标一值)
	int Hist[256]={0};
	GetHistgram(Hist,false);
	int GrayTh=0;
	int tol=0;
	int size=(pDoc->EndPoint.y-pDoc->StartPoint.y+1)*(pDoc->EndPoint.x-pDoc->StartPoint.x+1);
	for(GrayTh=0;GrayTh<256;GrayTh++){
		tol+=Hist[GrayTh];
		if(tol>size*8/10) break;
	}


	//1)get edge
	OnEdgeSobel();
	//Filter
	GaussFilter(5,5,1.414);

	unsigned char* lpSrc;
	unsigned char* lpDst;

	//设置边界梯度为最大,防止物体在边界上(梯度=0)与背景混合
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			if(i==pDoc->StartPoint.y || i==pDoc->EndPoint.y || j==pDoc->StartPoint.x || j==pDoc->EndPoint.x){
				lpDst  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + j;
				*lpDst=255;//edge
			}

		}
	}

	DisplayNewImg(pDoc->m_pDib->m_lpImage, lLineBytes ,lHeight,"梯度Image");

	//初始化标记图置0,0代表未作标记的点(等待生长的点)
	memset(pMarker, 0, lLineBytes*lHeight);

	//2) set all lable is 0xff 
	//目标为亮,背景为暗,取目标内部区域为Marker(0xff),保证每个目标都有Marker点
	//目标的Marker点:梯度小且亮度大
	int GradientTh=40;


	TRACE("\nGradientTh=%d,GrayTh=%d\n",GradientTh,GrayTh);

	const int initLabel=0xff;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + j;
			lpDst = pOrgIMg +  lLineBytes* (lHeight-1-i) + j;
			if((*lpSrc<GradientTh) && (*lpDst >GrayTh))//目标内部
			{int min=*lpSrc; 
			for(int m=-1;m<2;m++)
				for(int n=-1;n<2;n++)
					if((*(lpSrc+m*lLineBytes+n))<min)
						min=*(lpSrc+m*lLineBytes+n);
			if(min<(*lpSrc-2) || min<5)
				*(pMarker+  lLineBytes*(lHeight-1-i) + j)=initLabel;
			}
		}
	}



	//设置边缘处判断为背景的点为:1
	for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
		for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
			if(i==pDoc->StartPoint.y+1 || i==pDoc->EndPoint.y-1 || j==pDoc->StartPoint.x+1 || j==pDoc->EndPoint.x-1){
				lpDst  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + j;
				lpSrc  =pOrgIMg + lLineBytes * (lHeight - 1 - i)+ j;
				if(*lpDst<GradientTh/2 && *lpSrc<GrayTh)
					*(pMarker+  lLineBytes*(lHeight-1-i) + j)=1;//back

			}
		}
	}




	//3 利用连通性标定
	//2、3...objectCount物体,消除了过小的目标(可能的噪声点) 


	int objectCount=1;

	bool bProcOver=false;
	while(!bProcOver){
		bProcOver=true;
		int No=0;
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
				lpSrc =pMarker + lLineBytes *(lHeight-1-i)+ j;
				if(*lpSrc==initLabel)
				{   objectCount++;
				*lpSrc=(BYTE)objectCount;//set first pt
				No++;
				bProcOver=false;
				break;
				}
			}
			if(!bProcOver)break;
		}

		if(bProcOver) break;
		bool bchg=true;

		while(bchg){
			bchg=false;

			for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
				for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
					lpSrc =pMarker + lLineBytes * (lHeight-1-i)+ j;
					if(*lpSrc==objectCount){
						for(int m=-1;m<2;m++)
							for(int n=-1;n<2;n++)
							{	if((*(lpSrc+m*lLineBytes+n))==initLabel){
								*(lpSrc+m*lLineBytes+n)=(BYTE)objectCount;
								No++;
								bchg=true;
							}
							}
					}
				}
			}
		}
		if(No<10){//面积过小,标注取消
			//delete all seed
			for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
				for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){ 
					lpSrc =pMarker + lLineBytes *(lHeight-1-i)+ j;
					if(*lpSrc==objectCount) *lpSrc=0;
				}
			}
			objectCount--;
			if(objectCount<0) objectCount=0;
		}

	}

	DisplayNewImg(pMarker, lLineBytes ,lHeight,"Marker Image");

	Watershed(pMarker,objectCount);

	DisplayNewImg(pOrgIMg, lLineBytes ,lHeight,"Origin Image");

	memcpy( pDoc->m_pDib->m_lpImage,pMarker, lLineBytes * lHeight);

	pDoc->SetTitle("Watershed");
	//如果粘连、或者一个目标多区域描述,可以进一步处理
	//将其二值化(门限>0),利用腐蚀、标注、条件膨胀可解决该问题,见物体分离

	DisplayObjLabel(objectCount); 


	EndWaitCursor();	

	delete []pMarker;
	delete []pOrgIMg;

}


//利用各个目标点与背景点(objectCount>0)对其邻域进行处理(相当于膨胀),
//其邻域梯度小(不大于当前值)就并入,否则待以后处理(梯度递增、相当于水位上升)
//利用队列确定梯度小的邻域先处理,每个目标同步处理,梯度小的未处理点(objectCount==0)并入最近的目标
//pMarkImg中所有点处理完为结果,1--表示背景,物体标识为2--objectCount+1
//可以不处理完,阈值上升到(例如128)一定时停止,这时其中还有位处理点(梯度较大),判断为背景
int CImageProcessView::Watershed(unsigned char* pMarkImg,int objectCount)
{
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char * lpSrc;
	unsigned char * lpDst;

	if(!objectCount){
		MessageBox("无区域种子!","Message");	
		return 0;
	}



	//int direct[8][2]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};



	//水域生长
	//每个种子同步生长,在交融处停止;标志区全部被标志
	for(int grad=2;grad<128;grad++){//256; 可以调整,大了浪费时间但没有问题
		for(int obj=1;obj<=objectCount;obj++){
			bool bchg=true;
			while(bchg){
				bchg=false;

				for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
					lpDst =pMarkImg  + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
					lpSrc =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
					for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){ 
						lpDst++;lpSrc++;
						if((*lpDst)==obj)
						{   
							for(int m=-1;m<2;m++)
								for(int n=-1;n<2;n++)
									if(*(lpDst+m*lLineBytes+n)==0)
										if((*(lpSrc+m*lLineBytes+n))<=grad){ 
											(*(lpDst+m*lLineBytes+n))=(BYTE)obj;
											bchg=true;
										}

						}
					}
				}
			}
		}
	}




	//obj-- ,0--back, 
	//未处理点置为背景
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
		{
			lpSrc =pMarkImg + lLineBytes * (lHeight-1-i)+ j;
			if(*lpSrc)
				*lpSrc=*lpSrc-1;
		}
	}


	return 0;
}

void CImageProcessView::DisplayObjLabel(int objectCount)
{
	//display color
	CImageProcessDoc* pDoc = GetDocument();

	int dstep=250/objectCount;
	unsigned char* lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
	for (int i=1;i<=objectCount;i++)//0 --back
	{
		*(lpSrc+i*4+1)=(BYTE)(i*dstep);
		*(lpSrc+i*4)=(BYTE)(255-i*dstep);
		*(lpSrc+i*4+2)=(BYTE)((i*20)%256);
	}

	//get character
	long int *pArea;

	pArea=new long int [objectCount+1];
	for(int i=0;i<=objectCount;i++)
		pArea[i]=0;

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
		{ 
			if(*lpSrc>objectCount) continue;//前面可以不做完,有255
			pArea[*lpSrc]++;
			lpSrc++;
		}
	}
	long int min=1000;
	long int max=0;
	long int total=0;

	CString str;
	str="\n\tNo\t\tArea";
	for(int i=1;i<objectCount;i++)//1 --back
	{
		if(pArea[i]>max)
			max=pArea[i];
		if(pArea[i]<min)
			min=pArea[i];
		total+=pArea[i];
		CString str1;
		str1.Format("\n\t%3d:\t\t%d",i,pArea[i]);
		str+=str1;

	}

	//int aver=total/(objectCount-1);



	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);


	MessageBox(str);


	delete []pArea;
}

void CImageProcessView::OnUpdateSegmentationWatershed(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnApplicationThinbycondition()
{
	// TODO: Add your command handler code here

	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	// 更改光标形状
	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	// 3×3相邻区域像素值
	unsigned char S[3][3];
	bool bOver=false;
	while (!bOver)
	{
		bOver = true;
		for(int kk=0;kk<2;kk++){//do step1/step2
			for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
				lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
				lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
				for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
					lpDst++;lpSrc++;						
					// 如果源图像中当前点为Backgroung,则跳过
					if (*lpSrc==TWOVALUE_L)
						continue;
					if(i<1 || i>=lHeight-1 && j<1 && j>=lWidth-1)
						continue;
					// 获得当前点相邻的3×3区域内像素值,白色用1代表,黑色用0代表
					for (int m = 0; m < 3; m++)
					{
						for (int n = 0; n < 3; n++)
						{
							if (*(lpSrc +  (1-m)* lLineBytes  + n-1 ) >= TWOVALUE_H)
								S[m][n] = 1;
							else
								S[m][n] = 0;
						}
					}

					// 判断条件一是否成立:
					int Num =  S[0][0] + S[0][1] + S[0][2] + S[1][0] 
					+ S[1][2] + S[2][0]	+ S[2][1] + S[2][2];
					if (Num < 2 || Num >6)
					{
						continue;
					}
					// 判断条件二是否成立:
					Num = 0;
					if (S[0][1] == 0 && S[0][2] == 1) 
						Num++;
					if (S[0][2] == 0 && S[1][2] == 1)
						Num++;
					if (S[1][2] == 0 && S[2][2] == 1)
						Num++;
					if (S[2][2] == 0 && S[2][1] == 1)
						Num++;
					if (S[2][1] == 0 && S[2][0] == 1)
						Num++;
					if (S[2][0] == 0 && S[1][0] == 1)
						Num++;
					if (S[1][0] == 0 && S[0][0] == 1)
						Num++;
					if (S[0][0] == 0 && S[0][1] == 1)
						Num++;
					if (Num != 1)
					{
						continue;
					}

					if(kk==0){
						// 判断条件三是否成立;
						if (S[0][1] * S[1][2] * S[2][1] != 0)
							continue;

						// 判断条件四是否成立:
						if (S[1][2] * S[2][1] * S[1][0] != 0)
							continue;

					}
					else
					{	// 判断条件三是否成立;
						if (S[0][1] * S[1][2] * S[1][0] != 0)
							continue;

						// 判断条件四是否成立:
						if (S[0][1] * S[2][1] * S[1][0] != 0)
							continue;
					}
					// 如果条件均满足则标注该点
					*lpDst = 0;
					bOver= false;
				}
			}
			//删除所有标注点
			if(!bOver){
				lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
				memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);
			}
		}
	}
	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"条件-细化");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	EndWaitCursor();	


	// 释放内存
	delete []lpNewDIBBits;

}

void CImageProcessView::OnUpdateApplicationThinbycondition(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}

//获取模板,可调用图像或在图中选择区域
//计算相关系数并显示(-1,1)为(0,255)
//可以方便的利用系数门限确定是否匹配,未做
void CImageProcessView::OnObjectrecognitionCorrelationmatch()
{
	// TODO: Add your command handler code here

	CImageProcessDoc* pDoc = GetDocument();
	BeginWaitCursor();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memset( lpNewDIBBits,0, lLineBytes * lHeight);

	int tol=0;
	for (int m = 0; m <m_ModelHeight; m++)
		for (int n =0; n <m_ModelWidth; n++)
			tol+=m_pModelData[m*m_ModelWidth+n];
	int size=m_ModelHeight*m_ModelWidth;
	int ModelMean=tol/size;

	int ModelSigm2=0;
	for (int m = 0; m <m_ModelHeight; m++)
		for (int n =0; n <m_ModelWidth; n++)
			ModelSigm2+=((m_pModelData[m*m_ModelWidth+n]-ModelMean)*(m_pModelData[m*m_ModelWidth+n]-ModelMean));

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;						
			if(i-m_ModelHeight/2<0 || i+m_ModelHeight/2>lHeight-1 || j-m_ModelWidth/2<0 || j+m_ModelWidth/2>lWidth-1)
				continue;

			tol=0;
			for (int m = -m_ModelHeight/2; m <=m_ModelHeight/2; m++)
				for (int n = -m_ModelWidth/2; n <=m_ModelWidth/2; n++)
					tol+=*(lpSrc-m*lLineBytes+n);
			int ImgMean=tol/size;

			int ImgSigm2=0;
			int ImgModel=0;
			for (int m = -m_ModelHeight/2; m <=m_ModelHeight/2; m++){
				for (int n = -m_ModelWidth/2; n <=m_ModelWidth/2; n++){
					ImgSigm2+=((*(lpSrc-m*lLineBytes+n)-ImgMean)*(*(lpSrc-m*lLineBytes+n)-ImgMean));
					ImgModel+=((*(lpSrc-m*lLineBytes+n)-ImgMean)*(m_pModelData[(m+m_ModelWidth/2)*
						m_ModelWidth+n+m_ModelWidth/2]-ModelMean));
				}

			}
			double r;
			r=((double)ImgModel)/sqrt((double)ImgSigm2*ModelSigm2);
			*lpDst=(BYTE)min((int)(128+r*128),255);
		}
	}

	//display
	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,"相关系数(-1,1)-(0,255)");//display orignal image


	// 恢复光标
	EndWaitCursor();	

	delete [] lpNewDIBBits;
}

void CImageProcessView::OnUpdateObjectrecognitionCorrelationmatch(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			if(m_pModelData)
				bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnMorphologicalDistancetransform()
{
	// TODO: Add your command handler code here

	CImageProcessDoc* pDoc = GetDocument();
	BeginWaitCursor();

	unsigned char*	lpSrc;
	int*	lpDst;

	int* pDist;
	pDist=new int [lLineBytes*lHeight];
	if (pDist == NULL)
	{
		return ;
	}

	Distance(pDist);


	//display
	int MaxDist=0;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =pDist + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;	
			if(*lpDst) {
				//*lpDst/=3;
				if(*lpDst>MaxDist) MaxDist=*lpDst;
				if(*lpDst>255) *lpSrc=255;
				else *lpSrc=(BYTE)*lpDst;
			}
		}
	}

	lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
	for (int i=1;i<=min(MaxDist,255);i++)
	{
		*(lpSrc+i*4+1)=(i/2%10)*25;*(lpSrc+i*4)=(10-i/2%10)*25;*(lpSrc+i*4+2)=(i/2%6)*50;
	}

	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"距离");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
	EndWaitCursor();	


	// 释放内存
	delete [] pDist;
}

void CImageProcessView::OnUpdateMorphologicalDistancetransform(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}
//设置背景距离为0 物体为大值
//顺序扫描,利用邻域值修正(+3,+4 近似欧几里得距离)取最小值改变当前距离值
//再次反向扫描,修改距离
//其值为3倍像数点值

void CImageProcessView::Distance(int * pDist){

	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	int*	lpDst;

	//init 0,max
	const int max=10000;//
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =pDist + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;	
			if(*lpSrc) *lpDst=max;
			else *lpDst=0;
		}
	}

	const int d1=3;//Euclidean
	const int d2=4;


	//do left--right top--down
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst =pDist + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpDst++;
			if(*lpDst){
				int Min=*lpDst;
				//d2 d1 d2
				//d1 0
				if(i>0)           Min=min(Min,*(lpDst+lLineBytes)+d1);
				if(j>0)           Min=min(Min,*(lpDst-1)+d1);
				if(i>0 && j>0)    Min=min(Min,*(lpDst+lLineBytes-1)+d2);
				if(i>0 && j<lWidth-1)Min=min(Min,*(lpDst+lLineBytes+1)+d2);

				//set label
				*(lpDst)=Min;

			}
		}

	}

	//do right--left down--top
	for (int i =pDoc->EndPoint.y; i >=pDoc->StartPoint.y; i --){
		for (int j =pDoc->EndPoint.x; j>=pDoc->StartPoint.x; j --){ 
			lpDst =pDist + lLineBytes * (lHeight - 1 - i)+ j;


			if(*lpDst){
				int Min=*lpDst;
				//    0 d1
				//d2 d1 d2
				if(i<lHeight-1)           Min=min(Min,*(lpDst-lLineBytes)+d1);
				if(j<lWidth-1)           Min=min(Min,*(lpDst+1)+d1);
				if(i<lHeight-1 && j>0)    Min=min(Min,*(lpDst-lLineBytes-1)+d2);
				if(i<lHeight-1 && j<lWidth-1)Min=min(Min,*(lpDst-lLineBytes+1)+d2);

				//set label
				*(lpDst)=Min;

			}
		}

	}


}
void CImageProcessView::OnApplicationSeparateobject()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	//	int Obj=TWOVALUE_H;
	int Back=TWOVALUE_L;

	const int M=31;
	const int N=31;
	const int r=15;

	int **S;

	S =  new int * [M];

	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}

	for (int i = 0; i < M; i++){ 
		for (int j = 0; j < N; j++)
			if((i-M/2)*(i-M/2)+(j-N/2)*(j-N/2)<r*r)
				S[i][j]=1;
			else S[i][j]=0;
	}


	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);

	//1)腐蚀
	Erosion(S,M,N,Back);

	DisplayNewImg( pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,"种子图像");


	//2) 标记

	int ObjNum=Connectedcomponents();

	//3)条件膨胀
	int obj=-1;
	unsigned char* lpSrc;
	unsigned char* lpDst;
	unsigned char* lpDst1;
	unsigned char*	lpNewDIBBits1;
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits1 == NULL)
		return ;
	memcpy( lpNewDIBBits1,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		lpDst1 =lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;lpDst1++;
			if ((*(lpSrc) !=Back) && (*(lpDst) ==Back)){//原图像有值
				bool bObj=false;
				for (int m = 0; m < M; m++){
					for (int n = 0; n < N; n++){
						if (S[m][n] == 0)
							continue;
						if(i+m-M/2>=0 && i+m-M/2<lHeight && j+n -N/2>=0 && j+n-N/2<lWidth)//图像内
							if (*(lpDst1 - lLineBytes*(m-M/2)  +(n-N/2) ) !=Back)//有非背景点
							{   bObj=true;
						obj=*(lpDst1 + lLineBytes*(M/2 - m)  +(n - N/2));//取当前标记值
						m=M;n=N;//out
						}

					}

				}
				if(bObj) *lpDst=(BYTE)obj;//设置该目标点为判断的标记值,若多个标记相连,取首个,不同于水域分割,同时生长,也可多次小范围膨胀
			}
		}

	}

	//4 显示结果
	DisplayObjLabel(ObjNum+1);
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	DisplayNewImg( lpNewDIBBits,lLineBytes,lHeight,"原图像");


	// 恢复光标
	EndWaitCursor();	

	delete [] lpNewDIBBits;
	delete [] lpNewDIBBits1;
	for(int i=0;i<M;i++)
		delete []S[i];
	delete []S;


}

void CImageProcessView::OnUpdateApplicationSeparateobject(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}


void CImageProcessView::OnWatershedprocessGetseed()
{
	// TODO: Add your command handler code here
	if(m_pModelData)//have image
	{
		CImageProcessDoc* pDoc = GetDocument();
		unsigned char *lpSrc;
		unsigned char *lpDst;
		unsigned char *lpDst1;
		unsigned char*	lpNewDIBBits;
		lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
		if (lpNewDIBBits == NULL)
			return ;
		memcpy( lpNewDIBBits,m_pModelData, lLineBytes * lHeight);
		memset( m_pModelData,0, lLineBytes * lHeight);
		const int GradientTh=30;
		const int GrayTh=100;
		int max=0;
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
				lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + j;
				lpDst = m_pModelData +  lLineBytes* (lHeight-1-i) + j;
				lpDst1 = lpNewDIBBits +  lLineBytes*i + j;//area, not bmp
				if(*lpDst1>max) max=*lpSrc;
				if((*lpSrc<GradientTh) && (*lpDst1 <GrayTh)){//目标内部
					int min=255;
					for(int m=-1;m<2;m++)
						for(int n=-1;n<2;n++)
							if(min>*(lpSrc+m*lLineBytes+n))
								min=*(lpSrc+m*lLineBytes+n);
					if(min==*lpSrc)
						*lpDst=TWOVALUE_H;
				}
			}
		}
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
				lpDst = m_pModelData +  lLineBytes* (lHeight-1-i) + j;
				lpDst1 = lpNewDIBBits +  lLineBytes*i + j;//area, not bmp
				if(*lpDst1==max)
					*lpDst=TWOVALUE_H;
			}
		}
		DisplayNewImg(m_pModelData,lLineBytes,lHeight,"Marked Point");//

		delete [] lpNewDIBBits;


	}
	else{//select point by hand
		m_bWatershedProcGetSeed=true;	
		m_pModelData=new unsigned char [lWidth*lHeight];
		memset(m_pModelData,0,lWidth*lHeight);
	}
}

void CImageProcessView::OnUpdateWatershedprocessGetseed(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}

void CImageProcessView::OnWatershedprocessLabelmarked()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	if(m_bWatershedProcGetSeed){

		DisplayNewImg( pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,"原图像");
		memcpy( pDoc->m_pDib->m_lpImage,m_pModelData , lLineBytes * lHeight);
		unsigned char* lpSrc;
		unsigned char* lpDst;

		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpSrc = m_pModelData +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			lpDst = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpSrc++;lpDst++;
				if ((*(lpSrc) == TWOVALUE_H)){
					*(lpDst-1)=TWOVALUE_H;*(lpDst+1)=TWOVALUE_H;
					*(lpDst+lLineBytes)=TWOVALUE_H;*(lpDst-lLineBytes)=TWOVALUE_H;
					*(lpDst+lLineBytes-1)=TWOVALUE_H;*(lpDst+lLineBytes+1)=TWOVALUE_H;
					*(lpDst-lLineBytes-1)=TWOVALUE_H;*(lpDst-lLineBytes+1)=TWOVALUE_H;
				}
			}
		}

	}		

	int ObjNum=Connectedcomponents();

	memcpy( m_pModelData ,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);

	if(ObjNum)
		DisplayObjLabel(ObjNum+1);
}

void CImageProcessView::OnUpdateWatershedprocessLabelmarked(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_pModelData!=NULL);
}

// Edge img
void CImageProcessView::OnWatershedprocessGetareas()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char* lpSrc;
	BeginWaitCursor();

	int objectCount=0;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = m_pModelData +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			if ((*lpSrc)>objectCount)
				objectCount=*(lpSrc);
		}
	}

	//set boarder 255
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			if (i == pDoc->StartPoint.y || i==pDoc->EndPoint.y || j ==pDoc->StartPoint.x || j ==pDoc->EndPoint.x)
				*(lpSrc)=255;
		}
	}



	Watershed(m_pModelData,objectCount);


	memcpy( pDoc->m_pDib->m_lpImage,m_pModelData, lLineBytes * lHeight);

	pDoc->SetTitle("Watershed");

	DisplayObjLabel(objectCount); 
	// 恢复光标
	EndWaitCursor();	


}

void CImageProcessView::OnUpdateWatershedprocessGetareas(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_pModelData!=NULL);

}

void CImageProcessView::OnSegmentationOstu()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	//直方图数组
	int lHistogram[256]={0};

	GetHistgram(lHistogram,true);

	int iThreshold;
	//用于计算区域灰度平均值的中间变量
	double m1,m2,w1,w2;
	double maxD=0.0;
	int size=(pDoc->EndPoint.x-pDoc->StartPoint.x+1)*(pDoc->EndPoint.y-pDoc->StartPoint.y+1);
	for(iThreshold = 1; iThreshold< 255;iThreshold ++)
	{
		m1 =0.0;m2=0.0;
		w1 =0.0;w2=0.0;
		//求两个区域的灰度平均值m and number w
		for (int i =0;i <=iThreshold;i++)
		{
			m1 += lHistogram[i]*i;//
			w1 += lHistogram[i];//total num
		}

		for (int i = iThreshold+1;i < 256;i++)
		{
			m2 += lHistogram[i]*i;
		}

		m1/=w1;
		m2/=(size-w1);
		w1/=size;
		w2=1-w1;

		double dev_B=w1*w2*(m2-m1)*(m2-m1);
		if(dev_B>maxD){
			maxD=dev_B;
			THRESHOLD=iThreshold;
		}

	}


	Fixedthreshold();

	//display Hist	

	CString str;
	str.Format("Treshold(%d)",THRESHOLD);
	DisplayDlg dlg;
	dlg.pData=&lHistogram[0];
	dlg.m_Sizex=256;
	dlg.m_Title=str;
	dlg.m_Level=1;//draw number
	dlg.m_LinePos=THRESHOLD;
	dlg.DoModal();

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSegmentationOstu(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnSegmentationEntropy()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	//直方图数组
	int lHistogram[256]={0};

	GetHistgram(lHistogram,true);

	int size=(pDoc->EndPoint.x-pDoc->StartPoint.x+1)*(pDoc->EndPoint.y-pDoc->StartPoint.y+1);
	int iThreshold;
	double maxH=0.0;
	for(iThreshold = 1; iThreshold< 255;iThreshold ++)
	{
		double Pk =0.0;
		for (int i =0;i <=iThreshold;i++)
		{
			Pk+= lHistogram[i];
		}
		Pk/=size;

		if(Pk<0.01 || Pk>0.99) continue;
		double H1=0.0;
		for (int i =0;i <=iThreshold;i++)
		{
			double dtmp=((double)lHistogram[i])/size;
			if(dtmp>0.0001)
				H1+= dtmp*log(dtmp);
		}
		double H2=0.0;
		for (int i = iThreshold+1;i < 256;i++)
		{
			double dtmp=((double)lHistogram[i])/size;
			if(dtmp>0.0001)
				H2+= dtmp*log(dtmp);
		}


		double H=log(Pk)+log(1-Pk)-H1/Pk-H2/(1-Pk);
		if(H>maxH){
			maxH=H;
			THRESHOLD=iThreshold;
		}

	}


	Fixedthreshold();

	//display Hist	

	CString str;
	str.Format("Treshold(%d)",THRESHOLD);
	DisplayDlg dlg;
	dlg.pData=&lHistogram[0];
	dlg.m_Sizex=256;
	dlg.m_Title=str;
	dlg.m_Level=1;//draw number
	dlg.m_LinePos=THRESHOLD;
	dlg.DoModal();

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSegmentationEntropy(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//假设存在2个正态分布,估计其均值、方差
//估计其背景、目标的比例
//依据最小误判概率,解2次方差
void CImageProcessView::OnSegmentationMaxlikelihood()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	//直方图数组
	int lHistogram[256]={0};

	GetHistgram(lHistogram,true);

	//get meanBack,meanObj
	int meanBack,meanObj;
	int ABack,AObj;
	//get max 
	ABack=0;
	meanBack=-1;
	meanObj=-1;

	for (int i = 0; i < 256;i++)
	{  if(ABack<lHistogram[i]) {
		ABack=(int)lHistogram[i];//max
		meanBack=i;
	}

	}

	int minH=0;
	while(lHistogram[minH]<ABack/20)
		minH++;

	int maxH=255;
	while(lHistogram[maxH]<ABack/20)
		maxH--;

	//get second max
	AObj=0;
	int pos=meanBack-(maxH-minH)/3;
	int min=lHistogram[meanBack];
	if(pos<0) pos=0;

	if(meanBack>10){
		for (int i =pos ; i>=0 ;i--){
			if(min>lHistogram[i])
				min=lHistogram[i];
			else
			{
				pos=i;break;
			}
			if(min<10) {
				pos=i;break;
			}

		}

		for (int i = pos; i >=0 ;i--){
			if(AObj<lHistogram[i]) {
				AObj=(int)lHistogram[i];//max
				meanObj=i;
			}

		}
	}

	min=lHistogram[meanBack];
	pos=meanBack+(maxH-minH)/3;
	if(pos>255) pos=255;

	if(meanBack<250){


		for (int i = pos; i<256 ;i++){
			if(min>lHistogram[i])
				min=lHistogram[i];
			else
			{
				pos=i;break;
			}
			if(min<10) {
				pos=i;break;
			}

		}
		for (int i = pos; i <256 ;i++){
			if(AObj<lHistogram[i]) {
				AObj=(int)lHistogram[i];//max
				meanObj=i;
			}

		}
	}

	if(meanObj<meanBack){
		//swap
		int tmp=meanBack;
		meanBack=meanObj;
		meanObj=tmp;
		int  dtmp=ABack;
		ABack=AObj;
		AObj=dtmp;

	}

	TRACE("\nmeanBack=%d,(%d),meanObj=%d,(%d) posStep=%d\n\n",meanBack,ABack,meanObj,AObj,(maxH-minH)/3);

	//get segm
	double segmBack;
	pos=meanBack;
	bool bfind=false;
	if(meanBack>10){
		while(pos>0 && !bfind){
			pos--;
			double dtmp=((double)lHistogram[pos])/ABack;
			if(dtmp<exp(-0.5))
				bfind=true;
		}
	}
	else{
		while(pos<255 && !bfind){
			pos++;
			double dtmp=((double)lHistogram[pos])/ABack;
			if(dtmp<exp(-0.5))
				bfind=true;
		}
	}
	segmBack=abs(pos-meanBack);
	if(segmBack<3.0)segmBack=3.0;//不连续直方图
	else if(segmBack>meanObj-meanBack)
		segmBack=(meanObj-meanBack)/3;

	double segmObj;
	pos=meanObj;
	bfind=false;

	if(meanObj>255-10){
		while(pos>0 && !bfind){
			pos--;
			double dtmp=((double)lHistogram[pos])/AObj;
			if(dtmp<exp(-0.5))
				bfind=true;
		}
	}
	else
	{while(pos<255 && !bfind){
		pos++;
		double dtmp=((double)lHistogram[pos])/AObj;
		if(dtmp<exp(-0.5))
			bfind=true;
	}
	}

	segmObj=abs(pos-meanObj);
	if(segmObj<3.0)segmObj=3.0;//不连续直方图
	else if(segmObj>meanObj-meanBack)
		segmObj=(meanObj-meanBack)/3;

	TRACE("\nmeanBack=%d,segmBack=%3.1f,meanObj=%d,segmObj=%3.1f",meanBack,segmBack,meanObj,segmObj);

	//get Th--比例
	double Th=AObj*segmObj/(AObj*segmObj+ABack*segmBack);

	//get iThreshold
	double A,B,C;
	A=segmObj*segmObj-segmBack*segmBack;
	B=2.0*(-meanBack*segmObj*segmObj+meanObj*segmBack*segmBack);
	C=meanBack*meanBack*segmObj*segmObj-meanObj*meanObj*segmBack*segmBack
		-2.0*segmObj*segmObj*segmBack*segmBack*log(segmObj/segmBack*(1.0-Th)/Th);

	if(A>0.01 || A<-0.01){ //A!=0
		double t1=(-B+sqrt(B*B-4*A*C))/(2.0*A);
		double t2=(-B-sqrt(B*B-4*A*C))/(2.0*A);
		if(t1>meanBack && t1<meanObj) THRESHOLD=(int)(t1+0.5);
		if(t2>meanBack && t2<meanObj) THRESHOLD=(int)(t2+0.5);
	}else if(B>0.01 || B<-0.01)
		THRESHOLD=(int)max((-C/B+0.5),0.0);
	else 
		THRESHOLD=0;//err


	Fixedthreshold();

	//display Hist	

	CString str;
	str.Format("Treshold(%d)",THRESHOLD);
	DisplayDlg dlg;
	dlg.pData=&lHistogram[0];
	dlg.m_Sizex=256;
	dlg.m_Title=str;
	dlg.m_Level=1;//draw number
	dlg.m_LinePos=THRESHOLD;
	dlg.DoModal();

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSegmentationMaxlikelihood(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//目标为黑,适合扫描文字提取,可克服明亮程度的不同
//利用邻域的最大最小值获取阈值
void CImageProcessView::OnSegmentationLocalthresholding()
{

	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);


	const int M=5;
	const int N=5;
	int minrange=255/5;

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;

		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			lpDst++;
			if(i>=M/2 && i<lHeight-M/2 && j>=N/2 && j<lWidth-N/2){
				int min=255;
				int max=0;
				for(int m=-M/2;m<=M/2;m++)
					for(int n=-N/2;n<=N/2;n++)
					{	
						if(*(lpSrc+m*lLineBytes+n)>max)
							max=*(lpSrc+m*lLineBytes+n);
						if(*(lpSrc+m*lLineBytes+n)<min)
							min=*(lpSrc+m*lLineBytes+n);
						int range=max-min;
						int T;
						if(range>minrange)
							T=(min+max)/2;
						else
							T=max-min/2;//all white
						if(*lpSrc>T)
							*(lpDst)=255;
						else
							*(lpDst)=0;

					}
			}
			else
				*(lpDst)=255;//back

		}
	}

	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,"自适应局部阈值");//

	// 释放内存
	delete []lpNewDIBBits;
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSegmentationLocalthresholding(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnApplicationParallelthin()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	// 更改光标形状
	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	BOOL bOver=false;
	while(!bOver){
		bOver=true;
		//North:
		//x  0  x
		//x (1) x
		//x  1  x
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
				lpDst++;lpSrc++;
				bool A0,A1,A2,A3,A4,A5,A6,A7,A8;
				A0 = *lpSrc>0;
				A1 = *(lpSrc+1)>0;
				A2 = *(lpSrc+lLineBytes+1)>0;
				A3 = *(lpSrc+lLineBytes)>0;
				A4 = *(lpSrc+lLineBytes-1)>0;
				A5 = *(lpSrc-1)>0;
				A6 = *(lpSrc - lLineBytes-1)>0;
				A7 = *(lpSrc - lLineBytes)>0;
				A8 = *(lpSrc - lLineBytes+1)>0;
				if(A0 && !A3 && A7){
					int sigm=A1+A2+A3+A4+A5+A6+A7+A8;
					int chi=(A1!=A3)+(A3!=A5)+(A5!=A7)+(A7!=A1)
						+2*((A1 && A2 && !A3)+(!A3 && A4 && !A5)
						+(!A5 && A6 && !A7)+(!A7 && A8 && !A1));
					if((chi==2) && (sigm!=1)){
						*lpDst = TWOVALUE_L;
						bOver=false;
					}
				}
			}
		}
		lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
		memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);

		//South:
		//x  1  x
		//x (1) x
		//x  0  x
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
				lpDst++;lpSrc++;
				bool A0,A1,A2,A3,A4,A5,A6,A7,A8;
				A0 = *lpSrc>0;
				A1 = *(lpSrc+1)>0;
				A2 = *(lpSrc+lLineBytes+1)>0;
				A3 = *(lpSrc+lLineBytes)>0;
				A4 = *(lpSrc+lLineBytes-1)>0;
				A5 = *(lpSrc-1)>0;
				A6 = *(lpSrc - lLineBytes-1)>0;
				A7 = *(lpSrc - lLineBytes)>0;
				A8 = *(lpSrc - lLineBytes+1)>0;
				if(A0 && !A7 && A3){
					int sigm=A1+A2+A3+A4+A5+A6+A7+A8;
					int chi=(A1!=A3)+(A3!=A5)+(A5!=A7)+(A7!=A1)
						+2*((A1 && A2 && !A3)+(!A3 && A4 && !A5)
						+(!A5 && A6 && !A7)+(!A7 && A8 && !A1));
					if((chi==2) && (sigm!=1)){
						*lpDst = TWOVALUE_L;
						bOver=false;
					}
				}
			}
		}
		lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
		memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);

		//East:
		//x  x  x
		//0 (1) 1
		//x  x  x
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
				lpDst++;lpSrc++;
				bool A0,A1,A2,A3,A4,A5,A6,A7,A8;
				A0 = *lpSrc>0;
				A1 = *(lpSrc+1)>0;
				A2 = *(lpSrc+lLineBytes+1)>0;
				A3 = *(lpSrc+lLineBytes)>0;
				A4 = *(lpSrc+lLineBytes-1)>0;
				A5 = *(lpSrc-1)>0;
				A6 = *(lpSrc - lLineBytes-1)>0;
				A7 = *(lpSrc - lLineBytes)>0;
				A8 = *(lpSrc - lLineBytes+1)>0;
				if(A0 && !A5 && A1){
					int sigm=A1+A2+A3+A4+A5+A6+A7+A8;
					int chi=(A1!=A3)+(A3!=A5)+(A5!=A7)+(A7!=A1)
						+2*((A1 && A2 && !A3)+(!A3 && A4 && !A5)
						+(!A5 && A6 && !A7)+(!A7 && A8 && !A1));
					if((chi==2) && (sigm!=1)){
						*lpDst = TWOVALUE_L;
						bOver=false;
					}
				}
			}
		}
		lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
		memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);

		//West:
		//x  x  x
		//1 (1) 0
		//x  x  x
		for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++){
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++){
				lpDst++;lpSrc++;
				bool A0,A1,A2,A3,A4,A5,A6,A7,A8;
				A0 = *lpSrc>0;
				A1 = *(lpSrc+1)>0;
				A2 = *(lpSrc+lLineBytes+1)>0;
				A3 = *(lpSrc+lLineBytes)>0;
				A4 = *(lpSrc+lLineBytes-1)>0;
				A5 = *(lpSrc-1)>0;
				A6 = *(lpSrc - lLineBytes-1)>0;
				A7 = *(lpSrc - lLineBytes)>0;
				A8 = *(lpSrc - lLineBytes+1)>0;
				if(A0 && !A1 && A5){
					int sigm=A1+A2+A3+A4+A5+A6+A7+A8;
					int chi=(A1!=A3)+(A3!=A5)+(A5!=A7)+(A7!=A1)
						+2*((A1 && A2 && !A3)+(!A3 && A4 && !A5)
						+(!A5 && A6 && !A7)+(!A7 && A8 && !A1));
					if((chi==2) && (sigm!=1)){
						*lpDst = TWOVALUE_L;
						bOver=false;
					}
				}
			}
		}

		lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
		memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);

	}


	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"细化");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	EndWaitCursor();	


	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdateApplicationParallelthin(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);
}

//1. select sub_image(2x2) ,it can improve accuray
//    not process ; ==select area by hand 
//2  select the origin at the center of area
//3  let rho>10
//4  Sobel
//5  count x0,y0 set list and count times
//6 sort by num 
//7 union by pt (near as 1)
//8 display positions (liness)
//delete last position (around )--not process
//9 use center and point(x0,y0) can get line function 
// not process!
//10 get near line (function) point ,then improve accuray by 最小二乘法拟合

void CImageProcessView::OnHoughFontofnormal()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;


	BeginWaitCursor();

	//err! must be 全局变量
	/*struct Info{
	CPoint pt;
	int num;
	};*/



	CList<LineInfo,LineInfo&> myList;
	LineInfo info;


	int pixel[8];
	CPoint center=CPoint((pDoc->EndPoint.x-pDoc->StartPoint.x+1)/2+pDoc->StartPoint.x,(pDoc->EndPoint.y-pDoc->StartPoint.y+1)/2+pDoc->StartPoint.y);
	const int TH=280;//need be changed::gantrycrane
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;			
			if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
				pixel[0] = (int)*(lpSrc+lLineBytes-1);
				pixel[1] = (int)*(lpSrc+lLineBytes);
				pixel[2] = (int)*(lpSrc+lLineBytes+1);
				pixel[3] = (int)*(lpSrc-1);
				pixel[4] = (int)*(lpSrc+1);
				pixel[5] = (int)*(lpSrc - lLineBytes-1);
				pixel[6] = (int)*(lpSrc - lLineBytes);
				pixel[7] = (int)*(lpSrc - lLineBytes+1);
				//  1   2   1
				//  0   0   0
				// -1  -2  -1

				int gy=pixel[0]+2*pixel[1]+pixel[2]-pixel[5]-2*pixel[6]-pixel[7];

				//  -1   0   1
				//  -2   0   2
				//  -1   0   1
				int gx=pixel[2]+2*pixel[4]+pixel[7]-pixel[0]-2*pixel[3]-pixel[5];

				int result =(int)(sqrt(double(gx*gx+gy*gy))); 
				//edge
				if(result>TH){
					double v=((double)((j-center.x)*gx+(center.y-i)*gy))/(gx*gx+gy*gy);
					int x0=(int)(v*gx);
					int y0=(int)(v*gy);


					bool bfind=false;
					POSITION pos=myList.GetHeadPosition();
					while(pos!=NULL)
					{
						POSITION tmp_pos=pos;
						info=myList.GetNext(pos);
						if(info.pt==CPoint(x0,y0))
						{
							bfind=true;
							pos=tmp_pos;
							break;
						}
					}
					if(!bfind){
						info.pt=CPoint(x0,y0);
						info.num=1;
						myList.AddTail(info);

					}
					else{
						info.num++;
						myList.SetAt(pos,info);//++
					}

				}

			}
		}
	}




	//watch data
	//sort

	for(POSITION pos1=myList.GetHeadPosition();pos1!=NULL;myList.GetNext(pos1))
		for(POSITION pos2=myList.GetHeadPosition();pos2!=NULL;myList.GetNext(pos2)){

			LineInfo info1=myList.GetAt(pos1);
			LineInfo info2=myList.GetAt(pos2);
			if(info1.num>info2.num){
				LineInfo tmp=info1;
				myList.SetAt(pos1,info2);//++
				myList.SetAt(pos2,tmp);//++
			}
		}

		POSITION  pos = myList.GetHeadPosition();
		TRACE("\nBefore Union:\nData(%d):\n",myList.GetCount());
		while(pos!=NULL){
			info=myList.GetNext(pos);
			TRACE("\t(%3d,%3d)=%3d",info.pt.x,info.pt.y,info.num);
			if(info.num<30) break;
		}
		TRACE("\n\n");

		//union
		for(POSITION pos1=myList.GetHeadPosition();pos1!=NULL;myList.GetNext(pos1))
			for(POSITION pos2=myList.GetHeadPosition();pos2!=NULL;myList.GetNext(pos2)){
				LineInfo info1=myList.GetAt(pos1);
				LineInfo info2=myList.GetAt(pos2);
				if(info1.pt!= info2.pt){
					if(abs(info1.pt.x-info2.pt.x)<3 && abs(info1.pt.y-info2.pt.y)<3){ //near pt
						info1.num+=info2.num;
						myList.SetAt(pos1,info1);//
						POSITION tmp=pos2;
						myList.GetPrev(pos2);
						myList.RemoveAt(tmp);//
					}
				}
			}

			pos = myList.GetHeadPosition();
			TRACE("\nAfter Union:\nData(%d):\n",myList.GetCount());
			while(pos!=NULL){
				info=myList.GetNext(pos);
				TRACE("\t(%3d,%3d)=%3d",info.pt.x,info.pt.y,info.num);
				if(info.num<50) break;
			}
			TRACE("\n\n");

			//find pt
			pos = myList.GetHeadPosition();
			CPoint pt;
			while(pos!=NULL){
				info=myList.GetNext(pos);//not be sorted now
				if(info.num>50){//line length>50
					pt=info.pt;
					pt.x+=center.x;
					pt.y=(center.y-pt.y);

					//display x0,y0
					lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-pt.y) + pt.x;
					*(lpSrc-2)=255;*(lpSrc-1)=255;*(lpSrc)=255;*(lpSrc+1)=255;*(lpSrc+2)=255;
					*(lpSrc-2*lLineBytes)=255;*(lpSrc-lLineBytes)=255;*(lpSrc+lLineBytes)=255;*(lpSrc+2*lLineBytes)=255;


				}
			}

			//display Center
			lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-center.y) + center.x;
			*(lpSrc-1)=255;*(lpSrc)=255;*(lpSrc+1)=255;
			*(lpSrc-lLineBytes-1)=255;*(lpSrc-lLineBytes)=255;*(lpSrc-lLineBytes+1)=255;
			*(lpSrc+lLineBytes-1)=255;*(lpSrc+lLineBytes)=255;*(lpSrc+lLineBytes+1)=255;
			LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable+255;

			pDibQuad->rgbRed = 255;	pDibQuad->rgbGreen =0;pDibQuad->rgbBlue = 0;


			CString str=pDoc->GetTitle();
			pDoc->SetTitle(str+"The Foot of Nomal Method");

			InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

			EndWaitCursor();	

}


void CImageProcessView::OnUpdateHoughFontofnormal(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

//1.选择一个圆处理
//可以进行二值化,标定再处理,获取多个圆---未完成
//2提取边缘Sobel
//3获取每行起始、终止边缘的中值
//4获取每列起始、终止边缘的中值
//5 取峰值获得圆心
//6 对于边缘点计算半径均值
//7 作图形显示圆心、圆

void CImageProcessView::OnCircledetectionChordbisectionalg()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpSrc;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	// 更改光标形状
	BeginWaitCursor();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//soble
	OnEdgeSobel();

	const int TH=250;//coins if no use OnEdgeSobel();:400

	int *ptx;
	ptx=new int [lWidth];
	memset(ptx,0,lWidth*sizeof(int));

	//获取行中心点
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		bool bfind=false;
		int pt1=0;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x && !bfind; j ++){
			lpSrc++;
			if(*lpSrc>TH){
				pt1=j;
				bfind=true;
			}
		}
		if(bfind){
			lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->EndPoint.x+1;
			bfind=false;
			int pt2=0;
			for (int j =pDoc->EndPoint.x; j >=pDoc->StartPoint.x && !bfind; j --){
				lpSrc--;
				if(*lpSrc>TH){
					pt2=j;
					bfind=true;
				}
			}
			ptx[(pt2+pt1)/2]++;
			if((pt2+pt1%2)) ptx[(pt2+pt1)/2+1]++;//后面取最大值,将其赋值,保证峰值点
		}
	}

	int *pty;
	pty=new int [lHeight];
	memset(pty,0,lHeight*sizeof(int));

	//获取列中心点
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
		bool bfind=false;
		int pt1=0;
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y && !bfind; i ++){
			lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +j;
			if(*lpSrc>TH){
				pt1=i;
				bfind=true;
			}
		}
		if(bfind){
			bfind=false;
			int pt2=0;
			for (int i =pDoc->EndPoint.y; i >=pDoc->StartPoint.y && !bfind; i --){
				lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) +j;
				if(*lpSrc>TH){
					pt2=i;
					bfind=true;
				}
			}
			pty[(pt2+pt1)/2]++;
			if((pt2+pt1%2)) pty[(pt2+pt1)/2+1]++;//后面取最大值,将其赋值,保证峰值点
		}
	}

	//中心点:最大值
	CPoint center(CPoint(0,0));
	int max1=0;
	for(int i=0;i<lWidth;i++)
		if(ptx[i]>max1){
			max1=ptx[i];
			center.x=i;
		}

		int max2=0;
		for(int i=0;i<lHeight;i++)
			if(pty[i]>max2){
				max2=pty[i];
				center.y=i;
			}
			delete []ptx;
			delete []pty;

			TRACE("\n\nCenter(%d,%d)  max(%d,%d)\n\n",center.x,center.y,max1,max2);

			//get radius
			int num=0;
			double addRadius=0;
			for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
				lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
				for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x ; j ++){
					lpSrc++;
					if(*lpSrc>TH){
						double r=sqrt(double((j-center.x)*(j-center.x)+(i-center.y)*(i-center.y)));
						num++;
						addRadius+=r;
					}
				}
			}

			double Radius=0;
			if(num)
				Radius=addRadius/num;
			TRACE("\n\nRadiu(%3.1f),edge num=%d\n",Radius,num);

			lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
			memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);//original image



			CString str=pDoc->GetTitle();
			pDoc->SetTitle(str+"Circle Detection");

			InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

			CString msg;
			msg.Format("圆心坐标(%d,%d)半径(%3.1f)\n",center.x,center.y,Radius);
			MessageBox(msg,"Message");
			//在显示图形前,等待屏幕刷新完成

			//display
			CDC *pdc=GetDC();
			CPen	Redpen;
			Redpen.CreatePen(PS_DOT, 1, RGB(255,0,0));

			pdc->SelectObject(Redpen);

			int radius=(int)(Radius+1.5);//普遍小,补偿?
			Arc(pdc->m_hDC,
				center.x-radius,
				center.y-radius,
				center.x+radius,
				center.y+radius,
				center.x+radius,
				center.y,
				center.x+radius,
				center.y
				);

			Rectangle(pdc->m_hDC,center.x-1,center.y-1,center.x+1,center.y+1);
			DeleteObject(Redpen);


			EndWaitCursor();	


			// 释放内存
			delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdateCircledetectionChordbisectionalg(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);

}

//1.选择一个圆处理
//物体为亮,否则圆心计算公式需要调整
//可以处理半个圆、
//多个圆----未完成
//2 Sobel
//3 估计半径
// 半径递增,取中心点,取最大数下为估计半径。误差+/-1 pixel
//半径不必整数,可初调后精调,边缘的大小可对中心数加权,提高精度—未完成
//4 中心点精确估计0.1pixel(书上介绍?)
//边缘的大小对中心数加权,提高精度
//梯度计算重复多次,可利用存储gx、gy降低计算量
//5 显示圆、圆心


void CImageProcessView::OnCircledetectionAcurr()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;


	BeginWaitCursor();

	//估计半径
	int pixel[8];
	const int Rmin=20;
	const int Rmax=35;

	CList<LineInfo,LineInfo&> myList;
	LineInfo info;

	const int TH=400;//coins :need be changed
	int Max=0;//num
	int rMax=0;//半径
	CPoint center;

	for(int R=Rmin;R<=Rmax;R++){
		myList.RemoveAll();

		//get List---info(x0,y0,num)  circle center \point num
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpSrc++;			
				if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
					pixel[0] = (int)*(lpSrc+lLineBytes-1);
					pixel[1] = (int)*(lpSrc+lLineBytes);
					pixel[2] = (int)*(lpSrc+lLineBytes+1);
					pixel[3] = (int)*(lpSrc-1);
					pixel[4] = (int)*(lpSrc+1);
					pixel[5] = (int)*(lpSrc - lLineBytes-1);
					pixel[6] = (int)*(lpSrc - lLineBytes);
					pixel[7] = (int)*(lpSrc - lLineBytes+1);
					//  1   2   1
					//  0   0   0
					// -1  -2  -1

					int gy=pixel[0]+2*pixel[1]+pixel[2]-pixel[5]-2*pixel[6]-pixel[7];

					//  -1   0   1
					//  -2   0   2
					//  -1   0   1
					int gx=pixel[2]+2*pixel[4]+pixel[7]-pixel[0]-2*pixel[3]-pixel[5];

					double g =sqrt(double(gx*gx+gy*gy)); 
					//edge
					if(g>TH){

						double v=R/g;
						int x0=j+(int)(v*gx+0.5);//于书不同!
						int y0=i-(int)(v*gy+0.5);


						bool bfind=false;
						POSITION pos=myList.GetHeadPosition();
						while(pos!=NULL)
						{
							POSITION tmp_pos=pos;
							info=myList.GetNext(pos);
							if(info.pt==CPoint(x0,y0))
							{
								bfind=true;
								pos=tmp_pos;
								break;
							}
						}
						if(!bfind){
							info.pt=CPoint(x0,y0);
							info.num=1;
							myList.AddTail(info);

						}
						else{
							info.num++;
							myList.SetAt(pos,info);//++
						}

					}

				}
			}
		}

		//sort

		for(POSITION pos1=myList.GetHeadPosition();pos1!=NULL;myList.GetNext(pos1))
			for(POSITION pos2=myList.GetHeadPosition();pos2!=NULL;myList.GetNext(pos2)){

				LineInfo info1=myList.GetAt(pos1);
				LineInfo info2=myList.GetAt(pos2);
				if(info1.num>info2.num){
					LineInfo tmp=info1;
					myList.SetAt(pos1,info2);//++
					myList.SetAt(pos2,tmp);//++
				}
			}

			//union
			for(POSITION pos1=myList.GetHeadPosition();pos1!=NULL;myList.GetNext(pos1))
				for(POSITION pos2=myList.GetHeadPosition();pos2!=NULL;myList.GetNext(pos2)){
					LineInfo info1=myList.GetAt(pos1);
					LineInfo info2=myList.GetAt(pos2);
					if(info1.pt!= info2.pt){
						if(abs(info1.pt.x-info2.pt.x)<3 && abs(info1.pt.y-info2.pt.y)<3){ //near pt
							info1.num+=info2.num;
							myList.SetAt(pos1,info1);//
							POSITION tmp=pos2;
							myList.GetPrev(pos2);
							myList.RemoveAt(tmp);//
						}
					}
				}
				//
				//POSITION pos = myList.GetHeadPosition();
				//TRACE("\nAfter Union:\nR=%dData(%d):\n",R,myList.GetCount());
				//while(pos!=NULL){
				//	info=myList.GetNext(pos);
				//	TRACE("\t(%3d,%3d)=%3d",info.pt.x,info.pt.y,info.num);
				//	if(info.num<30) break;
				//}
				//TRACE("\n\n");

				info=myList.GetHead();
				if(Max<info.num){
					Max=info.num;
					rMax=R;
					center=info.pt;

				}
	}

	TRACE("\n圆心坐标(%3d,%3d)\t 半径(%3d) 数目(%d)\n",center.x,center.y,rMax,Max);

	//中心点精确估计
	int R=rMax;
	double num=0;
	double totX=0;
	double totY=0;

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpSrc  = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;			
			if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
				pixel[0] = (int)*(lpSrc+lLineBytes-1);
				pixel[1] = (int)*(lpSrc+lLineBytes);
				pixel[2] = (int)*(lpSrc+lLineBytes+1);
				pixel[3] = (int)*(lpSrc-1);
				pixel[4] = (int)*(lpSrc+1);
				pixel[5] = (int)*(lpSrc - lLineBytes-1);
				pixel[6] = (int)*(lpSrc - lLineBytes);
				pixel[7] = (int)*(lpSrc - lLineBytes+1);
				//  1   2   1
				//  0   0   0
				// -1  -2  -1

				int gy=pixel[0]+2*pixel[1]+pixel[2]-pixel[5]-2*pixel[6]-pixel[7];

				//  -1   0   1
				//  -2   0   2
				//  -1   0   1
				int gx=pixel[2]+2*pixel[4]+pixel[7]-pixel[0]-2*pixel[3]-pixel[5];

				double g =sqrt(double(gx*gx+gy*gy)); 
				//edge
				if(g>TH){

					double v=R/g;
					double x0=j+v*gx;
					double y0=i-v*gy;
					double s=sqrt((x0-j)*(x0-j)+(y0-i)*(y0-i));
					if(abs(s-R)<5){
						//num++;
						double w=g/TH;
						num+=w;//边缘峰值加权
						totX+=(j-(R/s)*(j-x0))*w;
						totY+=(i-(R/s)*(i-y0))*w;
					}
				}
			}
		}
	}

	if(num>1.0){
		TRACE("\n中心点精确估计后\n圆心坐标(%3.1f,%3.1f)\t 半径(%3d) 数目(%3.1f)\n",totX/num,totY/num,rMax,num);
	}

	//display
	//	MessageBox(msg,"Message");
	//在显示图形前,等待屏幕刷新完成

	//display
	CDC *pdc=GetDC();
	CPen	Redpen;
	Redpen.CreatePen(PS_DOT, 1, RGB(255,0,0));

	pdc->SelectObject(Redpen);

	int radius=R;
	center.x=(int)(totX/num+0.5);
	center.y=(int)(totY/num+0.5);
	Arc(pdc->m_hDC,
		center.x-radius,
		center.y-radius,
		center.x+radius,
		center.y+radius,
		center.x+radius,
		center.y,
		center.x+radius,
		center.y
		);

	Rectangle(pdc->m_hDC,center.x-1,center.y-1,center.x+1,center.y+1);
	DeleteObject(Redpen);


	EndWaitCursor();	
}

void CImageProcessView::OnUpdateCircledetectionAcurr(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);

}

void CImageProcessView::OnHistgramGrayBar()
{
	// TODO: Add your command handler code here
	//	CImageProcessDoc* pDoc = GetDocument();

	int Hist[256]={0};
	GetHistgram(Hist,false);


	pDlg=new DisplayDlg();//

	pDlg->Create(IDD_DISPLAY_DIALOG,this);

	//pDlg->pData=&Hist[0];//动态时,数据传不过去

	pDlg->pData=new int [256];
	memcpy(pDlg->pData,Hist,256*sizeof(int));

	pDlg->m_Sizex=256;
	pDlg->m_LinePos=100;
	pDlg->m_Title=_T("灰度直方图");
	pDlg->m_Level=1;
	pDlg->bBar=true;

	pDlg->ShowWindow(SW_SHOW);



}

void CImageProcessView::OnUpdateHistgramGrayBar(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;

	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramRgbbar()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int m_nHistRGB[256*3]={0};
	unsigned char *lpSrc;

	// 计算各个灰度值的计数,即得到直方图
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
		{
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes*(lHeight-1-i) + j*3;//down -up
			// 计数加1
			m_nHistRGB[*(lpSrc+2)]++;//R
			m_nHistRGB[256+*(lpSrc+1)]++;//G
			m_nHistRGB[256*2+*(lpSrc)]++;//B
		}


		pDlg=new DisplayDlg();//

		pDlg->Create(IDD_DISPLAY_DIALOG,this);


		pDlg->pData=new int [256*3];
		memcpy(pDlg->pData, m_nHistRGB,256*3*sizeof(int));

		pDlg->m_Sizex=256;
		pDlg->m_Title="彩色RGB直方图";
		pDlg->m_Level=3;//draw number
		pDlg->m_LinePos=0;
		pDlg->bBar=true;

		pDlg->ShowWindow(SW_SHOW);

}

void CImageProcessView::OnUpdateHistgramRgbbar(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==24)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnHistgramHsibar()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	int m_nHistHSI[256*3]={0};
	unsigned char *lpSrc;

	// 计算各个灰度值的计数,即得到直方图
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
		{
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes*(lHeight-1-i) + j*3;//down -up

			RGB Rgb;
			HSI Hsi;
			Rgb.b=*lpSrc;Rgb.g=*(lpSrc+1);Rgb.r=*(lpSrc+2);
			RgbtoHsi(&Rgb, &Hsi);
			unsigned int H,S,I;
			H=(unsigned int) (Hsi.Hue/360.0*255.0);
			S=(unsigned int) (Hsi.Saturation*255.0);
			I=(unsigned int) (Hsi.Intensity*255.0);
			// 计数加1
			m_nHistHSI[H]++;//H
			m_nHistHSI[256+S]++;//S
			m_nHistHSI[256*2+I]++;//I
		}


		pDlg=new DisplayDlg();//

		pDlg->Create(IDD_DISPLAY_DIALOG,this);


		pDlg->pData=new int [256*3];
		memcpy(pDlg->pData, m_nHistHSI,256*3*sizeof(int));

		pDlg->m_Sizex=256;
		pDlg->m_Title="彩色HSI直方图";
		pDlg->m_Level=3;//draw number
		pDlg->m_LinePos=0;
		pDlg->bBar=true;

		pDlg->ShowWindow(SW_SHOW);
}

void CImageProcessView::OnUpdateHistgramHsibar(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==24)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnObjectrecognitionPlesseycornerdetector()
{

	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();


	// 更改光标形状
	BeginWaitCursor();

	//1 filter
	GaussFilter(7,7,1.0);//-3*1.0--3*1.0


	//2 difference

	double*	Dx;
	double*	Dy;

	Dx=new double [lLineBytes*lHeight];
	Dy=new double [lLineBytes*lHeight];

	_ASSERT(Dx != NULL);//false
	_ASSERT(Dy != NULL);//false



	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		unsigned char *lpSrc  = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		double* pDx  = Dx +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		double* pDy  = Dy +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;pDx++;pDy++;	
			if(*lpSrc==255)
				*lpSrc=254;//for display out
			if(i>1 && i<lHeight-2 && j>1 && j<lWidth-2){
				*pDx=*(lpSrc-1)-*(lpSrc+1);
				*pDy=*(lpSrc+lLineBytes)-*(lpSrc-lLineBytes);
			}
			else
			{
				*pDx=*pDy=0;
			}
		}
	}

	//3 Dx2=Dx*Dx Dy2 Dxy

	double*	Dxy;

	Dxy=new double [lLineBytes*lHeight];

	_ASSERT(Dxy != NULL);//false


	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		double* pDx  = Dx +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		double* pDy  = Dy +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		double* pDxy  = Dxy +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			pDxy++;pDx++;pDy++;			

			*pDxy=(*pDx)*(*pDy);
			*pDx=(*pDx)*(*pDx);
			*pDy=(*pDy)*(*pDy);
		}
	}

	//4 filter

	GaussFilter(Dx,25,25,4.0);
	GaussFilter(Dy,25,25,4.0);
	GaussFilter(Dxy,25,25,4.0);

	for test
	//for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
	//	unsigned char *lpSrc  = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	//	double* pDx  = Dx +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	//	double* pDy  = Dy +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	//	double* pDxy  = Dxy +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	//	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
	//		lpSrc++;pDx++;pDy++;pDxy++;			
	//	    *lpSrc=min(255,max(0,(*pDxy)/5+128));	
	//            
	//	}
	//}


	 kappa = 0.04 ... 0.06, at most 0.25 .
	const double kappa = 0.04;
	const double CxyTh = 250000;
	double maxCxy=0; 

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		unsigned char *lpSrc  = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		double* pDx  = Dx +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		double* pDy  = Dy +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		double* pDxy  = Dxy +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;pDx++;pDy++;pDxy++;			
			double A=*pDx;
			double B=*pDy;
			double C=*pDxy;
			double Cxy=(A*B-C*C)-kappa*(A+B)*(A+B);

			if(Cxy>maxCxy)
				maxCxy=Cxy;

			if(Cxy>CxyTh)
				*lpSrc=255;


		}
	}

	TRACE("\nmaxCxy=%6.1f\n",maxCxy);
	//display
	unsigned char* lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
	*(lpSrc+255*4+1)=0;*(lpSrc+255*4)=0;*(lpSrc+255*4+2)=255;

	//
	// 释放内存
	delete []Dx;
	delete []Dy;
	delete []Dxy;

	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"角点检测");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);



	EndWaitCursor();	

}


void CImageProcessView::OnUpdateObjectrecognitionPlesseycornerdetector(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}

void CImageProcessView::OnEdgeCanny()
{
	// TODO: 在此添加命令处理程序代码
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpImg;

	// 指向转置图像对应象素的指针
	unsigned char*	lpMag;
	unsigned char*	lpEdge;

	// 指向转置图像的指针
	unsigned char*	lpNewDIBBits;
	unsigned char*	lpNewDIBBits1;
	// 暂时分配内存,以保存新图像
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	// 判断是否内存分配失败
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}


	// 暂时分配内存,以保存新图像
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];

	// 判断是否内存分配失败
	if (lpNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return ;
	}

	BeginWaitCursor();

	// 针对图像每行进行操作
	lpImg=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpImg, lLineBytes * lHeight);

	//1 Gaussian Filter
	const int M=7;
	GaussFilter(M,M,1.5);//edge number down



	//2 Sobel to get Mag
	// 针对图像每行进行操作
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpImg =(unsigned char *)pDoc->m_pDib->m_lpImage+  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	lpMag =lpNewDIBBits1 + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
	// 针对每行图像每列进行操作
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{
		// 指向源DIB第i行,第j个象素的指针
		lpImg++;//
		lpMag++;//

		if(i<1 || i>=lHeight-1 || j<1 || j >=lWidth-1)
		{
			*lpMag=0;
			continue;
		}
		int valx,valy;
		valy=*(lpImg+lLineBytes-1)+*(lpImg+lLineBytes)*2+*(lpImg+lLineBytes+1)
			-*(lpImg-lLineBytes-1)-*(lpImg-lLineBytes)*2-*(lpImg-lLineBytes+1);
		valx=*(lpImg+lLineBytes-1)+*(lpImg-1)*2+*(lpImg-lLineBytes-1)
			-*(lpImg+lLineBytes+1)-*(lpImg+1)*2-*(lpImg-lLineBytes+1);
		int val=(int)(0.5+sqrt(double(valx*valx+valy*valy)));
		*lpMag=(unsigned char)min(val,255);

	}

	}

	//3 应用non-maximum 抑制
	const int DOOR=8;
	// 针对图像每行进行操作
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpMag =lpNewDIBBits1  +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	lpImg =(unsigned char *)pDoc->m_pDib->m_lpImage  + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
	lpEdge =lpNewDIBBits+ lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
	// 针对每行图像每列进行操作
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{
		// 指向源DIB第i行,第j个象素的指针
		lpImg++;//
		lpMag++;//
		lpEdge++;//
		int g,g1,g2,g3,g4;
		if(i<1 || i>lHeight-2 || j<1 || j >lWidth-2)
			*lpEdge = 0 ;
		else{
			g=*(lpMag);
			if(g>DOOR){
				int gx,gy;
				gy=*(lpImg-lLineBytes);
				gy-=*(lpImg+lLineBytes);
				gx=*(lpImg+1);
				gx-=*(lpImg-1);
				double weight;
				// 如果方向导数y分量比x分量大,说明导数的方向更加“趋向”于y分量。
				if (abs(gy) > abs(gx)) 
				{
					// 计算插值的比例
					weight = fabs((float) gx)/fabs((float) gy); 

					g2 = *(lpMag+lLineBytes) ; 
					g4 = *(lpMag-lLineBytes);

					// 如果x,y两个方向的方向导数的符号相同
					// C是当前象素,与g1-g4的位置关系为:
					//	 g1 g2 
					//		 C         
					//		 g4 g3 
					if (gx*gy > 0) 
					{ 					
						g1 = *(lpMag+lLineBytes-1) ;
						g3 =  *(lpMag-lLineBytes+1) ;
					} 

					// 如果x,y两个方向的方向导数的符号相反
					// C是当前象素,与g1-g4的位置关系为:
					//	    g2 g1
					//		 C         
					//	 g3 g4  
					else 
					{ 
						g1 =  *(lpMag+lLineBytes+1) ;
						g3 = *(lpMag-lLineBytes-1) ;
					} 
				}

				// 如果方向导数x分量比y分量大,说明导数的方向更加“趋向”于x分量
				// 这个判断语句包含了x分量和y分量相等的情况
				else
				{
					// 计算插值的比例
					weight = fabs((float) gy)/fabs((float) gx); 

					g2 =  *(lpMag+1) ; 
					g4 = *(lpMag-1) ;

					// 如果x,y两个方向的方向导数的符号相同
					// C是当前象素,与g1-g4的位置关系为:
					//	g3   
					//	g4 C g2       
					//       g1
					if (gx*gy > 0) 
					{				
						g1 =  *(lpMag-lLineBytes+1) ;
						g3 =  *(lpMag+lLineBytes-1) ;
					} 
					// 如果x,y两个方向的方向导数的符号相反
					// C是当前象素,与g1-g4的位置关系为:
					//	     g1
					//	g4 C g2       
					//  g3     
					else 
					{ 
						g1 = *(lpMag+lLineBytes+1) ;
						g3 =  *(lpMag-lLineBytes-1) ;
					}
				}

				// 下面利用g1-g4对梯度进行插值
				{
					double dTmp1 = weight*g1 + (1-weight)*g2 ;
					double dTmp2 = weight*g3 + (1-weight)*g4 ;

					// 当前象素的梯度是局部的最大值
					// 该点可能是个边界点
					if(g>=dTmp1 && g>=dTmp2)
					{
						*lpEdge =TWOVALUE_H ;
					}else *lpEdge = 0 ;

				}	

			}else *lpEdge = 0 ;

		}
	}

	}

	DisplayNewImg(lpNewDIBBits,lLineBytes,lHeight,"non-maximum Edge");

	//4应用Hysteresis,找到所有的边界


	//  估计需要的低阈值,高阈值
	int ThdHigh,ThdLow;
	int nHist[256];//
	const double dRatioHigh =0.61;//总边缘数的比例
	const double dRatioLow =0.3;//
	// 该数组的大小和梯度值的范围有关,如果采用本程序的算法,那么梯度的范围不会超过pow(2,10)

	// 初始化
	for(int k=0; k<256; k++) 
	{
		nHist[k] = 0; 
	}

	// 统计直方图,然后利用直方图计算阈值
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpMag =lpNewDIBBits1  +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	lpEdge =lpNewDIBBits+ lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
	// 针对每行图像每列进行操作
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{
		// 指向源DIB第i行,第j个象素的指针
		lpEdge++;//
		lpMag++;//
		// 只是统计那些可能是边界点,并且还没有处理过的象素
		if(*lpEdge==TWOVALUE_H)
		{
			nHist[*lpMag]++;
		}
	}
	}

	int nEdgeNb = nHist[0]  ;
	int nMaxMag = 0         ;
	// 统计经过“非最大值抑止(non-maximum suppression)”后有多少象素
	for(int k=1; k<256; k++)
	{
		if(nHist[k] != 0)
		{
			// 最大梯度值
			nMaxMag = k;
		}

		// 梯度为0的点是不可能为边界点的
		// 经过non-maximum suppression后有多少象素
		nEdgeNb += nHist[k];
	}

	// 梯度比高阈值*pnThdHigh小的象素点总数目
	int nHighCount = (int)(dRatioHigh * nEdgeNb +0.5);

	int nLowCount = (int)(dRatioLow * nEdgeNb +0.5);

	int k = 1;
	nEdgeNb = nHist[1];

	// 计算低阈值
	while( (k<(nMaxMag-1)) && (nEdgeNb < nLowCount) )
	{
		k++;
		nEdgeNb += nHist[k];
	}

	// 设置低阈值
	ThdLow = k ;

	// 计算高阈值
	while( (k<(nMaxMag-1)) && (nEdgeNb < nHighCount) )
	{
		k++;
		nEdgeNb += nHist[k];
	}

	// 设置高阈值
	ThdHigh = k ;

	TRACE("\nThdLow =%d,ThdHigh=%d\n",ThdLow ,ThdHigh);

	// 这个循环用来寻找大于nThdHigh的点,这些点被用来当作边界点,然后用
	// TraceEdge函数来跟踪该点对应的边界(大于ThdLow)
	for (int i = pDoc->StartPoint.y+1; i <pDoc->EndPoint.y; i ++)
	{	lpMag =lpNewDIBBits1  +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
	lpEdge =lpNewDIBBits+ lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
	// 针对每行图像每列进行操作
	for (int j =pDoc->StartPoint.x+1; j <pDoc->EndPoint.x; j ++)
	{
		// 指向源DIB第i行,第j个象素的指针
		lpEdge++;//
		lpMag++;//
		// 只是统计那些可能是边界点,并且还没有处理过的象素
		if(*lpEdge==TWOVALUE_H)
		{
			if(*lpMag >= ThdHigh)
			{
				// 设置该点为边界点
				*lpEdge = 255;
				TraceEdge(i, j, ThdLow, lpNewDIBBits, lpNewDIBBits1);
			}
		}
	}
	}

	//经过试验,无需反向再做一遍,

	// 那些还没有被设置为边界点的象素已经不可能成为边界点
	int Num=0;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpEdge =lpNewDIBBits+ lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{
		lpEdge++;//
		if(*lpEdge!= 255)
		{
			// 设置为非边界点
			*lpEdge = 0 ;

		}else
			Num++;
	}
	}

	TRACE("\n Total Edge Num=%d\n",Num);
	lpImg=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpImg, lpNewDIBBits,lLineBytes * lHeight);
	CString str=pDoc->GetTitle();
	pDoc->SetTitle(str+"Canny 边缘检测");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);


	// 恢复光标
	EndWaitCursor();	

	// 释放内存
	delete []lpNewDIBBits;
	delete []lpNewDIBBits1;
}

void CImageProcessView::OnUpdateEdgeCanny(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}
void CImageProcessView::TraceEdge(int y, int x,int LowThd, unsigned char* pUnchEdge, unsigned char* pnMag)
{
	// 对8邻域象素进行查询
	int xNb[8] = {1, 1, 0,-1,-1,-1, 0, 1} ;
	int yNb[8] = {0, 1, 1, 1,0 ,-1,-1,-1} ;

	int yy ;
	int xx ;

	int k  ;
	int nWidth=lLineBytes;
	for(k=0; k<8; k++)
	{
		yy =y + yNb[k] ;
		xx = x + xNb[k] ;
		// 如果该象素为可能的边界点,又没有处理过
		// 并且梯度大于阈值
		if(*(pUnchEdge+(lHeight-1-yy)*lLineBytes+xx) == 128  && *(pnMag+(lHeight-1-yy)*nWidth+xx)>=LowThd)
		{
			// 把该点设置成为边界点
			*(pUnchEdge+(lHeight-1-yy)*lLineBytes+xx) = 255 ;

			// 以该点为中心进行跟踪
			TraceEdge(yy, xx, LowThd, pUnchEdge, pnMag);
		}
	}
}
void CImageProcessView::OnSegmentationOptimal()
{

	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	//直方图数组
	int lHistogram[256]={0};

	GetHistgram(lHistogram,true);

	int iThreshold=*pDoc->m_pDib->m_lpImage;
	int iOldThreshold=-1;
	int size=(pDoc->EndPoint.x-pDoc->StartPoint.x+1)*(pDoc->EndPoint.y-pDoc->StartPoint.y+1);
	for (int i =0;i <=255;i++)
		if(	lHistogram[i]>size/10)
		{
			iThreshold=i;
			break;
		}

		//用于计算区域灰度平均值的中间变量
		int m1,m2,w1,w2;
		while(iThreshold !=iOldThreshold )
		{	iOldThreshold=iThreshold;
		m1 =0;m2=0;
		w1 =0;w2=0;
		//求两个区域的灰度平均值m and number w
		for (int i =0;i <=iOldThreshold;i++)
		{
			m1 += lHistogram[i]*i;//
			w1 += lHistogram[i];//total num
		}

		for (int i = iOldThreshold+1;i < 256;i++)
		{
			m2 += lHistogram[i]*i;
		}

		m1/=w1;
		m2/=(size-w1);
		iThreshold=(m1+m2)/2;

		}


		THRESHOLD=iThreshold;
		Fixedthreshold();

		//display Hist	

		CString str;
		str.Format("Treshold(%d)",THRESHOLD);
		DisplayDlg dlg;
		dlg.pData=&lHistogram[0];
		dlg.m_Sizex=256;
		dlg.m_Title=str;
		dlg.m_Level=1;//draw number
		dlg.m_LinePos=THRESHOLD;
		dlg.DoModal();

		// 恢复光标
		EndWaitCursor();	
}

void CImageProcessView::OnUpdateSegmentationOptimal(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnEdgeNon()
{

	CImageProcessDoc* pDoc = GetDocument();
	// 指向转置图像对应象素的指针
	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	// 指向转置图像的指针
	unsigned char*	lpNewDIBBits;
	// 暂时分配内存,以保存新图像
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	// 指向转置图像的指针
	// 判断是否内存分配失败
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}


	OnEdgeSobel();

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
	lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
	for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
	{
		lpSrc++;lpDst++;						
		if(i>0 && i<lHeight-1 && j>0 && j<lWidth-1){
			if((*lpSrc & 0x3) == 2) //------
			{
				if(*lpSrc<*(lpSrc+lLineBytes) || *lpSrc<*(lpSrc-lLineBytes))
					*lpDst=0;
			}else if((*lpSrc & 0x3) == 0)	//  |
			{
				if(*lpSrc<*(lpSrc+1) || *lpSrc<*(lpSrc-1))
					*lpDst=0;
			}
			else  if((*lpSrc & 0x3) == 1)	//  |
			{if(*lpSrc<*(lpSrc+lLineBytes+1) || *lpSrc<*(lpSrc-lLineBytes-1))
			*lpDst=0;
			}
			else {if(*lpSrc<*(lpSrc-lLineBytes+1) || *lpSrc<*(lpSrc+lLineBytes-1))
				*lpDst=0;
			}

		}else *lpDst=0;
	}
	}
	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy(lpSrc, lpNewDIBBits, lLineBytes * lHeight);
	CString str=pDoc->GetTitle();
	str+="--Non_Maximum Suppression";
	pDoc->SetTitle(str);
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::OnUpdateEdgeNon(CCmdUI *pCmdUI)
{
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}
//process after edgeed
void CImageProcessView::OnEdgeHysteresis()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	const int HighTh=80;
	const int LowTh=10;
	bool bOver=false;
	while(!bOver){
		bOver=true;
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
		{	
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
			{
				lpSrc++;						
				if(*lpSrc>LowTh && *lpSrc<HighTh){
					for(int m=-1;m<2;m++)
						for(int n=-1;n<2;n++)
						{
							if(m+i>0 && m+i<lHeight && n+j>0 && n+j<lWidth){
								if(*(lpSrc-m*lLineBytes+n)>=HighTh && ((*(lpSrc-m*lLineBytes+n) & 0x3) == (*(lpSrc) & 0x3))){
									*lpSrc=HighTh;
									bOver=false;
								}
							}
						}
				}
			}
		}
	}


	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{	
		lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++)
		{
			lpSrc++;						
			if(*lpSrc<HighTh)
				*lpSrc=0;
		}
	}

	CString str=pDoc->GetTitle();
	str+="--Hysteresis to filter";
	pDoc->SetTitle(str);
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

}

void CImageProcessView::OnUpdateEdgeHysteresis(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}

void CImageProcessView::OnHoughCircle()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();
	CPoint StartPoint=pDoc->StartPoint;
	CPoint EndPoint=pDoc->EndPoint;

	BeginWaitCursor();

	const int aMax=512;//center x(0-aMax)
	const int bMax=512;//center y(0-bMax)
	const int rMin=25;//radium //
	const int rMax=80;//radium

	int dx=max(EndPoint.y-StartPoint.y,EndPoint.y-StartPoint.y)/min(aMax,bMax)+1;

	int (*pArray)[bMax][rMax-rMin]=new int [aMax][bMax][rMax-rMin];
	//init  
	for(int k=0;k<aMax;k++)
		for(int m=0;m<bMax;m++)
			for(int r=0;r<rMax-rMin;r++)
				pArray[k][m][r]=0;

	const double pi=3.14159;

	unsigned char* lpSrc;
	//get pArray
	for (int i = StartPoint.y; i <=EndPoint.y; i ++)
	{	lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + StartPoint.x-1;
	for (int j =StartPoint.x; j <=EndPoint.x; j ++)
	{
		lpSrc++;
		if(*lpSrc)
		{
			for(int theta=0;theta<360;theta+=2)
				for(int r=rMin;r<rMax;r++)
				{

					int a=j-StartPoint.x-int(cos((float)theta*pi/180)*r+0.5);
					int b=i-StartPoint.y-int(sin((float)theta*pi/180)*r+0.5);
					if(a>=0 && a/dx<aMax && b>=0 && b/dx<bMax){			    
						pArray[a/dx][b/dx][r-rMin]++;
					}
				}
		}
	}
	}



	int N_value=200;
	int N_MaxVal=100;
	vector <bool> Err;//重合点数少判为err
	int  kk=0;//times


	while(N_value>N_MaxVal && kk<30)
	{kk++;

	//查找计数器数组中的最大值
	int Max=0;
	int A=-1,B=-1,R=-1;
	for(int r=0;r<rMax-rMin;r++)
	{
		for(int a=0;a<aMax;a++)
			for(int b=0;b<bMax;b++)
			{
				if(pArray[a][b][r]>Max)
				{
					Max=pArray[a][b][r];
					A=a;
					B=b;
					R=r+rMin;
				}
			}
	}


	A=A*dx;//chg
	B=B*dx;

	CString str;
	str.Format("\n%d: (a: %d  b: %d r: %d ) Max:%d\n",kk,A+StartPoint.x,B+StartPoint.y,R,Max);
	TRACE(str);


	//将最大值点附近清零
	for(int r=-R/2;r<R/2;r++)
	{   for(int a=A-R/2;a<=A+R/2;a++)
	for(int b=B-R/2;b<=B+R/2;b++)
	{   
		if(a>=0 && a<aMax*dx)
			if(b>=0 && b<bMax*dx)
				if(r+R>=rMin && r+R<rMax)

				{
					pArray[a/dx][b/dx][r+R-rMin]=0;
				}
	}
	}

	N_value=Max;
	N_MaxVal=20+R/2;
	if(dx>1) N_MaxVal+=(dx-1)*R;//if dx>1 have more point

	A+=StartPoint.x;
	B+=+StartPoint.y;
	if(N_value>N_MaxVal){
		int num=0;
		int allnum=0;
		//Draw a circle	(A,B,R) to get poin or point--circle 
		int x=0;
		int y=R;
		int p=1-R;
		while(x<y){
			x++;
			if(p<0) 
				p+=2*x+1;
			else
			{
				y--;
				p+=2*(x-y)+1;
			}
			for(int i=-1;i<2;i+=2)//-1,1
				for(int j=-1;j<2;j+=2)//-1,1
				{
					if(A+i*x>=StartPoint.x && A+i*x<=EndPoint.x && B+j*y>=StartPoint.y && B+j*y<=EndPoint.y)
					{
						lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-B-j*y) +A+i*x;
						if(*lpSrc==TWOVALUE_H) num++;
						*lpSrc=(unsigned char)(min(200+kk,255));allnum++;

					}
					if(A+i*y>=StartPoint.x && A+i*y<=EndPoint.x && B+j*x>=StartPoint.y && B+j*x<=EndPoint.y)
					{
						lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-B-j*x) +A+i*y;
						if(*lpSrc==TWOVALUE_H) num++;
						*lpSrc=(unsigned char)(min(200+kk,255));allnum++;
					}


				}
		}

		if(num>allnum/5 && num>N_value/3)
			Err.push_back(true);
		else
			Err.push_back(false);	
	}
	}
	// 复制图像
	//lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	//memcpy( lpSrc,lpNewDIBBits, lLineBytes * lHeight);


	LPRGBQUAD pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable+200;
	for(int i=0;i<min(kk,255);i++){
		// 更新DIB调色板红色分量
		pDibQuad->rgbRed = 255;

		// 更新DIB调色板绿色分量
		pDibQuad->rgbGreen =i*10%256;

		// 更新DIB调色板蓝色分量
		pDibQuad->rgbBlue = 0;
		pDibQuad ++;
	}

	//display err find in blue
	if(Err.size()>0){
		for(int i=0;i<(int)Err.size();i++)
		{
			if(!Err[i]){
				pDibQuad = (LPRGBQUAD) pDoc->m_pDib->m_lpvColorTable+200+i+1;
				pDibQuad->rgbRed =0;pDibQuad->rgbGreen =0;pDibQuad->rgbBlue = 255;
			}

		}
	}
	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	// 恢复光标
	EndWaitCursor();	

	delete []pArray;
}

void CImageProcessView::OnUpdateHoughCircle(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnSegmentationDynamic()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	CPoint StartPoint=pDoc->StartPoint;
	CPoint EndPoint=pDoc->EndPoint;

	BeginWaitCursor();

	unsigned char*	lpSrc;
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		return ;
	}


	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	const int M=25;
	const int N=25;
	const int Gdiff=10;


	//if select small area display data
	int Data[256*3]={0};
	bool bDisplay=false;//draw line?
	if((EndPoint.x-StartPoint.x)<256) 
		bDisplay=true;

	int minMean=255;
	int maxMean=0;
	int maxDiff=0;
	unsigned char* lpDst;
	for (int i = StartPoint.y; i <=EndPoint.y; i ++)	{
		for (int j = StartPoint.x; j <= EndPoint.x; j ++){
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + j;
			lpDst=lpNewDIBBits +  lLineBytes* (lHeight-1-i) + j;
			*lpSrc=TWOVALUE_H;
			int mean=*lpDst;
			if(i>=N/2 && i<lHeight-N/2 && j>=M/2 && j<lWidth-M/2){
				int add=0;
				int num=0;

				for(int m=-M/2;m<=M/2;m++)
					for(int n=-N/2;n<=N/2;n++)
					{   if(*(lpDst+lLineBytes* n + m)>(*lpDst+5))
					{
						add+=*(lpDst+lLineBytes* n + m);
						num++;
					}
					}
					if(num>N*M/3)
						mean=add/num;

					if(mean-(*lpDst)>Gdiff)
					{
						*lpSrc=TWOVALUE_L;
						if(mean-(*lpDst)>maxDiff) maxDiff=mean-(*lpDst);
						if(mean>maxMean) maxMean=mean;
						if(mean<minMean) minMean=mean;
					}


			}
			if(bDisplay){
				if(i==(EndPoint.y/2+StartPoint.y/2)){
					Data[min(j- StartPoint.x,199)]=mean-*lpDst;//max(mean-*lpDst,0);
					Data[256+min(j- StartPoint.x,199)]=*lpDst;
					Data[512+min(j- StartPoint.x,199)]=mean;
				}
			}
		}
	}



	if(bDisplay){


		CString str;
		str.Format("minMean=%d maxMean=%d  maxDiff=%d",minMean,maxMean,maxDiff);
		DisplayDlg dlg;
		dlg.pData=&Data[0];
		dlg.m_Sizex=256;
		dlg.m_Title=str;
		dlg.m_Level=3;//draw number
		dlg.m_LinePos=0;
		dlg.DoModal();


	}

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	DisplayNewImg(lpNewDIBBits, lLineBytes ,lHeight,"Origin Image");

	EndWaitCursor();	
	delete [] lpNewDIBBits;
}

void CImageProcessView::OnUpdateSegmentationDynamic(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnSpatialdomainZoombilinearinterpolation()
{
	// TODO: Add your command handler code here


	BeginWaitCursor();

	ZoomDblLinear(1.8,1.8);//zoom out

	ZoomDblLinear(.8,.8);//zoom in

	EndWaitCursor();	

}

void CImageProcessView::OnUpdateSpatialdomainZoombilinearinterpolation(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);

}

void CImageProcessView::ZoomDblLinear(double fx, double fy)
{
	CImageProcessDoc* pDoc = GetDocument();

	CPoint StartPoint=pDoc->StartPoint;
	CPoint EndPoint=pDoc->EndPoint;
	unsigned char*	lpSrc;

	// 指向转置图像对应象素的指针
	unsigned char*	lpDst;


	//if scaled down get smooth first; else : aliasing effects
	if(fx<1.0 || fy<1.0)
		GaussFilter(5,5,0);


	int w,h,l;

	h=(int)(fy*(EndPoint.y-StartPoint.y+1));
	w=(int)(fx*(EndPoint.x-StartPoint.x+1));

	l=(w+3)/4*4;

	unsigned char *lpNewDIBBits=new unsigned char [h * l];
	// 判断是否内存分配失败
	if (lpNewDIBBits == NULL)
	{
		// 分配内存失败
		return ;
	}

	//out image
	for(int i = 0; i < h; i++)
	{
		// 列
		for(int j = 0; j <w ; j++)
		{
			// 指向DIB第i行,第j个象素的指针
			lpDst = (unsigned char*)lpNewDIBBits + l * (h - 1 - i) + j;
			double x=j/fx;
			double y=i/fy;

			int x1=(int)x;
			int y1=(int)y;
			if(x1+StartPoint.x>=0 && x1+StartPoint.x<lWidth-1 && y1+StartPoint.y>=0 && y1+StartPoint.y<lHeight-1){//in
				lpSrc = (unsigned char*)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - y1-StartPoint.y) + x1+StartPoint.x;
				int v=(unsigned char)((y1+1-y)*((x1+1-x)*(*lpSrc)+(x-x1)*(*(lpSrc+1)))
					+(y-y1)*((x1+1-x)*(*(lpSrc-lLineBytes))+(x-x1)*(*(lpSrc-lLineBytes+1))));//a=x-x1 b=y-y1 
				if(v<0) v=0;
				else if(v>255) v=255;
				*lpDst=(BYTE)v;
			}else
				*lpDst=*(pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - (int)(y+0.5)-StartPoint.y) + (int)(x+0.5)+StartPoint.x);//近邻插值

		}

	}

	CString str;
	str.Format("Scaling by (%3.2f %3.2f)",fx,fy);
	DisplayNewImg(lpNewDIBBits, l ,h,str);

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	// 释放内存
	delete []lpNewDIBBits;

	return ;



}
void CImageProcessView::OnUpdateApplicationContourtrace(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	pCmdUI->Enable(m_bTwoValue);

}

//obj:black
//1)能获取多个边界及参数
//2)获取周长
//3)存储边界点
//4)计算面积
//5)显示边界图形
//可以在标记后再进行跟踪,无需考虑处理的区域了,每个标号仅有一个起始点

void CImageProcessView::OnApplicationContourtrace()
{
	 TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();


	BeginWaitCursor();

	unsigned char*	lpSrc;

	//1 置处理边沿为背景
	for (int j = pDoc->StartPoint.y;j <= pDoc->EndPoint.y ;j++)
	{
		for(int i = pDoc->StartPoint.x;i <= pDoc->EndPoint.x ;i++)
		{
			if(i == pDoc->StartPoint.x || i == pDoc->EndPoint.x ||  j == pDoc->StartPoint.y || j == pDoc->EndPoint.y)
			{
				lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-j) + i;
				*lpSrc=TWOVALUE_H;
			}
		}
	}

	BOOL bFindStartPoint;
	CPoint StartPoint;
	int SearchNo=0;
	const int MaxAreaNum=20;
	CRect Area[MaxAreaNum];
	while(SearchNo<MaxAreaNum){

		//初始化处理区域大小(为后面比较最大最小值)
		Area[SearchNo].left=lWidth;
		Area[SearchNo].top=lHeight;
		Area[SearchNo].right=0;
		Area[SearchNo].bottom=0;

		//获取起始点 StartPoint
		bFindStartPoint = false;
		for (int j = pDoc->StartPoint.y;j <= pDoc->EndPoint.y && !bFindStartPoint;j++)
		{
			for(int i = pDoc->StartPoint.x;i <= pDoc->EndPoint.x && !bFindStartPoint;i++)
			{
				lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-j) + i;

				if(*lpSrc == 0)//obj
				{

					bFindStartPoint = true;

					StartPoint.y = j;
					StartPoint.x = i;
					//确定该点不在已经处理的区域内
					int k_tmp=0;
					while(k_tmp<SearchNo){
						if(StartPoint.x<=Area[k_tmp].right && StartPoint.x>=Area[k_tmp].left
							&& StartPoint.y<=Area[k_tmp].bottom && StartPoint.y>=Area[k_tmp].top)
							bFindStartPoint = false;

						k_tmp++;
					}

				}		
			}
		}

		if(!bFindStartPoint) break;//无新未处理的区域,退出循环

		//八个方向和起始扫描方向
		int Direction[8][2]={{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}};//

		//由于起始点是在左上方,故起始扫描沿左下方向
		int BeginDirect = 5;//

		//跟踪边界
		CPoint CurrentPoint;
		//从初始点开始扫描
		CurrentPoint.y = StartPoint.y;
		CurrentPoint.x = StartPoint.x;

		//起始点
		//memorey area
		if(CurrentPoint.x<Area[SearchNo].left)Area[SearchNo].left=CurrentPoint.x;
		if(CurrentPoint.x>Area[SearchNo].right)Area[SearchNo].right=CurrentPoint.x;
		if(CurrentPoint.y<Area[SearchNo].top)Area[SearchNo].top=CurrentPoint.y;
		if(CurrentPoint.y>Area[SearchNo].bottom)Area[SearchNo].bottom=CurrentPoint.y;


		vector<CPoint> edgePt;
		edgePt.push_back(CurrentPoint);
		double perimeter=0.0;
		while(1)
		{
			//沿扫描方向查看一个像素
			lpSrc = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1- CurrentPoint.y - Direction[BeginDirect][1])
				+ (CurrentPoint.x + Direction[BeginDirect][0]);

			if(*lpSrc == 0)//obj
			{
				CurrentPoint.y = CurrentPoint.y + Direction[BeginDirect][1];
				CurrentPoint.x = CurrentPoint.x + Direction[BeginDirect][0];

				//获取周长
				if(BeginDirect%2) perimeter+=1.414;
				else      perimeter+=1;

				//存储边界点
				edgePt.push_back(CurrentPoint);

				if(CurrentPoint.y == StartPoint.y && CurrentPoint.x == StartPoint.x)
					break;//out while (闭合)

				//memorey area
				if(CurrentPoint.x<Area[SearchNo].left)Area[SearchNo].left=CurrentPoint.x;
				if(CurrentPoint.x>Area[SearchNo].right)Area[SearchNo].right=CurrentPoint.x;
				if(CurrentPoint.y<Area[SearchNo].top)Area[SearchNo].top=CurrentPoint.y;
				if(CurrentPoint.y>Area[SearchNo].bottom)Area[SearchNo].bottom=CurrentPoint.y;

				//扫描的方向顺时针旋转两格
				BeginDirect--;
				if(BeginDirect == -1)
					BeginDirect = 7;
				BeginDirect--;
				if(BeginDirect == -1)
					BeginDirect = 7;



			}
			else
			{
				//扫描方向逆时针旋转一格
				BeginDirect++;
				if(BeginDirect == 8)
					BeginDirect = 0;



			}
		}

		SearchNo++;

		//计算面积
		int S=0;
		for(int i=0;i<(int)edgePt.size()-1;i++)
			S+=(edgePt[i].x*edgePt[i+1].y-edgePt[i+1].x*edgePt[i].y) ;
		S/=2;
		if(S<0) S=-S;

		TRACE("\nNo=%d,面积=%d,周长=%3.1f,圆形度=%3.1f\n",SearchNo,S,perimeter,perimeter*perimeter/S);//

		CDC *pdc = GetDC();


		//显示边界图形
		for(int i=0;i<(int)edgePt.size();i++)
			pdc->SetPixel(edgePt[i],RGB(255,0,0)) ;//

		ReleaseDC(pdc);

	}


	CString str;
	str.Format("\nContour Number is %d\n",SearchNo);
	TRACE(str);
	//MessageBox(str,"Message ",MB_OK);


	EndWaitCursor();	

}


void CImageProcessView::OnEdgeTrace()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();


	BeginWaitCursor();

	CPoint StartPoint=pDoc->StartPoint;
	CPoint EndPoint=pDoc->EndPoint;
	unsigned char*	lpSrc;
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];
	if (lpNewDIBBits == NULL)
	{
		return ;
	}


	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

	//1 get start Point=maxGrad point
	CPoint stPt;
	unsigned char* lpDst;
	double maxGrad=0;
	double last_angle=0;
	for (int i = StartPoint.y; i <=EndPoint.y; i ++)	{
		for (int j = StartPoint.x; j <= EndPoint.x; j ++){
			lpDst=lpNewDIBBits +  lLineBytes* (lHeight-1-i) + j;

			*lpDst=min(*lpDst,254);

			if(i>=1 && i<lHeight-1 && j>=1 && j<lWidth-1){
				CPoint pt=CPoint(j,i);
				double grad=0.0;
				double angle=0.0;
				Gradient(pt,&grad,&angle);
				if(grad>maxGrad){
					maxGrad=grad;
					last_angle=angle;
					stPt=pt;
				}

			}
		}
	}

	if(maxGrad<10)
	{
		delete[]lpNewDIBBits;
		return;
	}
	//根据边缘方向调整 0: |o (6)
	int Direction[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};//


	const double DiffTh=maxGrad/2;

	CPoint pt=stPt;
	int no=0;
	while(1){

		lpDst=lpNewDIBBits +  lLineBytes* (lHeight-1-pt.y) + pt.x;
		*lpDst=255;


		CPoint nextpt;
		//下一点位置获取

		int dir=int((last_angle+22.5)/45);

		if((last_angle+22.5)>=360)
			dir=0;


		//边缘
		double grad1=0.0;
		double angle1=0.0;
		CPoint nextpt1=CPoint(pt.x+Direction[dir][0],pt.y+Direction[dir][1]);

		Gradient(nextpt1,&grad1,&angle1);

		double grad2=0.0;
		double angle2=0.0;
		dir++;
		if(dir>8) dir=0;
		CPoint nextpt2=CPoint(pt.x+Direction[dir][0],pt.y+Direction[dir][1]);
		Gradient(nextpt2,&grad2,&angle2);

		double grad=0.0;
		double angle=0.0;
		if(grad2>grad1){
			grad=grad2;
			angle=angle2;
			nextpt=nextpt2;
		}else
		{
			grad=grad1;
			angle=angle1;
			nextpt=nextpt1;

		}

		double diff=abs(last_angle-angle);
		if(diff>315) diff=0;
		if(grad>DiffTh && diff<45){
			last_angle=angle;
			pt=nextpt;

		}
		else{

			//修正角度
			//可能不需要,
			//find max grad near pt
			double maxGrad=0;
			double tmpangle=last_angle;
			for(int m=-1;m<2;m++)
				for(int n=-1;n<2;n++){
					CPoint tmpPt=pt;
					tmpPt.x+=m;tmpPt.y+=n;
					lpDst=lpNewDIBBits +  lLineBytes* (lHeight-1-tmpPt.y) + tmpPt.x;
					if(*lpDst<255){
						double grad=0.0;
						double angle=0.0;
						Gradient(tmpPt,&grad,&angle);
						if(abs(angle-last_angle)<15)//5 err!
							grad*=1.2;
						if(grad>maxGrad ){
							maxGrad=grad;
							nextpt=tmpPt;
							tmpangle=angle;
						}

					}
				}

				pt=nextpt;
				last_angle=tmpangle;

		}
		no++;

		// out of while
		if(no>10){
			if(abs(pt.x-stPt.x)<2 && abs(pt.y-stPt.y)<2){
				lpDst=lpNewDIBBits +  lLineBytes* (lHeight-1-pt.y) + pt.x;
				//set 255
				*lpDst=255;

				break;
			}
		}

		if(no>10000) break;//防止死循环
	}


	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);

	//display
	lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
	*(lpSrc+255*4+1)=0;*(lpSrc+255*4)=0;*(lpSrc+255*4+2)=255;

	pDoc->SetTitle("Edge Trace Image");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	EndWaitCursor();	
	delete [] lpNewDIBBits;
}

void CImageProcessView::OnUpdateEdgeTrace(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	//if(m_bTwoValue) bAvail=false;
	pCmdUI->Enable(bAvail);
}




void CImageProcessView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: Add your message handler code here and/or call default
	//微调(+、- 1)处理窗口大小
	CImageProcessDoc* pDoc = GetDocument();
	switch(nChar){
	case VK_LEFT:

		if(pDoc->StartPoint.x--<=0)
			pDoc->StartPoint.x=0;

		break;
	case VK_RIGHT:
		if(pDoc->EndPoint.x++>=lWidth-1)
			pDoc->EndPoint.x=lWidth-1;
		break;
	case VK_UP:
		if(pDoc->StartPoint.y--<=0)
			pDoc->StartPoint.y=0;
		break;
	case VK_DOWN:
		if(pDoc->EndPoint.y++>=lHeight-1)
			pDoc->EndPoint.y=lHeight-1;
		break;

	}


	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);
	CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
}

void CImageProcessView::OnSmoothTrun()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();
	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);



	const int M=13;//odd
	const int N=15;//odd

	TrunMedianFilter(M,N);

	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str+"--++截断中值滤波");//display orignal image


	//get img back
	pDoc->SetTitle(str);
	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);


	delete [] lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::OnUpdateSmoothTrun(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	if(m_bTwoValue) bAvail=false;
	pCmdUI->Enable(bAvail);
}
void CImageProcessView::TrunMedianFilter(int M,int N)
{
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;

	unsigned char*	lpDst;

	lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
	memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);



	//unsigned char *v=new unsigned char[M*N];//[N*M];//line N Column M not rect (int err) 
	vector<unsigned char> v(M*N,0);
	const int Th=(M*N)/2;//Mid Pos

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;

		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			lpDst++;
			if(i>=M/2 && i<lHeight-M/2 && j>=N/2 && j<lWidth-N/2){
				//Get M*N data to v[]
				int vSize=0;
				int aver=0;
				for(int m=-M/2;m<=M/2;m++)
					for(int n=-N/2;n<=N/2;n++)
					{	v[vSize]=*(lpSrc+lLineBytes*m+n);
				aver+=v[vSize];
				vSize++;
				}

				aver/=vSize;
				//sort v[]
				for(int m=0;m<M*N-1;m++)
					for(int n=m+1;n<M*N;n++)
					{
						if(v[m]>v[n]){
							//swap
							BYTE tmp=v[m];
							v[m]=v[n];
							v[n]=tmp;
						}
					}

					//截断
					int lower=v[0];
					int upper=v[vSize-1];
					if(aver>v[Th])
						upper=2*v[Th]-lower;
					else
						lower=2*v[Th]-upper;
					int pos1=0;
					int pos2=vSize-1;
					while(lower>v[pos1])
						pos1++;
					while(upper<v[pos2])
						pos2--;

					//取中值
					*(lpDst)=(unsigned char)v[(pos1+pos2)/2];

			}
		}
	}


	// 释放内存
	delete []lpNewDIBBits;
	//delete []v;

}
void CImageProcessView::OnSmoothAnisotropicdiffusion()
{
	// TODO: Add your command handler code here
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();
	//copy img
	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
		return ;

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);



	AnisotropicDiffusion();

	CString str=pDoc->GetTitle();

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,str+"--++各向异性扩散滤波");//display orignal image


	//get img back
	pDoc->SetTitle(str);
	memcpy( pDoc->m_pDib->m_lpImage,lpNewDIBBits, lLineBytes * lHeight);

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);


	delete [] lpNewDIBBits;

	// 恢复光标
	EndWaitCursor();	
}

void CImageProcessView::AnisotropicDiffusion(){
	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	if (lpNewDIBBits == NULL)
	{
		return ;
	}

	unsigned char*	lpSrc;

	unsigned char*	lpDst;



	const int k=5;
	const float lamda=0.25f;

	for(int t=0;t<20;t++)//迭代
	{
		lpSrc=(unsigned char *)pDoc->m_pDib->m_lpImage;
		memcpy( lpNewDIBBits,lpSrc, lLineBytes * lHeight);

		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;

			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpSrc++;
				lpDst++;
				if(i>=1 && i<lHeight-1 && j>=1 && j<lWidth-1){

					//获取变化
					float dN=(float)(*(lpSrc+lLineBytes)-*(lpSrc));
					float dS=(float)(*(lpSrc-lLineBytes)-*(lpSrc));
					float dE=(float)(*(lpSrc-1)-*(lpSrc));
					float dW=(float)(*(lpSrc+1)-*(lpSrc));

					/*int v=*(lpSrc)+(int)(lamda*(dN/(1+dN*dN/k/k)+dS/(1+dS*dS/k/k)+
					dE/(1+dE*dE/k/k)+dW/(1+dW*dW/k/k)));*/
					int v=*(lpSrc)+(int)(lamda*(dN*exp(-dN*dN/k/k)+dS*exp(-dS*dS/k/k)+
						dE*exp(-dE*dE/k/k)+dW*exp(-dW*dW/k/k)));
					if(v>255) v=255;
					else if(v<0) v=0;

					*lpDst=(BYTE)v;

				}			

			}
		}

	}


	// 释放内存
	delete []lpNewDIBBits;

}


void CImageProcessView::OnUpdateSmoothAnisotropicdiffusion(CCmdUI *pCmdUI)
{
	// TODO: Add your command update UI handler code here
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	if(m_bTwoValue) bAvail=false;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnGrayReconstruction()
{
	// TODO: Add your command handler code here

	BeginWaitCursor();

	CImageProcessDoc* pDoc = GetDocument();

	CDemoTimer exeTimer;
	exeTimer.Reset();


	//1 2x20 Se

	//se = strel('disk', 20)

	const int M=39;
	const int N=39;

	动态定义三维数组:

	//int *** p3 ;//[ hight][ row][ col]

	//p3 = new int**[hight ] ;


	int **S;

	S =  new int * [M];//S[M][N]
	for (int i = 0; i < M; i++) {
		S[i] = new int[N] ;
	}

	for (int i = 0; i < M; i++) 
		for (int j = 0; j < N; j++)
		{ 
			if((i-M/2)*(i-M/2)+(j-N/2)*(j-N/2)<=20*20)
				S[i][j]=0;

			else
				S[i][j]=-1;
		}


		//掩膜图像 原图:(lpNewDIBBits)

		unsigned char*	lpNewDIBBits;
		lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

		_ASSERT(lpNewDIBBits != NULL);//false

		memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);


		//GrayErosion(S,M,N);//7s 578 ms

		GrayFastOperate(false);


		TRACE("\nUsed Time is %.3f ms\n",exeTimer.GetTime(false)*1000);


		标记图像 腐蚀 :pDoc->m_pDib->m_lpImage


		ReConstruction(pDoc->m_pDib->m_lpImage,lpNewDIBBits);

		TRACE("\nUsed Time is %.3f ms\n",exeTimer.GetTime(false)*1000);



		memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);
		//掩膜图像:(lpNewDIBBits)
		//

		//GrayDilation(S,M,N);

		GrayFastOperate(true);

		//标记图像 膨胀运算pDoc->m_pDib->m_lpImage

		unsigned char*	lpSrc;
		unsigned char*	lpDst;


		// 掩膜图像\标记图像 取反
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpDst = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpSrc++;lpDst++;
				*(lpSrc)=255-(*lpSrc);
				*(lpDst)=255-(*lpDst);


			}
		}

		//重构
		ReConstruction(pDoc->m_pDib->m_lpImage,lpNewDIBBits);

		// 重构图像 取反
		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
			lpDst = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpDst++;
				*(lpDst)=255-(*lpDst);


			}
		}

		TRACE("\nUsed Time is %.3f ms\n",exeTimer.GetTime(false)*1000);


		CString str=pDoc->GetTitle();

		pDoc->SetTitle(str+"重构");

		InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

		for(int i=0;i<M;i++)
			delete []S[i];
		delete []S;

		// 释放内存
		delete []lpNewDIBBits;

		// 恢复光标
		EndWaitCursor();	
}

void CImageProcessView::GrayFastOperate(bool bDilate){

	CImageProcessDoc* pDoc = GetDocument();

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	_ASSERT(lpNewDIBBits != NULL);//false

	memcpy( lpNewDIBBits,pDoc->m_pDib->m_lpImage, lLineBytes * lHeight);

	//结构分解:
	//seq = getsequence(se)

	unsigned char*	lpSrc;
	unsigned char*	lpDst;

	//1)
	int M=15;
	int N=15;
	//腐蚀运算,定义域内输入数据减对应模板数据,并求最小值,该最小值便是该点输出
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			//for (int m = 0; m < M; m++)
			int m=M/2;
			{
				for (int n = 0; n < N; n++)
				{  // if(S[m][n]<0) continue;
					if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth)
					{
						int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2));//-S[m][n];
						if(bDilate)
						{if(tmp>gray) gray=tmp;}//max
						else
						{	if(tmp<gray) gray=tmp;}//min



					}
				}
			}

			*lpDst=(BYTE)gray;

		}
	}

	//2)
	M=11;N=11;
	//腐蚀运算,定义域内输入数据减对应模板数据,并求最小值,该最小值便是该点输出
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =(unsigned char *)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			for (int m = 0; m < M; m++)
			{
				//for (int n = 0; n < N; n++)
				int n=m;
				{  // if(S[m][n]<0) continue;
					if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth)
					{
						int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2));//-S[m][n];
						if(bDilate)
						{if(tmp>gray) gray=tmp;}//max
						else
						{	if(tmp<gray) gray=tmp;}//min

					}
				}
			}

			*lpDst=(BYTE)gray;

		}
	}

	//3
	M=15;
	N=15;

	//腐蚀运算,定义域内输入数据减对应模板数据,并求最小值,该最小值便是该点输出
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			for (int m = 0; m < M; m++)
			{
				//for (int n = 0; n < N; n++)
				int n=m/2;
				{   //if(S[m][n]<0) continue;
					if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth)
					{
						int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2));//-S[m][n];
						if(bDilate)
						{if(tmp>gray) gray=tmp;}//max
						else
						{	if(tmp<gray) gray=tmp;}//min
					}
				}
			}

			*lpDst=(BYTE)gray;

		}
	}

	//4)
	M=11;N=11;
	//腐蚀运算,定义域内输入数据减对应模板数据,并求最小值,该最小值便是该点输出
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = lpNewDIBBits +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =(unsigned char *)pDoc->m_pDib->m_lpImage + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			for (int m = 0; m < M; m++)
			{
				//for (int n = 0; n < N; n++)
				int n=N-1-m;
				{  // if(S[m][n]<0) continue;
					if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth)
					{
						int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2));//-S[m][n];
						if(bDilate)
						{if(tmp>gray) gray=tmp;}//max
						else
						{	if(tmp<gray) gray=tmp;}//min
					}
				}
			}

			*lpDst=(BYTE)gray;

		}
	}

	//5
	M=5;
	N=5;

	//腐蚀运算,定义域内输入数据减对应模板数据,并求最小值,该最小值便是该点输出
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			for (int m = 0; m < M; m++)
			{
				//for (int n = 0; n < N; n++)
				int n=m/2;
				{   //if(S[m][n]<0) continue;
					if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth)
					{
						int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2));//-S[m][n];
						if(bDilate)
						{if(tmp>gray) gray=tmp;}//max
						else
						{	if(tmp<gray) gray=tmp;}//min

					}
				}
			}

			*lpDst=(BYTE)gray;

		}
	}
	//6
	M=5;
	N=5;
	//腐蚀运算,定义域内输入数据减对应模板数据,并求最小值,该最小值便是该点输出
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++){
		lpDst = (unsigned char *)pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;lpDst++;
			int gray=*lpSrc;

			//for (int m = 0; m < M; m++)
			int m=M/2;
			{
				for (int n = 0; n < N; n++)
				{  // if(S[m][n]<0) continue;
					if(i-M/2 + m>=0 && i-M/2 +m<lHeight && j+n - N/2>=0 && j+n - N/2<lWidth)
					{
						int tmp=*(lpSrc + lLineBytes*(M/2 - m)  +(n - N/2));//-S[m][n];
						if(bDilate)
						{if(tmp>gray) gray=tmp;}//max
						else
						{	if(tmp<gray) gray=tmp;}//min

					}
				}
			}

			*lpDst=(BYTE)gray;

		}
	}

	// 释放内存
	delete []lpNewDIBBits;
}

void CImageProcessView::ReConstruction(unsigned char* lpLevel,unsigned char* lpMasked){

	//

	CImageProcessDoc* pDoc = GetDocument();
	unsigned char*	lpSrc;
	unsigned char*	lpDst;
	unsigned char*	lpMask;

	unsigned char*	lpNewDIBBits;
	lpNewDIBBits=new unsigned char [lLineBytes*lHeight];

	_ASSERT(lpNewDIBBits != NULL);//false

	unsigned char*	lpNewDIBBits1;
	lpNewDIBBits1=new unsigned char [lLineBytes*lHeight];

	_ASSERT(lpNewDIBBits1 != NULL);//false

	memcpy(lpNewDIBBits, lpLevel, lLineBytes * lHeight);
	memcpy(lpNewDIBBits1, lpLevel, lLineBytes * lHeight);

	bool bChg=true;

	int num=0;
	while(bChg)
	{
		num++;
		bChg=false;
		//memcpy( lpLevel,lpNewDIBBits, lLineBytes * lHeight);

		水平膨胀运算

		for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
		{
			lpSrc = lpLevel +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			lpDst =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <=pDoc->EndPoint.x-1; j ++){
				lpSrc++;lpDst++;			
				*lpDst=max(*lpSrc,max(*(lpSrc+1),*(lpSrc-1)));						;
			}
		}

		垂直膨胀运算
		for (int i = pDoc->StartPoint.y+1; i <=pDoc->EndPoint.y-1; i ++)
		{
			lpDst = lpNewDIBBits1 +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
			lpSrc =lpNewDIBBits + lLineBytes * (lHeight - 1 - i)+ pDoc->StartPoint.x-1;
			for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
				lpSrc++;lpDst++;

				*lpDst=max(*lpSrc,max(*(lpSrc+lLineBytes),*(lpSrc-lLineBytes)));

			}
		}


		//比较运算
		for (int i = pDoc->StartPoint.y+1; i <=pDoc->EndPoint.y-1; i ++)
		{
			lpSrc = lpLevel +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			lpMask= lpMasked+  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			lpDst =lpNewDIBBits1 +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <=pDoc->EndPoint.x-1; j ++){
				lpDst++;lpMask++;lpSrc++;
				if(*lpDst>*lpMask)
					*lpDst=*lpMask;

				if((*lpDst)!=(*lpSrc)){	
					bChg=true;
					*lpSrc=*lpDst;
				}
			}

		}



	}

	TRACE("\nnum=%d\n",num);

	memcpy( pDoc->m_pDib->m_lpImage,lpLevel, lLineBytes * lHeight);

	// 释放内存
	delete []lpNewDIBBits;
	delete []lpNewDIBBits1;
}

void CImageProcessView::OnEdgeRelaxation()
{
	// TODO: 在此添加命令处理程序代码
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	CPoint* pEdgeInfo;//i | j      // i - j


	pEdgeInfo=new CPoint [lLineBytes*lHeight];

	_ASSERT(pEdgeInfo != NULL);//false

	CPoint* pEdgeInfo1;
	//i | j      
	// i 
	// - 
	// j


	pEdgeInfo1=new CPoint [lLineBytes*lHeight];

	_ASSERT(pEdgeInfo1 != NULL);//false


	//1 init  c(e)=0---100
	int eMax=200;
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{
		unsigned char* lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		CPoint * pEdge =pEdgeInfo +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;pEdge++;
			if(i==pDoc->EndPoint.y || j==pDoc->EndPoint.x)
				*pEdge=CPoint(0,0);
			else
			{
				(*pEdge)=CPoint(abs(*lpSrc-*(lpSrc+1)),abs(*lpSrc-*(lpSrc-lLineBytes)));
				if((*pEdge).x>eMax)
					eMax=(*pEdge).x;
				if((*pEdge).y>eMax)
					eMax=(*pEdge).y;

			}
		}
	}
	//
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{
		CPoint * pEdge =pEdgeInfo +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			pEdge++;
			(*pEdge).x=min(90,(*pEdge).x*200/eMax);
			(*pEdge).y=min(90,(*pEdge).y*200/eMax);
			if((*pEdge).x<10)// && (*pEdge).x>5)//q=10 not type err!
				(*pEdge).x=0;
			if((*pEdge).y<10)// && (*pEdge).y>5)
				(*pEdge).y=0;


		}
	}


	//2迭代num
	const int num=100;

	int no=0;
	const int q=10;
	const int delt=20;
	int type[4];

	bool bOver=false;

	while(no<num && !bOver){
		no++;
		bOver=true;	
		memcpy(pEdgeInfo1,pEdgeInfo,lLineBytes*lHeight*sizeof(CPoint));

		for (int i = pDoc->StartPoint.y+1; i <=pDoc->EndPoint.y-1; i ++)
		{
			CPoint * pEdge1 =pEdgeInfo1 +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			CPoint * pEdge =pEdgeInfo +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x;
			for (int j =pDoc->StartPoint.x+1; j <=pDoc->EndPoint.x-1; j ++){
				pEdge1++;pEdge++;


				int a=(*(pEdge1-1)).x;
				int b=(*(pEdge1-1)).y;
				int c=(*(pEdge1-lLineBytes-1)).x;

				//sort
				if(a<b) 
					Swap(&a,&b);
				if(a<c)
					Swap(&a,&c);

				if(b<c)
					Swap(&b,&c);

				int m=max(q,a);

				int Snode=0;
				type[0]=(m-a)*(m-b)*(m-c);
				type[1]=a*(m-b)*(m-c);
				type[2]=a*b*(m-c);
				type[3]=a*b*c;
				int maxT=type[0];
				for(int k=1;k<4;k++){
					if(maxT<type[k]){
						Snode=k;
						maxT=type[k];
					}
				}

				int d=(*(pEdge1)).x;
				int g=(*(pEdge1+1)).y;
				int f=(*(pEdge1-lLineBytes)).x;

				//sort
				if(d<g) 
					Swap(&d,&g);
				if(d<f)
					Swap(&d,&f);

				if(g<f)
					Swap(&g,&f);

				m=max(q,d);

				type[0]=(m-d)*(m-g)*(m-f);
				type[1]=d*(m-g)*(m-f);
				type[2]=d*g*(m-f);
				type[3]=d*g*f;
				int Enode=0;
				maxT=type[0];
				for(int k=1;k<4;k++){
					if(maxT<type[k]){
						Enode=k;
						maxT=type[k];
					}

				}
				if((Snode==0 && Enode!=1) || (Snode!=1 && Enode==0))//-
				{
					(*pEdge).y=max((*pEdge).y-delt,0);bOver=false;

				}

				if((Snode==1 && Enode==1))//+
				{
					(*pEdge).y=min((*pEdge).y+delt,100);bOver=false;

				}else
					if((Snode==1 && Enode!=0) || (Snode!=0 && Enode==1))//+
					{
						(*pEdge).y=min((*pEdge).y+delt/2,100);bOver=false;

					}

					a=(*(pEdge1+lLineBytes)).x;
					b=(*(pEdge1+lLineBytes)).y;
					c=(*(pEdge1+lLineBytes+1)).y;

					//sort
					if(a<b) 
						Swap(&a,&b);
					if(a<c)
						Swap(&a,&c);

					if(b<c)
						Swap(&b,&c);

					m=max(q,a);

					type[0]=(m-a)*(m-b)*(m-c);
					type[1]=a*(m-b)*(m-c);
					type[2]=a*b*(m-c);
					type[3]=a*b*c;
					Snode=0;
					maxT=type[0];
					for(int k=1;k<4;k++){
						if(maxT<type[k]){
							Snode=k;
							maxT=type[k];
						}
					}
					d=(*(pEdge1)).y;
					g=(*(pEdge1+1)).y;
					f=(*(pEdge1-lLineBytes)).x;

					//sort
					if(d<g) 
						Swap(&d,&g);
					if(d<f)
						Swap(&d,&f);

					if(g<f)
						Swap(&g,&f);

					m=max(q,d);

					type[0]=(m-d)*(m-g)*(m-f);
					type[1]=d*(m-g)*(m-f);
					type[2]=d*g*(m-f);
					type[3]=d*g*f;
					Enode=0;
					maxT=type[0];
					for(int k=1;k<4;k++){
						if(maxT<type[k]){
							Enode=k;
							maxT=type[k];
						}

					}
					if((Snode==0 && Enode!=1) || (Snode!=1 && Enode==0))//-
					{
						(*pEdge).x=max((*pEdge).x-delt,0);bOver=false;

					}

					if((Snode==1 && Enode==1))//+
					{
						(*pEdge).x=min((*pEdge).x+delt,100);bOver=false;

					}else
						if((Snode==1 && Enode!=0) || (Snode!=0 && Enode==1))//+
						{
							(*pEdge).x=min((*pEdge).x+delt/2,100);bOver=false;

						}


			}

		}
	}

	TRACE("\n\n run: %d\n\n",no);
	//3输出结果

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y-1; i ++)
	{
		unsigned char* lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		CPoint * pEdge =pEdgeInfo +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x-1; j ++){
			lpSrc++;pEdge++;

			*lpSrc=0;//max((*pEdge).x,(*pEdge).y);
			if((*pEdge).x>80){
				*lpSrc=255;
			}


		}
	}

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,"垂直边缘松弛");


	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y-1; i ++)
	{
		unsigned char* lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		CPoint * pEdge =pEdgeInfo +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x-1; j ++){
			lpSrc++;pEdge++;

			*lpSrc=0;//max((*pEdge).x,(*pEdge).y);
			if((*pEdge).y>80){
				*lpSrc=255;
			}


		}
	}

	DisplayNewImg(pDoc->m_pDib->m_lpImage,lLineBytes,lHeight,"水平边缘松弛");

	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y-1; i ++)
	{
		unsigned char* lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		CPoint * pEdge =pEdgeInfo +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x-1; j ++){
			lpSrc++;pEdge++;

			*lpSrc=0;//max((*pEdge).x,(*pEdge).y);
			if((*pEdge).x>80 && (*pEdge).y<80){
				*lpSrc=255;
			}
			if((*pEdge).x<80 && (*pEdge).y>80){
				*lpSrc=255;
			}


		}
	}

	pDoc->SetTitle("边缘松弛");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	// 恢复光标
	EndWaitCursor();	

	delete[]pEdgeInfo;
	delete[]pEdgeInfo1;

}

void CImageProcessView::OnUpdateEdgeRelaxation(CCmdUI *pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::Swap(int* a, int* b){
	int tmp=*a;
	*a=*b;
	*b=tmp;

}

void CImageProcessView::OnSegmentationBoundarytrace()
{
	// TODO: 在此添加命令处理程序代码
	CImageProcessDoc* pDoc = GetDocument();

	BeginWaitCursor();


	int* pCost;//i | j      // i - j


	pCost=new int [lLineBytes*lHeight];

	_ASSERT(pCost != NULL);//false

	memset(pCost,0,lLineBytes*lHeight*sizeof(int));

	//get cost
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{
		unsigned char* lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pDoc->StartPoint.x-1;
		int* pC =pCost +  lLineBytes*i + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;pC++;
			*lpSrc=min(*lpSrc,254);//for diaply
			if(i == pDoc->StartPoint.y){
				*pC=*lpSrc;

			}else
			{
				if(j == pDoc->StartPoint.x)
					*pC=*lpSrc+min(*(pC-lLineBytes),*(pC-lLineBytes+1));
				else
					if(j == pDoc->EndPoint.x)
						*pC=*lpSrc+min(*(pC-lLineBytes),*(pC-lLineBytes-1));
					else
						*pC=*lpSrc+min(*(pC-lLineBytes),min(*(pC-lLineBytes-1),*(pC-lLineBytes+1)));

			}
		}
	}

	//get min path
	vector<int> path;
	int pos=pDoc->StartPoint.x+1;

	int min=*(pCost +  lLineBytes*pDoc->EndPoint.y + pDoc->StartPoint.x+1);


	for (int j =pDoc->StartPoint.x+1; j <=pDoc->EndPoint.x-1; j ++){
		int* pC =pCost +  lLineBytes*pDoc->EndPoint.y + j;
		if(*pC<min){
			min=*pC;
			pos=j;
		}
		//	TRACE("\t%d",*pC);
	}

	path.push_back(pos);

	for (int i =pDoc->EndPoint.y-1 ; i >=pDoc->StartPoint.y; i --){

		int* pC =pCost +  lLineBytes*i + pos;
		if(*(pC-1)<min(*(pC),*(pC+1)))
			pos--;

		if(*(pC+1)<min(*(pC),*(pC-1)))
			pos++;

		path.push_back(pos);


	}


	//display
	unsigned char* lpSrc;
	for (int i =pDoc->EndPoint.y ; i >=pDoc->StartPoint.y; i --){
		int pos=path[pDoc->EndPoint.y-i];
		lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* (lHeight-1-i) + pos;
		*lpSrc=255;
	}


	lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;
	*(lpSrc+255*4+1)=0;*(lpSrc+255*4)=0;*(lpSrc+255*4+2)=255;



	pDoc->SetTitle("边界跟踪(最小路径)");

	InvalidateRect(CRect(pDoc->StartPoint.x,pDoc->StartPoint.y,pDoc->EndPoint.x,pDoc->EndPoint.y),true);

	// 恢复光标
	EndWaitCursor();	

	delete[]pCost;


}

void CImageProcessView::OnUpdateSegmentationBoundarytrace(CCmdUI *pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	CImageProcessDoc* pDoc = GetDocument();
	BOOL bAvail=false;
	if(pDoc->m_pDib->m_lpBMIH!=NULL)
		if(pDoc->m_pDib->m_lpBMIH->biBitCount==8)
			bAvail=true;
	pCmdUI->Enable(bAvail);
}

void CImageProcessView::OnFileOpenavi()
{
	 TODO: 在此添加命令处理程序代码
	TCHAR szFilters[]= _T("AVI Files (*.avi)|*.avi|");



	// Create an Open dialog; the default file name extension is ".my".
	CFileDialog fileDlg(TRUE, _T("avi"), _T("*.avi"),
		OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, szFilters);

	// Display the file dialog. When user clicks OK, fileDlg.DoModal() 
	// returns IDOK.
	if(fileDlg.DoModal() == IDOK)
	{
		if(fileDlg.GetFileExt()=="avi")
		{

			m_AviName=fileDlg.GetPathName();
			if(!LoadAvi())
				SetTimer(TIMER_AVI,60,NULL);
		}
	}
}

int CImageProcessView::LoadAvi(void)
{
	CImageProcessDoc* pDoc = GetDocument();


	//load avi
	AVIFileInit(); 
	PAVIFILE avi;

	if(AVIFileOpen(&avi,m_AviName,OF_READ,NULL)!=AVIERR_OK)
		return 1;

	AVIFILEINFO avi_info;
	AVIFileInfo(avi, &avi_info, sizeof(AVIFILEINFO));


	if(avi_info.dwSuggestedBufferSize<avi_info.dwHeight*avi_info.dwWidth)
	{
		MessageBox("Avi 视频压缩,需要先解压!退出");
       return 1;

	}

	if(AVIFileGetStream(avi, &m_pAviStream, streamtypeVIDEO ,0 /*first stream*/)!=AVIERR_OK)
		return 1;


	int iFirstFrame;
	iFirstFrame=AVIStreamStart(m_pAviStream);
	if (iFirstFrame==-1)
	{
		//Error getteing the frame inside the stream
		if (m_pAviStream!=NULL)
			AVIStreamRelease(m_pAviStream);
		AVIFileExit();
		return 1;
	}

	m_AviNumFrames=AVIStreamLength(m_pAviStream);//512
	if (m_AviNumFrames==-1)
	{
		//Error getteing the number of frames inside the stream
		if (m_pAviStream!=NULL)
			AVIStreamRelease(m_pAviStream);
		AVIFileExit();
		return 1;
	}


	lHeight=avi_info.dwHeight;
	lWidth=avi_info.dwWidth;
	pDoc->StartPoint=CPoint(0,0);
	pDoc->EndPoint=CPoint(lWidth-1,lHeight-1);


	lLineBytes=(lWidth+3)/4*4;

	if(	pDoc->m_pDib)
		delete 	pDoc->m_pDib;

	pDoc->m_pDib =new CDib(CSize(lLineBytes,lHeight) ,8);

	memset(pDoc->m_pDib->m_lpImage,0,lLineBytes*lHeight);
	unsigned char* lpSrc=(unsigned char*)pDoc->m_pDib->m_lpvColorTable;

	for(int i=0;i<256;i++){
		*lpSrc=(unsigned char)i;lpSrc++;
		*lpSrc=(unsigned char)i;lpSrc++;
		*lpSrc=(unsigned char)i;lpSrc++;
		*lpSrc=0;lpSrc++;
	}


	m_AviIndex=0;


	pDoc->SetTitle(m_AviName);



	return 0;
}

void CImageProcessView::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	if(nIDEvent==TIMER_AVI)
	{
		if(!GetAviNext())
			KillTimer(TIMER_AVI);
		Invalidate();
	}
	CScrollView::OnTimer(nIDEvent);
}

int CImageProcessView::GetAviNext(void)
{

	CImageProcessDoc* pDoc = GetDocument();

	m_pAviFrame=AVIStreamGetFrameOpen(m_pAviStream, NULL );

	AVIStreamGetFrame(m_pAviFrame, m_AviIndex); //

	BITMAPINFOHEADER bitmapH; //  buffer containing the BITMAPINFOHEADER

	long int len=40;
	AVIStreamReadFormat(m_pAviStream,m_AviIndex,&bitmapH,&len);

	int lineBytes=bitmapH.biWidth*2;//16bit
	int height=bitmapH.biHeight;
	if(bitmapH.biBitCount==24)
		lineBytes=bitmapH.biWidth*3;//24bit


	if(m_AviIndex==0)
	{
		if(m_AviBuff)
			delete [] m_AviBuff;//may be 2 times open

		m_AviBuff=new unsigned char [lineBytes*height];

	}

	AVIStreamRead(m_pAviStream,m_AviIndex,1, m_AviBuff,lineBytes*height,NULL,NULL);

	AVIStreamGetFrameClose(m_pAviFrame);


	m_AviIndex++;

	CString str;
	str.Format("Play Avi...%d/%d)",m_AviIndex,m_AviNumFrames);

	((CMainFrame*)AfxGetMainWnd())->m_wndStatusBar.SetPaneText(0,str);


	//获取数据图像
	for (int i = pDoc->StartPoint.y; i <=pDoc->EndPoint.y; i ++)
	{
		unsigned char* lpSrc = pDoc->m_pDib->m_lpImage +  lLineBytes* i + pDoc->StartPoint.x-1;
		for (int j =pDoc->StartPoint.x; j <=pDoc->EndPoint.x; j ++){
			lpSrc++;
			if(bitmapH.biBitCount==24)
			{
				*lpSrc=*(m_AviBuff+i*lineBytes+j*3);
			}
			if(bitmapH.biBitCount==16)
			{
				*lpSrc=*(m_AviBuff+i*lineBytes+j*2)&0xf8;
				//*lpSrc=*(m_AviBuff+i*lineBytes+j*2+1)&0xf8;
			}
			if(bitmapH.biBitCount==8)
			{
				*lpSrc=*(m_AviBuff+i*lineBytes+j);
			}


		}
	}

	//close the stream after finishing the task
	if(m_AviIndex>=m_AviNumFrames)
	{
		if (m_pAviStream!=NULL)
			AVIStreamRelease(m_pAviStream);
		AVIFileExit();
		if(m_AviBuff)
			delete [] m_AviBuff;
		m_AviBuff=NULL;

		return 0;
	}
	else
		return 1;
}

void CImageProcessView::OnFileBmp2avi()
{
	// TODO: 在此添加命令处理程序代码
	//CString strBmpDir="d:\\imageprocess\\bmpset";
	//CString szAviName="d:\\imageprocess\\bmpset.avi";
	CString strBmpDir="d:\\imageprocess\\jpgset";
	CString szAviName="d:\\imageprocess\\jpgset.avi";
	CFileFind finder;

	strBmpDir += _T("\\*.*");

	AVIFileInit();
	AVISTREAMINFO strhdr;
	PAVIFILE pfile=NULL;
	PAVISTREAM ps=NULL; 
	int nFrames =0; 
	HRESULT hr; 

	BOOL bFind = finder.FindFile(strBmpDir);
	CImage LoadImg;
	while(bFind)
	{
		bFind = finder.FindNextFile();
		if(!finder.IsDots() && !finder.IsDirectory())
		{
			CString pathName = finder.GetFilePath();

			
			if(!LoadImg.IsNull())
				LoadImg.Destroy();

			LoadImg.Load(pathName);

			if(!LoadImg.IsNull())
			{		 


				BYTE *tmp_buf = NULL;
				if(nFrames ==0 )
				{
					AVIFileOpen(&pfile,szAviName,OF_WRITE | OF_CREATE,NULL);
					memset(&strhdr, 0, sizeof(strhdr));
					strhdr.fccType = streamtypeVIDEO;// stream type
					strhdr.fccHandler = 0;
					strhdr.dwScale = 1;
					strhdr.dwRate = 15; // 15 fps
					strhdr.dwSuggestedBufferSize = LoadImg.GetWidth()*LoadImg.GetHeight()*3;//bmpInfoHdr.biSizeImage ;
					SetRect(&strhdr.rcFrame, 0, 0, LoadImg.GetWidth(),LoadImg.GetHeight());
					// And create the stream;
					hr = AVIFileCreateStream(pfile,&ps,&strhdr); 
					// hr = AVIStreamSetFormat(ps,nFrames,&bmpInfoHdr,sizeof(bmpInfoHdr));
				}
				tmp_buf = new BYTE[ LoadImg.GetWidth()*LoadImg.GetHeight() * 3];
				
				byte* pRealData;
				pRealData=(byte*)LoadImg.GetBits();

				int pit=LoadImg.GetPitch();//-line:-1056

				for (int y=0; y<LoadImg.GetHeight(); y++) 
					for (int x=0; x<LoadImg.GetWidth(); x++)
					{	if(LoadImg.GetBPP()==24)
					{
						*(tmp_buf -pit*(LoadImg.GetHeight()-1-y) +3*x)=*(pRealData + pit*y +3*x);					;
						*(tmp_buf -pit*(LoadImg.GetHeight()-1-y) +3*x+1)=*(pRealData + pit*y +3*x+1);					;
						*(tmp_buf -pit*(LoadImg.GetHeight()-1-y) +3*x+2)=*(pRealData + pit*y +3*x+2);					;
					}
					if(LoadImg.GetBPP()==8)
					{
						*(tmp_buf -3*pit*(LoadImg.GetHeight()-1-y) +3*x)=*(pRealData + pit*y +x);					;
						*(tmp_buf -3*pit*(LoadImg.GetHeight()-1-y) +3*x+1)=*(pRealData + pit*y +x);					;
						*(tmp_buf -3*pit*(LoadImg.GetHeight()-1-y) +3*x+2)=*(pRealData + pit*y +x);					;
					}
					}

					CDib dib(CSize( LoadImg.GetWidth(),LoadImg.GetHeight()),24);

					//dib.m_lpBMIH->biXPelsPerMeter=4724;
					//dib.m_lpBMIH->biYPelsPerMeter=4724;

					for(int i=0;i<3;i++)//增加长度
					{
						hr = AVIStreamSetFormat(ps,nFrames,dib.m_lpBMIH,40);
						 hr = AVIStreamWrite(ps, // stream pointer
							nFrames , // time of this frame
							1, // number to write
							(LPBYTE) tmp_buf,
							LoadImg.GetWidth()*LoadImg.GetHeight()*3,//bmpInfoHdr.biSizeImage , // size of this frame
							AVIIF_KEYFRAME, // flags....
							NULL,
							NULL);
						nFrames ++; 
					}

				
					delete []tmp_buf;
			}
		}
	}
	AVIStreamClose(ps);

	if(pfile != NULL)
		AVIFileRelease(pfile);
	AVIFileExit();

}

void CImageProcessView::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CImageProcessDoc* pDoc = GetDocument();

	//for test
	CDemoTimer exeTimer;
	exeTimer.Reset();

	


	/



	TRACE("\nUsed Time is %.3f ms\n",exeTimer.GetTime(false)*1000);


	CScrollView::OnRButtonDown(nFlags, point);

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值