
// ThresholdToolsDlg.cpp: 实现文件
//

#include "stdafx.h"
#include "ThresholdTools.h"
#include "ThresholdToolsDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CThresholdToolsDlg 对话框



CThresholdToolsDlg::CThresholdToolsDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_THRESHOLDTOOLS_DIALOG, pParent)
	, m_strMaxVal(_T(""))
	, m_strLeft(_T(""))
	, m_strTop(_T(""))
	, m_strRight(_T(""))
	, m_strBottom(_T(""))
	, m_bThreshold(FALSE)
{
	m_strMaxVal = _T("255");
	m_nRadio = 0;
	m_bPress = FALSE;
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CThresholdToolsDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_SLIDER1, m_slider);
	DDX_Text(pDX, IDC_EDIT2, m_strMaxVal);
	DDX_Control(pDX, IDC_SPIN1, m_Spin1);
	DDX_Control(pDX, IDC_SPIN2, m_Spin2);
	DDX_Control(pDX, COMBO_THRESHOLD_TYPE, m_cbThresholdType);
	DDX_Text(pDX, TX_LEFT, m_strLeft);
	DDX_Text(pDX, TX_TOP, m_strTop);
	DDX_Text(pDX, TX_RIGHT, m_strRight);
	DDX_Text(pDX, TX_BOTTOM, m_strBottom);
	DDX_Radio(pDX, RADIO_NONE, m_nRadio);
}

// 该函数，只用于Pictrue Control控件中,在Static不适合;
// static text控件要使用，必须先GetDlgItem(IDC_MY_PIC)->ModifyStyle( SS_TYPEMASK, SS_OWNERDRAW );   
void CThresholdToolsDlg::DrawMat(Mat & img, UINT uId)
{
	if (img.data == NULL)
		return;

	CRect rc;
	Mat imgTmp;
	// 获取控件大小;
	GetDlgItem(uId)->GetClientRect(&rc);
	// 按控件大小，缩小或放大图片;
	cv::resize(img, imgTmp, cv::Size(rc.Width(), rc.Height()));

	// 转换格式;
	switch (imgTmp.channels())
	{
	case 1:
		cv::cvtColor(imgTmp, imgTmp, COLOR_GRAY2BGRA);
		break;
	case 3:
		cv::cvtColor(imgTmp, imgTmp, COLOR_BGR2BGRA);
		break;
	default:
		break;
	}

	int pixelBytes = imgTmp.channels()*(imgTmp.depth() + 1); // 计算一个像素多少个字节
	// 制作bitmapinfo(数据头);
	BITMAPINFO bitInfo;
	bitInfo.bmiHeader.biBitCount = 8 * pixelBytes;
	bitInfo.bmiHeader.biWidth = imgTmp.cols;
	bitInfo.bmiHeader.biHeight = -imgTmp.rows;
	bitInfo.bmiHeader.biPlanes = 1;
	bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bitInfo.bmiHeader.biCompression = BI_RGB;
	bitInfo.bmiHeader.biClrImportant = 0;
	bitInfo.bmiHeader.biClrUsed = 0;
	bitInfo.bmiHeader.biSizeImage = 0;
	bitInfo.bmiHeader.biXPelsPerMeter = 0;
	bitInfo.bmiHeader.biYPelsPerMeter = 0;

	// 双缓存;
	CDC *pDC = GetDlgItem(uId)->GetDC();
	CDC MemDC; //首先定义一个显示设备对象
	CBitmap MemBitmap;//定义一个位图对象

	//随后建立与屏幕显示兼容的内存显示设备
	MemDC.CreateCompatibleDC(NULL);
	//这时还不能绘图，因为没有地方画 ^_^
	//下面建立一个与屏幕显示兼容的位图，至于位图的大小嘛，可以用窗口的大小
	MemBitmap.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());

	//将位图选入到内存显示设备中
	//只有选入了位图的内存显示设备才有地方绘图，画到指定的位图上
	CBitmap *pOldBit = MemDC.SelectObject(&MemBitmap);

	//先用背景色将位图清除干净，这里我用的是白色作为背景
	//你也可以用自己应该用的颜色
	MemDC.FillSolidRect(0, 0, rc.Width(), rc.Height(), RGB(255, 255, 255));
	// Mat.data + bitmap数据头 -> MFC
	int nRet = ::StretchDIBits(
		MemDC,
		0, 0, rc.Width(), rc.Height(),
		0, 0, rc.Width(), rc.Height(),
		imgTmp.data,
		&bitInfo,
		DIB_RGB_COLORS,
		SRCCOPY
	);

	//将内存中的图拷贝到屏幕上进行显示
	pDC->BitBlt(0, 0, rc.Width(), rc.Height(), &MemDC, 0, 0, SRCCOPY);

	//绘图完成后的清理
	MemBitmap.DeleteObject();
	MemDC.DeleteDC();

	ReleaseDC(pDC);
}

void CThresholdToolsDlg::RefreshCanvas()
{
	CRect rc;
	GetDlgItem(IDC_IMG)->GetWindowRect(&rc);
	ScreenToClient(&rc);
	InvalidateRect(rc, FALSE);//True会闪烁;
}

BOOL CThresholdToolsDlg::ImgThreshold(long nThresholdVal, long nMaxThresholdVal)
{
	GetROI();
	if (m_ImgROI.data == NULL)
		return FALSE;

	int nCurSel = m_cbThresholdType.GetCurSel();
	if (nCurSel == CB_ERR)
		return FALSE;

	switch (nCurSel)
	{
		case 0: 
			{
				// 赋值效果图;
				m_pRenderings = &m_ImgShow;
				// 刷新画布区域;
				RefreshCanvas();
			}
			break;
		case 1://全局阀值;
			{
				// 转成灰阶图;
				cvtColor(m_ImgROI, m_ImgThreshold, COLOR_BGR2GRAY);
				// 再高斯模糊处理(滤波);
				GaussianBlur(m_ImgThreshold, m_ImgThreshold, Size(5, 5), 0, 0);
				// 二值化;//全局化指定的阀值与返回值相等;
				double dRetVal = threshold(m_ImgThreshold, m_ImgThreshold, nThresholdVal, nMaxThresholdVal, THRESH_BINARY);
				// 赋值效果对象;
				//m_pRenderings = &m_ImgThreshold;
				// ROI为三通道，所以必须将灰度转回BGR格式,copyTo才有效;
				cvtColor(m_ImgThreshold, m_ImgROI, COLOR_GRAY2BGR);
				// 将二值图复制ROI上;
				//m_ImgThreshold.copyTo(m_ImgROI);
				// 赋值效果图;
				m_pRenderings = &m_ImgShow;
				// 刷新画布区域;
				RefreshCanvas();
			}
			break;
		case 2://自适应阀值;
			{
				// 转成灰阶图;
				cvtColor(m_ImgROI, m_ImgThreshold, COLOR_BGR2GRAY);
				// 再高斯模糊处理(滤波);
				GaussianBlur(m_ImgThreshold, m_ImgThreshold, Size(3, 3), 0, 0);
				// 自适应阀值;
				medianBlur(m_ImgThreshold, m_ImgThreshold, 3);
				// 局部二值化;//blocksize一般取3、5、7
				adaptiveThreshold(m_ImgThreshold, m_ImgThreshold, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, 4.5);
				// 赋值效果对象;
				//m_pRenderings = &m_ImgThreshold;
				// ROI为三通道，所以必须将灰度转回BGR格式,copyTo才有效;
				cvtColor(m_ImgThreshold, m_ImgROI, COLOR_GRAY2BGR);
				// 将二值图复制ROI上;
				//m_ImgThreshold.copyTo(m_ImgROI);
				// 赋值效果图;
				m_pRenderings = &m_ImgShow;
				// 刷新画布区域;
				RefreshCanvas();
			}
			break;
		case 3:// otsu阀值;
			{
				cvtColor(m_ImgROI, m_ImgThreshold, COLOR_BGR2GRAY);
				// 高斯模糊;
				GaussianBlur(m_ImgThreshold, m_ImgThreshold, Size(3, 3), 0, 0);
#if 0
				// otus;//阀值必须为0;
				Mat tempImg;
				m_ImgThreshold.copyTo(tempImg);
				double dRetVal = threshold(m_ImgThreshold, tempImg, nThresholdVal, nMaxThresholdVal, THRESH_BINARY | THRESH_OTSU);
				//TRACE1("当前阀值：%lf\n", dRetVal);
				threshold(m_ImgThreshold, m_ImgThreshold, dRetVal, nMaxThresholdVal, THRESH_BINARY);
#else
				threshold(m_ImgThreshold, m_ImgThreshold, nThresholdVal, nMaxThresholdVal, THRESH_BINARY | THRESH_OTSU);
#endif
				// 赋值效果对象;
				//m_pRenderings = &m_ImgThreshold;
				// ROI为三通道，所以必须将灰度转回BGR格式,copyTo才有效;
				cvtColor(m_ImgThreshold, m_ImgROI, COLOR_GRAY2BGR);
				// 将二值图复制ROI上;
				//m_ImgThreshold.copyTo(m_ImgROI);
				// 赋值效果图;
				m_pRenderings = &m_ImgShow;
				// 刷新画布区域;
				RefreshCanvas(); 
			}
			break;
		default:
			break;
	}

	if (m_ImgThreshold.data) {

		// 查找轮廓;
		m_contours.clear();
		m_hierarchy.clear();
		BOOL bCheck = ((CButton*)GetDlgItem(IDC_CHECK3))->GetCheck();
		if (bCheck == TRUE)
		{
			// 所有轮廓，内外轮廓分等级;
			findContours(m_ImgThreshold, m_contours, m_hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
			// 所有轮廓，内外轮廓不分等级，独立;
			//findContours(m_ImgThreshold, m_contours, m_hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
		}
		else
		{
			// RETR_EXTERNAL=只检索最外面的轮廓;
			findContours(m_ImgThreshold, m_contours, m_hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
		}
	}

	return TRUE;
}

BOOL CThresholdToolsDlg::DrawContours(BOOL bPerimeter,long nMinPerimeter, long nMaxPerimeter, BOOL bArea,long nMinArea, long nMaxArea)
{
	//if ( m_ImgThreshold.data == NULL)
	//	return FALSE;
	//
	//// 查找轮廓;
	//m_contours.clear();
	//m_hierarchy.clear();
	//BOOL bCheck = ((CButton*)GetDlgItem(IDC_CHECK3))->GetCheck();
	//if (bCheck == TRUE)
	//{
	//	// 所有轮廓，内外轮廓分等级;
	//	findContours(m_ImgThreshold, m_contours, m_hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
	//	// 所有轮廓，内外轮廓不分等级，独立;
	//	//findContours(m_ImgThreshold, m_contours, m_hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE);
	//}
	//else
	//{
	//	// RETR_EXTERNAL=只检索最外面的轮廓;
	//	findContours(m_ImgThreshold, m_contours, m_hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
	//}

	// 过滤不符合要求的轮廓;
	int i = 0;
	GetROI();
	m_ImgContours = m_ImgROI.clone();

	vector<vector<Point>>::iterator it = m_contours.begin();
	for ( ; it != m_contours.end(); it++,i++)
	{
		if (bPerimeter && !bArea)
		{
			if (arcLength(*it, true) < nMinPerimeter || arcLength(*it, true) > nMaxPerimeter)
				continue;
		}
		else if (!bPerimeter && bArea)
		{
			if (contourArea(*it) < nMinArea || contourArea(*it) > nMaxArea)
				continue;
		}
		else if (bArea && bPerimeter)
		{
			if ((arcLength(*it, true) < nMinPerimeter || arcLength(*it, true) > nMaxPerimeter) || (contourArea(*it) < nMinArea || contourArea(*it) > nMaxArea))
				continue;
		}

		// 填充轮廓;
		Scalar color = Scalar(rand() % 255, rand() % 255, rand() % 255);
		drawContours(m_ImgContours, m_contours, i, color, CV_FILLED, 8, m_hierarchy);
	}
	m_ImgContours.copyTo(m_ImgROI);
	m_pRenderings = &m_ImgShow;

	// 刷新画布区域;
	RefreshCanvas();

	return TRUE;
}

void CThresholdToolsDlg::GetPointInfo(CPoint pt, long &nPerimeter, long &nArea, Rect &rc)
{
	long a1 = 0, p1 = 0;
	vector<vector<Point>>::iterator it = m_contours.begin();
	BOOL bCheck = ((CButton*)GetDlgItem(IDC_CHECK3))->GetCheck();

	int left = GetDlgItemInt(TX_LEFT);
	int top = GetDlgItemInt(TX_TOP);
	for (; it != m_contours.end(); it++)
	{
		// 检测点是否在轮廓内;
		if (pointPolygonTest(*it, cv::Point(pt.x, pt.y), false) == 1)
		{
			a1 = contourArea(*it);
			p1 = arcLength(*it, true);
			if (bCheck == FALSE)
			{// 外轮廓;
				nArea = a1, nPerimeter = p1;
#if 1
				// 计算轮廓的垂直边界最小矩形，矩形是与图像上下边界平行的;
				rc = boundingRect(*it);
				rc.x = rc.x + left;
				rc.y = rc.y + top;
#else
				vector<Point> contours_poly;
				// 把一个连续光滑曲线折线化，对图像轮廓点进行多边形拟合
				approxPolyDP(*it, contours_poly, 3, TRUE);
				// 计算轮廓的垂直边界最小矩形，矩形是与图像上下边界平行的;
				rc = boundingRect(contours_poly);
				// minAreaRect，minEnclosingTriangle，minEnclosingCircle
				RotatedRect rc_ = minAreaRect(contours_poly);//有角度的矩形;
#endif

				break;
			}
			else
			{// 内轮廓;
				if (nArea > a1)
					nArea = a1;

				if (nPerimeter > p1)
					nPerimeter = p1;

#if 1
				// 计算轮廓的垂直边界最小矩形，矩形是与图像上下边界平行的;
				rc = boundingRect(*it);
				rc.x = rc.x + left;
				rc.y = rc.y + top;
#else
				vector<Point> contours_poly;
				// 把一个连续光滑曲线折线化，对图像轮廓点进行多边形拟合
				approxPolyDP(*it, contours_poly, 3, TRUE);
				// 计算轮廓的垂直边界最小矩形，矩形是与图像上下边界平行的;
				rc = boundingRect(contours_poly);
				// minAreaRect，minEnclosingTriangle，minEnclosingCircle
				RotatedRect rc_ = minAreaRect(contours_poly);//有角度的矩形;
#endif
			}
		}		
	}
}

CPoint CThresholdToolsDlg::WndPt2ImgPt(CPoint WndPt)
{
	// 1.屏幕坐标转成窗口坐标;
	//ScreenToClient(&WndPt);

	// 2.窗口坐标转成控件坐标;
	CRect rcWnd;
	CWnd *pWnd = GetDlgItem(IDC_IMG);	
	pWnd->GetWindowRect(&rcWnd);
	ScreenToClient(&rcWnd);

	WndPt.x -= rcWnd.left;
	WndPt.y -= rcWnd.top;

	// 3.将控件坐标转成图像坐标;
	// 计算出png原图缩放显示到窗口的缩放比例;
	float fScalex = (float)rcWnd.Width() / m_Img.cols;
	float fScaley = (float)rcWnd.Height() / m_Img.rows;
#if 0
	CString str;
	str.Format(_T("控件坐标点：x=%d,y=%d, scalex=%lf=%ld,%ld, scaley=%lf=%ld,%ld\n"),
		WndPt.x, WndPt.y, fScalex, rcWnd.Width() , m_Img.cols, fScaley, rcWnd.Height(), m_Img.rows);
	OutputDebugString(str);
#endif
	// 3.再将窗口点缩放到PNG原图比例;
	WndPt.x /= fScalex;
	WndPt.y /= fScaley;

	return WndPt;
}


void CThresholdToolsDlg::GetROI()
{
	if ( m_ImgShow.data)
	{
		m_ImgShow.release();
	}

	if ( m_ImgROI.data)
	{
		m_ImgROI.release();
	}

	m_Img.copyTo(m_ImgShow);
	m_ImgROI = m_ImgShow([&]()-> Rect {
		long left = GetDlgItemInt(TX_LEFT);
		long top = GetDlgItemInt(TX_TOP);
		long right = GetDlgItemInt(TX_RIGHT);
		long bottom = GetDlgItemInt(TX_BOTTOM);

		if (left < 0)
			left = 0;

		if (top < 0)
			top = 0;

		if (top > m_Img.rows)
			top = m_Img.rows;

		if (left > m_Img.cols)
			left = m_Img.cols;

		left = left > m_Img.cols ? 0 : left;
		top = top > m_Img.rows ? 0 : top;

		// 注意是x,y,w=cols,h=rows
		return Rect( left, top,  right - left, bottom - top);
	}());
}

BEGIN_MESSAGE_MAP(CThresholdToolsDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(BTN_OPENIMG, &CThresholdToolsDlg::OnBnClickedOpenimg)
	ON_WM_SIZE()
	ON_WM_HSCROLL()
	ON_BN_CLICKED(IDOK, &CThresholdToolsDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDCANCEL, &CThresholdToolsDlg::OnBnClickedCancel)
	ON_BN_CLICKED(BTN_RESET, &CThresholdToolsDlg::OnBnClickedReset)
	ON_BN_CLICKED(IDC_BUTTON2, &CThresholdToolsDlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_CHECK1, &CThresholdToolsDlg::OnBnClickedCheck1)
	ON_BN_CLICKED(IDC_CHECK2, &CThresholdToolsDlg::OnBnClickedCheck2)
	ON_EN_CHANGE(TX_Perimeter, &CThresholdToolsDlg::OnEnChangePerimeter)
	ON_EN_CHANGE(TX_Square, &CThresholdToolsDlg::OnEnChangeSquare)
	ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN1, &CThresholdToolsDlg::OnDeltaposSpin1)
	ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN2, &CThresholdToolsDlg::OnDeltaposSpin2)
	ON_EN_CHANGE(TX_Perimeter2, &CThresholdToolsDlg::OnEnChangePerimeter2)
	ON_EN_CHANGE(TX_Square2, &CThresholdToolsDlg::OnEnChangeSquare2)
	ON_WM_MOUSEWHEEL()
	ON_WM_MOUSEMOVE()
	ON_BN_CLICKED(IDC_CHECK3, &CThresholdToolsDlg::OnBnClickedCheck3)
	ON_CBN_SELCHANGE(COMBO_THRESHOLD_TYPE, &CThresholdToolsDlg::OnCbnSelchangeThresholdType)
	ON_EN_CHANGE(TX_LEFT, &CThresholdToolsDlg::OnEnChangeLeft)
	ON_EN_CHANGE(TX_TOP, &CThresholdToolsDlg::OnEnChangeTop)
	ON_EN_CHANGE(TX_RIGHT, &CThresholdToolsDlg::OnEnChangeRight)
	ON_EN_CHANGE(TX_BOTTOM, &CThresholdToolsDlg::OnEnChangeBottom)
	ON_BN_CLICKED(BTN_PREVE, &CThresholdToolsDlg::OnBnClickedPreve)
	ON_BN_CLICKED(BTN_NEXT, &CThresholdToolsDlg::OnBnClickedNext)
	ON_BN_CLICKED(RADIO_NONE, &CThresholdToolsDlg::OnBnClickedThreshold)
	ON_BN_CLICKED(RADIO_THRESHOLD, &CThresholdToolsDlg::OnBnClickedThreshold)
	ON_BN_CLICKED(RADIO_FILLCONTOUR, &CThresholdToolsDlg::OnBnClickedThreshold)
	ON_BN_CLICKED(RADIO_TEMP, &CThresholdToolsDlg::OnBnClickedThreshold)
	ON_BN_CLICKED(BTN_OPEN_TEMP, &CThresholdToolsDlg::OnBnClickedOpenTemp)
	ON_BN_CLICKED(BTN_FIND_TEMP, &CThresholdToolsDlg::OnBnClickedFindTemp)
END_MESSAGE_MAP()


// CThresholdToolsDlg 消息处理程序

BOOL CThresholdToolsDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	SetDlgItemText(TX_Perimeter, _T("500"));
	SetDlgItemText(TX_Square, _T("500"));

	SetDlgItemText(TX_Perimeter2, _T("1000"));
	SetDlgItemText(TX_Square2, _T("1000"));
#if 0
	m_Img = imread("E:\\IMCapture\\AVerCapSDK.png");
	m_img_bak = m_Img.clone();
	DrawMat(m_Img, IDC_IMG);
#endif
	GetClientRect(&m_WndRect);

	// 将static控件样式修改;
	GetDlgItem(IDC_IMG)->ModifyStyle(SS_TYPEMASK, SS_OWNERDRAW);
	// 设置范围;
	m_slider.SetRange(0, 255);
	// 每10个值设置一个刻度;
	m_slider.SetTicFreq(10);
	// 设置滑动刻度;
	m_slider.SetPageSize(1);

	// 设置全局阀值为默认;
	m_cbThresholdType.SetCurSel(0);
	//m_Spin1.SetRange(100000, 0);
	//m_Spin2.SetRange(100000, 0);

// 	m_Spin1.SetRange(0, 100000);
// 	m_Spin2.SetRange(0, 100000);

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CThresholdToolsDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CThresholdToolsDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);	
	}
	else
	{
		CDialogEx::OnPaint();
		// 绘图;
		if (m_pRenderings)
		{
			DrawMat(*m_pRenderings, IDC_IMG);
			//DrawMat(m_ImgShow, IDC_IMG);
		}

		// 模板图片;
		if ( m_ImgTemp.data)
		{
			DrawMat(m_ImgTemp, IDC_TEMP);
		}
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CThresholdToolsDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CThresholdToolsDlg::OnBnClickedOpenimg() // 打开图片;
{
	// TODO: 在此添加控件通知处理程序代码
	CString strFindFile = _T("");
	CString strFilters = _T("图片(*.jpg;*.jpeg;*.png;*.bmp;)||所有文件 (*.*)|*.*||");
	CString strDeftExt = _T("default Files (*.png)");
	CString strTitle = _T("请选择要取阀值的图片");
	DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ENABLESIZING;
	CFileDialog dlg(TRUE, strDeftExt, NULL, dwFlags, strFilters, NULL);
	dlg.m_ofn.lpstrTitle = strTitle;	// 显示的标题, 应该做成参数传入;
	dlg.m_ofn.lpstrInitialDir = NULL;	// 默认打开的文件夹, 应该做成参数传入;

	// 显示文件对话框,获得文件名集合;
	if (dlg.DoModal() == IDCANCEL)
		return;

	CString strFiles = dlg.GetPathName();
	CString strPath = dlg.GetFolderPath();
	m_files.clear();
	filehelpImpl fhelp;
	fhelp.getfiles_findout_subfolder(strPath.GetString(), _T("*.png|*.jpg|*.bmp"), &m_files);

	OpenImg(strFiles.GetString(), TRUE);
	m_curIndex = GetFileIndex(strFiles.GetString(), m_files);
}


void CThresholdToolsDlg::OnSize(UINT nType, int cx, int cy)
{
	return CDialogEx::OnSize(nType, cx, cy);

	// 获取控件句柄;
	CWnd *pWnd = GetDlgItem(IDC_IMG);
	if ( pWnd )
	{
		CRect rcContrl;
		pWnd->GetWindowRect(&rcContrl);
		ScreenToClient(&rcContrl);

		rcContrl.right = cx - 20;
		rcContrl.bottom = cy - 50;

		pWnd->MoveWindow(rcContrl);
	}
}

void CThresholdToolsDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if ((&m_slider) == (CSliderCtrl *)pScrollBar)         // mSlider 为你的slider控件
	{
		// 获取当前刻度;
		long lVal = m_slider.GetPos();
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);
		// 图像二值化;
		if ( ImgThreshold(lVal, lMaxVal) )
		{
			CString str;
			str.Format(_T("当前值：%ld"), lVal);
			SetWindowText(str);
		}

		m_bPerimeter = ((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck();
		if (m_nRadio != 2)
			return;
		long nPerimeter = GetDlgItemInt(TX_Perimeter);
		long nSquare = GetDlgItemInt(TX_Square);

		long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
		long nSquare2 = GetDlgItemInt(TX_Square2);
		DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
	}

	CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CThresholdToolsDlg::OnBnClickedOk()
{
	// TODO: 在此添加控件通知处理程序代码
	CDialogEx::OnOK();
}


void CThresholdToolsDlg::OnBnClickedCancel()
{
	// TODO: 在此添加控件通知处理程序代码
	CDialogEx::OnCancel();
}


void CThresholdToolsDlg::OnBnClickedReset() // 复位;
{
	m_slider.SetPos(0);
	m_Img.copyTo(m_ImgShow);
	m_pRenderings = &m_ImgShow;
	// 刷新画布;
	RefreshCanvas();
}


void CThresholdToolsDlg::OnBnClickedButton2() // 轮廓;
{
	// TODO: 在此添加控件通知处理程序代码
	// 获取当前刻度;
	long lVal = m_slider.GetPos();
	long lMaxVal = GetDlgItemInt(IDC_EDIT2);
	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);

	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);
	if ( !m_bThreshold)
	{
		DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
		SetDlgItemText(IDC_BUTTON2, _T("二值化"));
	}
	else
	{
		GetROI();
		if (m_ImgThreshold.data)
		{
			cvtColor(m_ImgThreshold, m_ImgROI, COLOR_GRAY2BGR);
			m_ImgThreshold.copyTo(m_ImgROI);
			m_pRenderings = &m_ImgShow;
		}
		// 刷新;
		RefreshCanvas();
		SetDlgItemText(IDC_BUTTON2, _T("轮廓"));
	}
	m_bThreshold = !m_bThreshold;
}


void CThresholdToolsDlg::OnBnClickedCheck1() // 周长;
{
	m_bPerimeter = ((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck();
	if (m_nRadio != 2)
		return;
	long lVal = m_slider.GetPos();
	long lMaxVal = GetDlgItemInt(IDC_EDIT2);
	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);

	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);
	DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
}


void CThresholdToolsDlg::OnBnClickedCheck2() // 面积;
{
	m_bSquare = ((CButton*)GetDlgItem(IDC_CHECK2))->GetCheck();
	if (m_nRadio != 2)
		return;
	long lVal = m_slider.GetPos();
	long lMaxVal = GetDlgItemInt(IDC_EDIT2);
	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);

	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);
	DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
}


void CThresholdToolsDlg::OnEnChangePerimeter()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	if ( m_nRadio == 2 )
	{
		long lVal = m_slider.GetPos();
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);
		
		long nPerimeter = GetDlgItemInt(TX_Perimeter);
		long nSquare = GetDlgItemInt(TX_Square);

		long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
		long nSquare2 = GetDlgItemInt(TX_Square2);
		DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
	}
	// TODO:  在此添加控件通知处理程序代码
}


void CThresholdToolsDlg::OnEnChangeSquare()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	if (m_nRadio == 2)
	{
		long lVal = m_slider.GetPos();
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);
		
		long nPerimeter = GetDlgItemInt(TX_Perimeter);
		long nSquare = GetDlgItemInt(TX_Square);

		long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
		long nSquare2 = GetDlgItemInt(TX_Square2);
		DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
	}
	// TODO:  在此添加控件通知处理程序代码
}


void CThresholdToolsDlg::OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码

	long val = GetDlgItemInt(TX_Perimeter);
 	if ( pNMUpDown->iDelta == 1) // 向下;
 	{
		val--;
 	}
 	else if (pNMUpDown->iDelta == -1)// 向上;
 	{
		val++;
 	}
 	*pResult = 0;

	
	SetDlgItemInt(TX_Perimeter, val);
}


void CThresholdToolsDlg::OnDeltaposSpin2(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码

	long val = GetDlgItemInt(TX_Square);
	if (pNMUpDown->iDelta == 1) // 向下;
	{
		val--;
	}
	else if (pNMUpDown->iDelta == -1)// 向上;
	{
		val++;
	}
	*pResult = 0;


	SetDlgItemInt(TX_Square, val);
}


void CThresholdToolsDlg::OnEnChangePerimeter2()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	if (m_nRadio == 2)
	{
		long lVal = m_slider.GetPos();
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);

		long nPerimeter = GetDlgItemInt(TX_Perimeter);
		long nSquare = GetDlgItemInt(TX_Square);

		long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
		long nSquare2 = GetDlgItemInt(TX_Square2);
		DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
	}
	// TODO:  在此添加控件通知处理程序代码
}


void CThresholdToolsDlg::OnEnChangeSquare2()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	if (m_nRadio == 2)
	{
		long lVal = m_slider.GetPos();
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);

		long nPerimeter = GetDlgItemInt(TX_Perimeter);
		long nSquare = GetDlgItemInt(TX_Square);

		long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
		long nSquare2 = GetDlgItemInt(TX_Square2);
		DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
	}
	// TODO:  在此添加控件通知处理程序代码
}


BOOL CThresholdToolsDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CWnd *pWnd = GetFocus();
	if ( pWnd == GetDlgItem(TX_Perimeter) || pWnd == GetDlgItem(TX_Perimeter2) 
		|| pWnd == GetDlgItem(TX_Square) || pWnd == GetDlgItem(TX_Square2))
	{
		long nVal = GetDlgItemInt(pWnd->GetDlgCtrlID());
		if ( zDelta > 0 )
		{//向上滚动;
			nVal++;
		}
		else
		{
			nVal--;
		}

		SetDlgItemInt(pWnd->GetDlgCtrlID(), nVal);
	}

	if (pWnd == GetDlgItem(TX_LEFT) )
	{
		long nVal = GetDlgItemInt(pWnd->GetDlgCtrlID());
		if (zDelta > 0)
		{//向上滚动;
			if (nVal < m_Img.cols)
				nVal++;
		}
		else
		{
			if (nVal > 0 )
				nVal--;
		}

		SetDlgItemInt(pWnd->GetDlgCtrlID(), nVal);
	}

	if ( pWnd == GetDlgItem(TX_TOP))
	{
		long nVal = GetDlgItemInt(pWnd->GetDlgCtrlID());
		if (zDelta > 0)
		{//向上滚动;
			if (nVal < m_Img.rows)
				nVal++;
		}
		else
		{
			if (nVal > 0)
				nVal--;
		}

		SetDlgItemInt(pWnd->GetDlgCtrlID(), nVal);
	}

	if ( pWnd == GetDlgItem(TX_RIGHT) )
	{
		long nVal = GetDlgItemInt(pWnd->GetDlgCtrlID());
		if (zDelta > 0)
		{//向上滚动;
			if (nVal < m_Img.cols)
				nVal++;
		}
		else
		{
			if (nVal > 0)
				nVal--;
		}

		SetDlgItemInt(pWnd->GetDlgCtrlID(), nVal);
	}

	if ( pWnd == GetDlgItem(TX_BOTTOM))
	{
		long nVal = GetDlgItemInt(pWnd->GetDlgCtrlID());
		if (zDelta > 0)
		{//向上滚动;
			if (nVal < m_Img.rows)
				nVal++;
		}
		else
		{
			if (nVal > 0)
				nVal--;
		}

		SetDlgItemInt(pWnd->GetDlgCtrlID(), nVal);
	}
	return CDialogEx::OnMouseWheel(nFlags, zDelta, pt);
}


BOOL CThresholdToolsDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN)
	{
		CWnd *pWnd = GetFocus();
		if (pWnd == GetDlgItem(TX_Perimeter) || pWnd == GetDlgItem(TX_Perimeter2)
			|| pWnd == GetDlgItem(TX_Square) || pWnd == GetDlgItem(TX_Square2)
			|| pWnd == GetDlgItem(TX_LEFT) || pWnd == GetDlgItem(TX_TOP) 
			|| pWnd == GetDlgItem(TX_RIGHT) || pWnd == GetDlgItem(TX_BOTTOM)
			)
		{
			long nVal = GetDlgItemInt(pWnd->GetDlgCtrlID());
			if (pMsg->wParam == VK_UP)
			{
				nVal++;
				SetDlgItemInt(pWnd->GetDlgCtrlID(), nVal);
			}
			else if (pMsg->wParam == VK_DOWN)
			{
				nVal--;
				SetDlgItemInt(pWnd->GetDlgCtrlID(), nVal);
			}			
		}
	}
	else if (pMsg->message == WM_LBUTTONDOWN)
	{
		CPoint point;
		GetCursorPos(&point);
		CRect rcWnd;
		CWnd *pWnd = GetDlgItem(IDC_IMG);
		pWnd->GetWindowRect(&rcWnd);

		if (!PtInRect(&rcWnd, point))
			return CDialogEx::PreTranslateMessage(pMsg);

		ScreenToClient(&point);
		point = WndPt2ImgPt(point);

		m_bPress = TRUE;
		m_firstPt.x = point.x;
		m_firstPt.y = point.y;
		long nPerimeter = 100000, nArea = 1000000;
		Rect rc;
		GetPointInfo(point, nPerimeter, nArea, rc);
		if (nPerimeter > 200 || nArea > 1000)
		{
			CString str;
			GetWindowText(str);

			int nIndex = str.Find(_T("   \t\t\t"));
			str.Format(_T("%s   \t\t\t 周长：%ld，面积：%ld\n, 坐标=[%d,%d,%d,%d]"), (nIndex == -1 ? str : str.Left(nIndex)), nPerimeter, nArea, rc.x, rc.y, rc.x+rc.width, rc.y+rc.height);
			SetWindowText(str);
		}
	}
	else if (pMsg->message == WM_LBUTTONUP)
	{
		if (m_bPress)
		{
			m_bPress = FALSE;
			// 最后的点;
			CPoint point;
			GetCursorPos(&point);
			CRect rcWnd;
			CWnd *pWnd = GetDlgItem(IDC_IMG);
			pWnd->GetWindowRect(&rcWnd);

			if (!PtInRect(&rcWnd, point))
				return CDialogEx::PreTranslateMessage(pMsg);

			ScreenToClient(&point);
			point = WndPt2ImgPt(point);
			m_lastPt.x = point.x;
			m_lastPt.y = point.y;

			SetDlgItemInt(TX_LEFT, m_firstPt.x);
			SetDlgItemInt(TX_TOP, m_firstPt.y);
			SetDlgItemInt(TX_RIGHT, m_lastPt.x);
			SetDlgItemInt(TX_BOTTOM, m_lastPt.y);
		}
	}

	return CDialogEx::PreTranslateMessage(pMsg);
}


void CThresholdToolsDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
#if 0
	if (m_contours.size())
	{
		// 坐标转换;
		CString str;
		point = WndPt2ImgPt(point);

		long nPerimeter = 0, nArea = 0;
		GetPointInfo(point, nPerimeter, nArea);
		if (nPerimeter > 200 || nArea > 1000)
		{
#if _DEBUG
			str.Format(_T("周长：%ld，面积：%ld\n"), nPerimeter, nArea);
			OutputDebugString(str);
#endif
		}
	}
#endif
	if ( m_bPress )
	{
		if (m_ImgShow.data)
			m_ImgShow.release();

		CPoint point;
		GetCursorPos(&point);
		CRect rcWnd;
		CWnd *pWnd = GetDlgItem(IDC_IMG);
		pWnd->GetWindowRect(&rcWnd);

		if (!PtInRect(&rcWnd, point))
			return CDialogEx::OnMouseMove(nFlags, point);

		ScreenToClient(&point);
		point  = WndPt2ImgPt(point);
		m_lastPt.x = point.x;
		m_lastPt.y = point.y;

		m_Img.copyTo(m_ImgShow);
		rectangle(m_ImgShow, m_firstPt, Point(m_lastPt.x, m_lastPt.y), Scalar(rand() % 255, rand() % 255, rand() % 255), 1, CV_AA, 0);
		m_pRenderings = &m_ImgShow;
		SetWindowText([&]()->CString {
			CString str;
			str.Format(_T("坐标=[%d,%d,%d,%d]"), m_firstPt.x, m_firstPt.y, point.x, point.y);
			return str;
			}());
		RefreshCanvas();
	}

	CDialogEx::OnMouseMove(nFlags, point);
}


void CThresholdToolsDlg::OnBnClickedCheck3() // 内轮廓;
{
	int nPos = m_slider.GetPos();
	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);

	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);

	if (nPos != 0)
	{
		// 二值化;
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);
		ImgThreshold(nPos, lMaxVal);

		if (m_nRadio == 2)
		{
			DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
		}
		else
		{
			// 刷新;
			RefreshCanvas();
		}
	}
	else
	{
		int nCurSel = m_cbThresholdType.GetCurSel();
		if (nCurSel != 0)
		{
			// 二值化;
			long lMaxVal = GetDlgItemInt(IDC_EDIT2);
			ImgThreshold(nPos, lMaxVal);

			if (m_nRadio == 2)
			{
				DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
			}
			else
			{
				// 刷新;
				RefreshCanvas();
			}
		}
		else
		{
			m_pRenderings = &m_ImgShow;
		}
		RefreshCanvas();
	}
}


void CThresholdToolsDlg::OnCbnSelchangeThresholdType()
{
	// TODO: 在此添加控件通知处理程序代码
	int nPos = m_slider.GetPos();
	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);

	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);

	if (nPos != 0)
	{
		// 二值化;
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);
		ImgThreshold(nPos, lMaxVal);

		if (m_nRadio == 2)
		{
			DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
		}
		else
		{
			// 刷新;
			RefreshCanvas();
		}
	}
	else
	{
		int nCurSel = m_cbThresholdType.GetCurSel();
		if (nCurSel != 0)
		{
			// 二值化;
			long lMaxVal = GetDlgItemInt(IDC_EDIT2);
			ImgThreshold(nPos, lMaxVal);

			if (m_nRadio == 2)
			{
				DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
			}
			else
			{
				// 刷新;
				RefreshCanvas();
			}
		}
		else 
		{
			m_pRenderings = &m_ImgShow;
		}
		RefreshCanvas();
	}
}


void CThresholdToolsDlg::OnEnChangeLeft()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	m_Img.copyTo(m_ImgShow);
	int nPos = m_slider.GetPos();
	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);

	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);

	if (nPos != 0)
	{
		// 二值化;
		long lMaxVal = GetDlgItemInt(IDC_EDIT2);
		ImgThreshold(nPos, lMaxVal);

		if (m_nRadio == 2)
		{
			DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
		}
		else
		{
			// 刷新;
			RefreshCanvas();
		}
	}
	else
	{
		int nCurSel = m_cbThresholdType.GetCurSel();
		if (nCurSel == 2 || nCurSel == 3)
		{
			// 二值化;
			long lMaxVal = GetDlgItemInt(IDC_EDIT2);
			ImgThreshold(nPos, lMaxVal);

			if (m_nRadio == 2)
			{
				DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
			}
			else
			{
				// 刷新;
				RefreshCanvas();
			}
		}
		else 
		{
			m_pRenderings = &m_ImgShow;
		}
		RefreshCanvas();
	}
	// TODO:  在此添加控件通知处理程序代码
}


void CThresholdToolsDlg::OnEnChangeTop()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	OnEnChangeLeft();
	// TODO:  在此添加控件通知处理程序代码
}


void CThresholdToolsDlg::OnEnChangeRight()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	OnEnChangeLeft();
	// TODO:  在此添加控件通知处理程序代码
}


void CThresholdToolsDlg::OnEnChangeBottom()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。
	OnEnChangeLeft();
	// TODO:  在此添加控件通知处理程序代码
}


void CThresholdToolsDlg::OnBnClickedPreve()
{
	// TODO: 在此添加控件通知处理程序代码
	if (m_files.size() == 0)
		return;

	if (m_curIndex == 0 )
	{
		m_curIndex = m_files.size();
		MessageBox(_T("已到第一张，将从最后一张继续"));
	}

	m_curIndex--;
	OpenImg(m_files[m_curIndex].c_str());
}


void CThresholdToolsDlg::OnBnClickedNext()
{
	if (m_files.size() == 0)
		return;

	if (m_curIndex == m_files.size()-1)
	{
		MessageBox(_T("已到最后一张，将从第一张继续"));
		m_curIndex = -1;
	}

	m_curIndex++;
	OpenImg(m_files[m_curIndex].c_str());
}

//打开图片;
void CThresholdToolsDlg::OpenImg(LPCTSTR lpFile, BOOL bResetROI /* = FALSE */)
{
	int lastr = 0, lastc = 0;
	if (m_Img.data != NULL)
	{
		lastr = m_Img.rows, lastc = m_Img.cols;
		m_Img.release();
	}

	if (m_ImgThreshold.data)
	{
		m_ImgThreshold.release();
	}

	if ( m_ImgShow.data )
	{
		m_ImgShow.release();
	}

	if ( m_ImgROI.data )
	{
		m_ImgROI.release();
	}

	SetDlgItemText(IDC_EDIT1, lpFile);
	m_Img = imread(lpFile, CV_LOAD_IMAGE_COLOR);
	if (m_Img.data)
	{
		if (lastr != m_Img.rows && lastc != m_Img.cols)
			bResetROI = TRUE;
		if (bResetROI)
		{
			m_strLeft = _T("0");
			m_strTop = _T("0");
			m_strRight.Format(_T("%ld"), m_Img.cols);
			m_strBottom.Format(_T("%ld"), m_Img.rows);
			UpdateData(FALSE);
		}

		m_Img.copyTo(m_ImgShow);
	}

	int nPos = m_slider.GetPos();
	int nCurSel = m_cbThresholdType.GetCurSel();
	// 二值化;
	long lMaxVal = GetDlgItemInt(IDC_EDIT2);
	ImgThreshold(nPos, lMaxVal);

	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);
	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);

	if (nCurSel == 2 || nCurSel == 3)
	{
		if (m_nRadio == 2)
		{
			DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
		}
		else
		{
			// 刷新;
			RefreshCanvas();
		}
	}
	else
	{
		if (nPos != 0)
		{
			if (m_nRadio == 2)
			{
				DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
			}
			else
			{
				// 刷新;
				RefreshCanvas();
			}
		}
		else
		{
			if (m_nRadio == 3)
			{
				OnBnClickedFindTemp();
			}
			else {
				m_pRenderings = &m_Img;
				RefreshCanvas();
			}
		}
	}

	
	//if (nPos != 0)
	//{
	//	// 二值化;
	//	long lMaxVal = GetDlgItemInt(IDC_EDIT2);
	//	ImgThreshold(nPos, lMaxVal);

	//	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	//	long nSquare = GetDlgItemInt(TX_Square);

	//	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	//	long nSquare2 = GetDlgItemInt(TX_Square2);

	//	if (m_nRadio == 2)
	//	{
	//		DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
	//	}
	//	else
	//	{
	//		//if (m_ImgThreshold.data)
	//		//	m_pRenderings = &m_ImgThreshold;
	//		// 刷新;
	//		RefreshCanvas();
	//	}
	//}
	//else
	//{
	//	m_pRenderings = &m_ImgShow;
	//	RefreshCanvas();
	//}
}

int CThresholdToolsDlg::GetFileIndex(LPCTSTR lpCurFile, STR_VEC & vtFiles)
{
	int nIndex = -1;
	int nCount = vtFiles.size();
	for ( int i = 0; i < nCount; i++ )
	{
		if (!_tcsicmp(lpCurFile, vtFiles[i].c_str()) )
		{ 
			nIndex = i;
			break;
		}
	}

	return nIndex;
}


void CThresholdToolsDlg::OnBnClickedThreshold()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);

	long lVal = m_slider.GetPos();
	long lMaxVal = GetDlgItemInt(IDC_EDIT2);
	long nPerimeter = GetDlgItemInt(TX_Perimeter);
	long nSquare = GetDlgItemInt(TX_Square);

	long nPerimeter2 = GetDlgItemInt(TX_Perimeter2);
	long nSquare2 = GetDlgItemInt(TX_Square2);

	switch (m_nRadio)
	{
		case 0:
			{
				m_pRenderings = &m_Img;
				// 刷新;
				RefreshCanvas();
			}
			break;
		case 1://二值图;
			{
				GetROI();
				if (m_ImgThreshold.data)
				{
					cvtColor(m_ImgThreshold, m_ImgROI, COLOR_GRAY2BGR);
					m_ImgThreshold.copyTo(m_ImgROI);
					m_pRenderings = &m_ImgShow;
				}
				// 刷新;
				RefreshCanvas();
			}
			break;
		case 2:// 轮廓填充;
			{
				DrawContours(m_bPerimeter, nPerimeter, nPerimeter2, m_bSquare, nSquare, nSquare2);
			}
			break;
		case 3: 
			{
				OnBnClickedFindTemp();
			}
			break;
		default:
			break;
	}
}


void CThresholdToolsDlg::OnBnClickedOpenTemp()//打开模板图片;
{
	// TODO: 在此添加控件通知处理程序代码
	CString strFindFile = _T("");
	CString strFilters = _T("图片(*.jpg;*.jpeg;*.png;*.bmp;)||所有文件 (*.*)|*.*||");
	CString strDeftExt = _T("default Files (*.png)");
	CString strTitle = _T("请选择要取阀值的图片");
	DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ENABLESIZING;
	CFileDialog dlg(TRUE, strDeftExt, NULL, dwFlags, strFilters, NULL);
	dlg.m_ofn.lpstrTitle = strTitle;	// 显示的标题, 应该做成参数传入;
	dlg.m_ofn.lpstrInitialDir = NULL;	// 默认打开的文件夹, 应该做成参数传入;

	// 显示文件对话框,获得文件名集合;
	if (dlg.DoModal() == IDCANCEL)
		return;

	CString strFiles = dlg.GetPathName();
	CString strPath = dlg.GetFolderPath();
	if ( m_ImgTemp.data )
	{
		m_ImgTemp.release();
	}
	m_ImgTemp = imread(strFiles.GetString(), CV_LOAD_IMAGE_COLOR);
	if ( m_ImgTemp.data)
	{
		DrawMat(m_ImgTemp, IDC_TEMP);
	}
}


void CThresholdToolsDlg::OnBnClickedFindTemp()
{
	// TODO: 在此添加控件通知处理程序代码
	if (m_ImgTemp.data == NULL)
		return;

	if ( m_ImgTemp.cols > m_Img.cols || m_ImgTemp.rows > m_Img.rows)
		return;

	GetROI();
	if (m_ImgROI.data == NULL)
		return;

	Mat ImgResult;
	matchTemplate(m_ImgROI, m_ImgTemp, ImgResult, TM_CCOEFF_NORMED);
	// 归一化到0~1
	//normalize(ImgResult, ImgResult, 0, 1, NORM_MINMAX, -1);
	//
	double lv_nMinVal = 0.0;
	double lv_nMaxVal = 0.0;
	Point lv_nMinLoc = Point(0, 0);
	Point lv_nMaxLoc = Point(0,0);
	Point lv_MatchLoc = Point(0,0);
	minMaxLoc(ImgResult, &lv_nMinVal, &lv_nMaxVal, &lv_nMinLoc, &lv_nMaxLoc);
	// TM_CCOEFF_NORMED:匹配值越大越相似;
	SetDlgItemText(MATCH_VAL, [&]()->CString{
		CString str;
		str.Format(_T("%0.13lf"), lv_nMaxVal);
		return str;
		}());

	SetWindowText([&]()->CString {
		CString str;
		str.Format(_T("相似度=%0.13lf       坐标=[%d,%d,%d,%d]"), lv_nMaxVal, lv_nMaxLoc.x, lv_nMaxLoc.y, lv_nMaxLoc.x + m_ImgTemp.cols, lv_nMaxLoc.y + m_ImgTemp.rows);
		return str;
		}());
	//m_Img.copyTo(m_ImgShow);
	//m_ImgROI = m_ImgShow(Rect(lv_nMaxLoc.x-2, lv_nMaxLoc.y-2, m_ImgTemp.cols+4, m_ImgTemp.rows+4));
	//m_ImgROI = m_ImgShow(Rect(lv_nMaxLoc.x, lv_nMaxLoc.y , m_ImgTemp.cols , m_ImgTemp.rows ));
	//CV_AA
	rectangle(m_ImgROI, Point(lv_nMaxLoc.x, lv_nMaxLoc.y), Point(lv_nMaxLoc.x+ m_ImgTemp.cols, lv_nMaxLoc.y+ m_ImgTemp.rows), Scalar(rand() % 255, rand() % 255, rand() % 255), 2, CV_AA, 0);
	m_pRenderings = &m_ImgShow;

	RefreshCanvas();
}

void CThresholdToolsDlg::DrawTempContours()
{

}