이미지 자동 생성기 MFC에 적용해보기!

바로 직전에 올린 게시물은 C++ OpenCV를 활영하여
이미지를 자동으로 생성하고 저장하는 프로그램의 소개였다.
이번엔 그 프로그램을 그대로 MFC에 적용시켜보겠다.

웬만하면 최대한 소스코드를 수정하지 않고 복사 붙여넣기 하고싶어서
클래스 멤버변수를 쓸떼없이 포인터로 부르고 래퍼런스로 받는 등…
하는 부분이 있지만 잘 돌아가기만 하면 됐지 뭐! 하하!

소스코드는 다음과 같다.

프로젝트.h

// MFC_OpenCV.h: PROJECT_NAME 애플리케이션에 대한 주 헤더 파일입니다.
//

#pragma once

#ifndef __AFXWIN_H__
	#error "PCH에 대해 이 파일을 포함하기 전에 'pch.h'를 포함합니다."
#endif

#include "resource.h"		// 주 기호입니다.


// CMFCOpenCVApp:
// 이 클래스의 구현에 대해서는 MFC_OpenCV.cpp을(를) 참조하세요.
//

class CMFCOpenCVApp : public CWinApp
{
public:
	CMFCOpenCVApp();

// 재정의입니다.
public:
	virtual BOOL InitInstance();

// 구현입니다.

	DECLARE_MESSAGE_MAP()
};

extern CMFCOpenCVApp theApp;

프로젝트.cpp

// MFC_OpenCV.cpp: 애플리케이션에 대한 클래스 동작을 정의합니다.
//

#include "pch.h"
#include "framework.h"
#include "MFC_OpenCV.h"
#include "MFC_OpenCVDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMFCOpenCVApp
BEGIN_MESSAGE_MAP(CMFCOpenCVApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()

// CMFCOpenCVApp 생성
CMFCOpenCVApp::CMFCOpenCVApp() {
	// TODO: 여기에 생성 코드를 추가합니다.
	// InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}

// 유일한 CMFCOpenCVApp 개체입니다.
CMFCOpenCVApp theApp;

// CMFCOpenCVApp 초기화
BOOL CMFCOpenCVApp::InitInstance() {
	CWinApp::InitInstance();

	CMFCOpenCVDlg dlg;
	m_pMainWnd = &dlg;
	dlg.DoModal();

	return FALSE;
}

프로젝트Dlg.h

// MFC_OpenCVDlg.h: 헤더 파일
//

#pragma once

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <direct.h>

using namespace cv;

// CMFCOpenCVDlg 대화 상자
class CMFCOpenCVDlg : public CDialogEx
{
// 생성입니다.
public:
	CMFCOpenCVDlg(CWnd* pParent = nullptr);	// 표준 생성자입니다.
private:
	Mat RED, // Canvas 선언
		GREEN,
		BLUE,
		BLACK,
		G32,
		G64,
		G127,
		WHITE,
		Color_WHITE_red,
		Color_WHITE_green,
		Color_WHITE_blue;

	bool AutoRun = false; // AutoRun 유무.. 
	int Cycle = 0; // AutoRun 사용 시 Position 자동선택에 관여.
	int Defect_Type = 0; // Defect Type ComboBox 에서 선택된 Item을 구분하는데 사용.
	int Position = 0; // Image 저장 시 몇 번째 Position을 사용했는지 확인하는 용도. ex)01_PD_G127.bmp

public: // 사용자 함수 선언
	void Canvas_Clear(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, Mat Color_WHITE_red, Mat Color_WHITE_green, Mat Color_WHITE_blue);
	void Point_Stain_Defect_Position_Select(int* PosX, int* Dark_PosY, int* Bright_PosY, int* Interval, int* Position, bool* AutoRun, int* Cycle);
	void Line_Defect_Position_Select(int* Dark_PosX, int* Bright_PosX, int* Interval, int* Position, bool* AutoRun, int* Cycle);
	void Draw_Point(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle);
	void Draw_Line(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle);
	void Draw_Stain(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle);
	void Draw_Stain_Color(Mat Color_WHITE_red, Mat Color_WHITE_green, Mat Color_WHITE_blue, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle);
	void Show_Image(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE);
	void Mono_Save_Image(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position);
	void Color_Save_Image(Mat Color_WHITE_red, Mat Color_WHITE_green, Mat Color_WHITE_blue, int* Defect_Type, int* Position);
// 대화 상자 데이터입니다.
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_MFC_OPENCV_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 지원입니다.

// 구현입니다.
protected:
	HICON m_hIcon;

	// 생성된 메시지 맵 함수
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	CComboBox m_Combo_DefectType;
	CComboBox m_Combo_DefectPosition;
	afx_msg void OnBnClickedButtonCreate();
	afx_msg void OnBnClickedButtonPreview();
	CComboBox m_Combo_Pattern;
	afx_msg void OnBnClickedButtonMonosave();
	afx_msg void OnBnClickedButtonColorsave();
	//afx_msg void OnBnClickedButtonAutocreate();
	afx_msg void OnBnClickedExit();
	afx_msg void OnBnClickedButtonCanvasclear();
	CProgressCtrl m_progressBar;
	afx_msg void OnBnClickedButtonAutorun();
	CEdit m_Edit_SavePath;
};

프로젝트Dlg.cpp

/*
제   목 : 어느 세월에 그림판으로 다 그리고 앉아있어~!~!
기   능 : Auto_Curved(국책과제) 촬상용 이미지 (결함시료) 자동으로 그려줌
파일이름 : MFC_OpenCV
수정날짜 : 2023-04-20
작 성 자 : 김영진
*/

// MFC_OpenCVDlg.cpp: 구현 파일

#include "pch.h"
#include "framework.h"
#include "MFC_OpenCV.h"
#include "MFC_OpenCVDlg.h"
#include "afxdialogex.h"
#include <direct.h>
#include <iostream>

using namespace std;

#define PanelSizeX 2940 // 캔버스 x축 px
#define PanelSizeY 816 // 캔버스 y축 px

enum {
	// Point Defect 127 수준별 밝기값 설정.
	PD_127_Bright_LEVEL_1 = 139,
	PD_127_Bright_LEVEL_2 = 152,
	PD_127_Bright_LEVEL_3 = 165,
	PD_127_Bright_LEVEL_4 = 177,
	PD_127_Bright_LEVEL_5 = 190,
	PD_127_Dark_LEVEL_1 = 115,
	PD_127_Dark_LEVEL_2 = 102,
	PD_127_Dark_LEVEL_3 = 89,
	PD_127_Dark_LEVEL_4 = 77,
	PD_127_Dark_LEVEL_5 = 64,

	// Point Defect BLACK 수준별 밝기값 설정.
	PD_BLACK_Bright_LEVEL_1 = 3,
	PD_BLACK_Bright_LEVEL_2 = 13,
	PD_BLACK_Bright_LEVEL_3 = 23,
	PD_BLACK_Bright_LEVEL_4 = 33,
	PD_BLACK_Bright_LEVEL_5 = 43,

	// Point Defect G32 수준별 밝기값 설정.
	PD_G32_Bright_LEVEL_1 = 35,
	PD_G32_Bright_LEVEL_2 = 38,
	PD_G32_Bright_LEVEL_3 = 41,
	PD_G32_Bright_LEVEL_4 = 44,
	PD_G32_Bright_LEVEL_5 = 48,
	PD_G32_Dark_LEVEL_1 = 29,
	PD_G32_Dark_LEVEL_2 = 26,
	PD_G32_Dark_LEVEL_3 = 23,
	PD_G32_Dark_LEVEL_4 = 20,
	PD_G32_Dark_LEVEL_5 = 16,

	// Point Defect G64 수준별 밝기값 설정.
	PD_G64_Bright_LEVEL_1 = 70,
	PD_G64_Bright_LEVEL_2 = 76,
	PD_G64_Bright_LEVEL_3 = 83,
	PD_G64_Bright_LEVEL_4 = 89,
	PD_G64_Bright_LEVEL_5 = 96,
	PD_G64_Dark_LEVEL_1 = 58,
	PD_G64_Dark_LEVEL_2 = 52,
	PD_G64_Dark_LEVEL_3 = 45,
	PD_G64_Dark_LEVEL_4 = 39,
	PD_G64_Dark_LEVEL_5 = 32,

	// Point Defect WHITE 수준별 밝기값 설정.
	PD_WHITE_Dark_LEVEL_1 = 230,
	PD_WHITE_Dark_LEVEL_2 = 204,
	PD_WHITE_Dark_LEVEL_3 = 179,
	PD_WHITE_Dark_LEVEL_4 = 153,
	PD_WHITE_Dark_LEVEL_5 = 128,

	// Line Defect 127 수준별 밝기값 설정.
	LD_127_Bright_LEVEL_1 = 130,
	LD_127_Bright_LEVEL_2 = 143,
	LD_127_Bright_LEVEL_3 = 156,
	LD_127_Bright_LEVEL_4 = 168,
	LD_127_Bright_LEVEL_5 = 181,
	LD_127_Dark_LEVEL_1 = 124,
	LD_127_Dark_LEVEL_2 = 111,
	LD_127_Dark_LEVEL_3 = 98,
	LD_127_Dark_LEVEL_4 = 86,
	LD_127_Dark_LEVEL_5 = 73,

	// Line Defect BLACK 수준별 밝기값 설정.
	LD_BLACK_Bright_LEVEL_1 = 1,
	LD_BLACK_Bright_LEVEL_2 = 3,
	LD_BLACK_Bright_LEVEL_3 = 7,
	LD_BLACK_Bright_LEVEL_4 = 10,
	LD_BLACK_Bright_LEVEL_5 = 13,

	// Line Defect G32 수준별 밝기값 설정.
	LD_G32_Bright_LEVEL_1 = 33,
	LD_G32_Bright_LEVEL_2 = 36,
	LD_G32_Bright_LEVEL_3 = 39,
	LD_G32_Bright_LEVEL_4 = 42,
	LD_G32_Bright_LEVEL_5 = 45,
	LD_G32_Dark_LEVEL_1 = 31,
	LD_G32_Dark_LEVEL_2 = 28,
	LD_G32_Dark_LEVEL_3 = 25,
	LD_G32_Dark_LEVEL_4 = 22,
	LD_G32_Dark_LEVEL_5 = 19,

	// Line Defect G64 수준별 밝기값 설정.
	LD_G64_Bright_LEVEL_1 = 65,
	LD_G64_Bright_LEVEL_2 = 72,
	LD_G64_Bright_LEVEL_3 = 78,
	LD_G64_Bright_LEVEL_4 = 85,
	LD_G64_Bright_LEVEL_5 = 91,
	LD_G64_Dark_LEVEL_1 = 63,
	LD_G64_Dark_LEVEL_2 = 56,
	LD_G64_Dark_LEVEL_3 = 50,
	LD_G64_Dark_LEVEL_4 = 43,
	LD_G64_Dark_LEVEL_5 = 37,

	// Line Defect WHITE 수준별 밝기값 설정.
	LD_WHITE_Dark_LEVEL_1 = 230,
	LD_WHITE_Dark_LEVEL_2 = 204,
	LD_WHITE_Dark_LEVEL_3 = 179,
	LD_WHITE_Dark_LEVEL_4 = 153,
	LD_WHITE_Dark_LEVEL_5 = 128,

	// Stain Defect 수준별 밝기값 설정은 밑에 따로있습니다.
};

int PD_127_Bright_LEVEL[] = { PD_127_Bright_LEVEL_1,
								PD_127_Bright_LEVEL_2,
								PD_127_Bright_LEVEL_3,
								PD_127_Bright_LEVEL_4,
								PD_127_Bright_LEVEL_5 };
int PD_127_Dark_LEVEL[] = { PD_127_Dark_LEVEL_1,
								PD_127_Dark_LEVEL_2,
								PD_127_Dark_LEVEL_3,
								PD_127_Dark_LEVEL_4,
								PD_127_Dark_LEVEL_5 };
int PD_BLACK_Bright_LEVEL[] = { PD_BLACK_Bright_LEVEL_1,
								PD_BLACK_Bright_LEVEL_2,
								PD_BLACK_Bright_LEVEL_3,
								PD_BLACK_Bright_LEVEL_4,
								PD_BLACK_Bright_LEVEL_5 };
int PD_G32_Bright_LEVEL[] = { PD_G32_Bright_LEVEL_1,
								PD_G32_Bright_LEVEL_2,
								PD_G32_Bright_LEVEL_3,
								PD_G32_Bright_LEVEL_4,
								PD_G32_Bright_LEVEL_5 };
int PD_G32_Dark_LEVEL[] = { PD_G32_Dark_LEVEL_1,
							PD_G32_Dark_LEVEL_2,
							PD_G32_Dark_LEVEL_3,
							PD_G32_Dark_LEVEL_4,
							PD_G32_Dark_LEVEL_5 };
int PD_G64_Bright_LEVEL[] = { PD_G64_Bright_LEVEL_1,
								PD_G64_Bright_LEVEL_2,
								PD_G64_Bright_LEVEL_3,
								PD_G64_Bright_LEVEL_4,
								PD_G64_Bright_LEVEL_5 };
int PD_G64_Dark_LEVEL[] = { PD_G64_Dark_LEVEL_1,
							PD_G64_Dark_LEVEL_2,
							PD_G64_Dark_LEVEL_3,
							PD_G64_Dark_LEVEL_4,
							PD_G64_Dark_LEVEL_5 };
int PD_WHITE_Dark_LEVEL[] = { PD_WHITE_Dark_LEVEL_1,
								PD_WHITE_Dark_LEVEL_2,
								PD_WHITE_Dark_LEVEL_3,
								PD_WHITE_Dark_LEVEL_4,
								PD_WHITE_Dark_LEVEL_5 };
int LD_127_Bright_LEVEL[] = { LD_127_Bright_LEVEL_1,
								LD_127_Bright_LEVEL_2,
								LD_127_Bright_LEVEL_3,
								LD_127_Bright_LEVEL_4,
								LD_127_Bright_LEVEL_5 };
int LD_127_Dark_LEVEL[] = { LD_127_Dark_LEVEL_1,
								LD_127_Dark_LEVEL_2,
								LD_127_Dark_LEVEL_3,
								LD_127_Dark_LEVEL_4,
								LD_127_Dark_LEVEL_5 };
int LD_BLACK_Bright_LEVEL[] = { LD_BLACK_Bright_LEVEL_1,
								LD_BLACK_Bright_LEVEL_2,
								LD_BLACK_Bright_LEVEL_3,
								LD_BLACK_Bright_LEVEL_4,
								LD_BLACK_Bright_LEVEL_5 };
int LD_G32_Bright_LEVEL[] = { LD_G32_Bright_LEVEL_1,
								LD_G32_Bright_LEVEL_2,
								LD_G32_Bright_LEVEL_3,
								LD_G32_Bright_LEVEL_4,
								LD_G32_Bright_LEVEL_5 };
int LD_G32_Dark_LEVEL[] = { LD_G32_Dark_LEVEL_1,
							LD_G32_Dark_LEVEL_2,
							LD_G32_Dark_LEVEL_3,
							LD_G32_Dark_LEVEL_4,
							LD_G32_Dark_LEVEL_5 };
int LD_G64_Bright_LEVEL[] = { LD_G64_Bright_LEVEL_1,
								LD_G64_Bright_LEVEL_2,
								LD_G64_Bright_LEVEL_3,
								LD_G64_Bright_LEVEL_4,
								LD_G64_Bright_LEVEL_5 };
int LD_G64_Dark_LEVEL[] = { LD_G64_Dark_LEVEL_1,
							LD_G64_Dark_LEVEL_2,
							LD_G64_Dark_LEVEL_3,
							LD_G64_Dark_LEVEL_4,
							LD_G64_Dark_LEVEL_5 };
int LD_WHITE_Dark_LEVEL[] = { LD_WHITE_Dark_LEVEL_1,
								LD_WHITE_Dark_LEVEL_2,
								LD_WHITE_Dark_LEVEL_3,
								LD_WHITE_Dark_LEVEL_4,
								LD_WHITE_Dark_LEVEL_5 };

// Stain Defect 수준별 밝기값 설정. 1 2 3 4 5 수준
// ex)G127 1수준 3% = (127 * 0.03) / 30 = 0.127
// 30 은 Stain Drawing 시 for문 반복횟수.
// 흑백 얼룩불량 수준
float Stain_127_Bright_LEVEL[] = { 0.127, 0.55, 0.9736, 1.397, 1.82 };
float Stain_127_Dark_LEVEL[] = { -0.127, -0.55, -0.96, -1.397, -1.82 };
float Stain_BLACK_Bright_LEVEL[] = { 0.03, 0.13, 0.23, 0.33, 0.43 };
float Stain_G32_Bright_LEVEL[] = { 0.03, 0.13, 0.24, 0.35, 0.45 };
float Stain_G32_Dark_LEVEL[] = { -0.03, -0.13, -0.24, -0.35, -0.45 };
float Stain_G64_Bright_LEVEL[] = { 0.064, 0.277, 0.49, 0.704, 0.9173 };
float Stain_G64_Dark_LEVEL[] = { -0.064, -0.277, -0.49, -0.704, -0.9173 };
float Stain_WHITE_Dark_LEVEL[] = { -0.255, -1.105, -1.955, -2.805, -3.655 };
// 컬러 얼룩불량 수준
float Stain_Color_WHITE_Dark_LEVEL[] = { -0.255, -1.105, -1.955, -2.805, -3.655 };

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMFCOpenCVDlg 대화 상자
CMFCOpenCVDlg::CMFCOpenCVDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_MFC_OPENCV_DIALOG, pParent) {
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMFCOpenCVDlg::DoDataExchange(CDataExchange* pDX) {
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_COMBO_DefectType, m_Combo_DefectType);
	DDX_Control(pDX, IDC_COMBO_DefectPosition, m_Combo_DefectPosition);
	DDX_Control(pDX, IDC_COMBO_Pattern, m_Combo_Pattern);
	DDX_Control(pDX, IDC_PROGRESS2, m_progressBar);
	DDX_Control(pDX, IDC_EDIT_SavePath, m_Edit_SavePath);
}

BEGIN_MESSAGE_MAP(CMFCOpenCVDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_Create, &CMFCOpenCVDlg::OnBnClickedButtonCreate)
	ON_BN_CLICKED(IDC_BUTTON_Preview, &CMFCOpenCVDlg::OnBnClickedButtonPreview)
	ON_BN_CLICKED(IDC_BUTTON_MonoSave, &CMFCOpenCVDlg::OnBnClickedButtonMonosave)
	ON_BN_CLICKED(IDC_BUTTON_ColorSave, &CMFCOpenCVDlg::OnBnClickedButtonColorsave)
	ON_BN_CLICKED(IDExit, &CMFCOpenCVDlg::OnBnClickedExit)
	ON_BN_CLICKED(IDC_BUTTON_CanvasClear, &CMFCOpenCVDlg::OnBnClickedButtonCanvasclear)
	ON_BN_CLICKED(IDC_BUTTON_AutoRun, &CMFCOpenCVDlg::OnBnClickedButtonAutorun)
END_MESSAGE_MAP()

// CMFCOpenCVDlg 메시지 처리기
BOOL CMFCOpenCVDlg::OnInitDialog() {
	CDialogEx::OnInitDialog();

	// 이 대화 상자의 아이콘을 설정합니다.  응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
	//  프레임워크가 이 작업을 자동으로 수행합니다.
	SetIcon(m_hIcon, TRUE);			// 큰 아이콘을 설정합니다.
	SetIcon(m_hIcon, FALSE);		// 작은 아이콘을 설정합니다.

	// TODO: 여기에 추가 초기화 작업을 추가합니다.

	// Program Window Name
	SetWindowText(L"곰두리 귀여웡");

	// Canvas 초기화 (PanelSizeY, PanelSizeX, 유형)
	RED = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	GREEN = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	BLUE = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	BLACK = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	G32 = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	G64 = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	G127 = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	WHITE = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	Color_WHITE_red = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	Color_WHITE_green = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);
	Color_WHITE_blue = Mat::zeros(PanelSizeY, PanelSizeX, CV_8UC3);

	// Canvas 초기화 (Blue, Green, Red)
	RED = Scalar(0, 0, 127);
	GREEN = Scalar(0, 127, 0);
	BLUE = Scalar(127, 0, 0);
	BLACK = Scalar(0, 0, 0);
	G32 = Scalar(32, 32, 32);
	G64 = Scalar(64, 64, 64);
	G127 = Scalar(127, 127, 127);
	WHITE = Scalar(255, 255, 255);
	Color_WHITE_red = Scalar(255, 255, 255);
	Color_WHITE_green = Scalar(255, 255, 255);
	Color_WHITE_blue = Scalar(255, 255, 255);

	// Defect Type ComboBox 항목 추가
	m_Combo_DefectType.AddString(_T("Point (Mono)"));
	m_Combo_DefectType.AddString(_T("Line (Mono)"));
	m_Combo_DefectType.AddString(_T("Stain (Mono)"));
	m_Combo_DefectType.AddString(_T("Stain (Color)"));
	m_Combo_DefectType.SetCurSel(0); // 초기값

	// Defect Position ComboBox 항목 추가
	m_Combo_DefectPosition.AddString(_T("1"));
	m_Combo_DefectPosition.AddString(_T("2"));
	m_Combo_DefectPosition.AddString(_T("3"));
	m_Combo_DefectPosition.AddString(_T("4"));
	m_Combo_DefectPosition.AddString(_T("5"));
	m_Combo_DefectPosition.AddString(_T("6"));
	m_Combo_DefectPosition.AddString(_T("7"));
	m_Combo_DefectPosition.AddString(_T("8"));
	m_Combo_DefectPosition.SetCurSel(0);

	// Pattern ComboBox 항목 추가
	m_Combo_Pattern.AddString(_T("RED"));
	m_Combo_Pattern.AddString(_T("GREEN"));
	m_Combo_Pattern.AddString(_T("BLUE"));
	m_Combo_Pattern.AddString(_T("BLACK"));
	m_Combo_Pattern.AddString(_T("G32"));
	m_Combo_Pattern.AddString(_T("G64"));
	m_Combo_Pattern.AddString(_T("G127"));
	m_Combo_Pattern.AddString(_T("WHITE"));
	m_Combo_Pattern.AddString(_T("Color_WHITE_red"));
	m_Combo_Pattern.AddString(_T("Color_WHITE_green"));
	m_Combo_Pattern.AddString(_T("Color_WHITE_blue"));
	m_Combo_Pattern.SetCurSel(0); // 초기값

	m_progressBar.SetRange(0, 216); // ProgressBar 초기화 0~216

	return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}

// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
//  아래 코드가 필요합니다.  문서/뷰 모델을 사용하는 MFC 애플리케이션의 경우에는
//  프레임워크에서 이 작업을 자동으로 수행합니다.

void CMFCOpenCVDlg::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();
	}
}

// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
//  이 함수를 호출합니다.
HCURSOR CMFCOpenCVDlg::OnQueryDragIcon() {
	return static_cast<HCURSOR>(m_hIcon);
}

// 클래스 멤버 사용자 함수 구현
void CMFCOpenCVDlg::Canvas_Clear(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, Mat Color_WHITE_red, Mat Color_WHITE_green, Mat Color_WHITE_blue) {
	RED = Scalar(0, 0, 127); // Scalar 함수를 이용해 배경을 다시 덧칠한다.
	GREEN = Scalar(0, 127, 0);
	BLUE = Scalar(127, 0, 0);
	BLACK = Scalar(0, 0, 0);
	G32 = Scalar(32, 32, 32);
	G64 = Scalar(64, 64, 64);
	G127 = Scalar(127, 127, 127);
	WHITE = Scalar(255, 255, 255);

	Color_WHITE_red = Scalar(255, 255, 255);
	Color_WHITE_green = Scalar(255, 255, 255);
	Color_WHITE_blue = Scalar(255, 255, 255);
}
void CMFCOpenCVDlg::Point_Stain_Defect_Position_Select(int* PosX, int* Dark_PosY, int* Bright_PosY, int* Interval, int* Position, bool* AutoRun, int* Cycle) {
	int select = 0; // 아래 switch 문에서 사용, Defect Position을 설정하는 용도.

	if (*AutoRun == true) { // AutoRun 일 경우엔
		select = *Cycle; // Cycle 로 부터 Select 값을 받아온다
	}
	else { // AutoRun이 아니라면 ComboBox에서 선택된 값을 읽어온다.
		select = m_Combo_DefectPosition.GetCurSel();
	}

	switch (select) {
	case 0: // 초기 설정값을 그대로 사용.
		*PosX = 300;
		*Dark_PosY = 200;
		*Bright_PosY = 600;
		*Interval = 350;
		*Position = 1;
		break;
	case 1: // 간격을 350 → 250 변경 & x축 시작위치 +300
		*PosX = 600;
		*Dark_PosY = 200;
		*Bright_PosY = 600;
		*Interval = 250;
		*Position = 2;
		break;
	case 2: // 간격을 350 → 150 변경 & x축 시작위치 +700
		*PosX = 1000;
		*Dark_PosY = 200;
		*Bright_PosY = 600;
		*Interval = 150;
		*Position = 3;
		break;
	case 3: // 간격을 그대로, 암점과 휘점의 Y축 거리를 200px만큼 더 가깝게
		*PosX = 300;
		*Dark_PosY = 300;
		*Bright_PosY = 500;
		*Interval = 350;
		*Position = 4;
		break;
	case 4: // 간격을 350 → 250 변경, 암점과 휘점의 Y축 거리를 200px만큼 더 가깝게 & x축 시작위치 +300
		*PosX = 600;
		*Dark_PosY = 300;
		*Bright_PosY = 500;
		*Interval = 250;
		*Position = 5;
		break;
	case 5: // 간격을 350 → 150 변경, 암점과 휘점의 Y축 거리를 200px만큼 더 가깝게 & x축 시작위치 +700
		*PosX = 1000;
		*Dark_PosY = 300;
		*Bright_PosY = 500;
		*Interval = 150;
		*Position = 6;
		break;
	case 6: // x축 시작위치를 -100px.
		*PosX = 200;
		*Dark_PosY = 200;
		*Bright_PosY = 600;
		*Interval = 350;
		*Position = 7;
		break;
	case 7: // x축 시작위치를 +100px.
		*PosX = 400;
		*Dark_PosY = 200;
		*Bright_PosY = 600;
		*Interval = 350;
		*Position = 8;
		break;
	default:
		MessageBox(_T("Point & Stain Defect Position Setting Error"));
		return;
		break;
	}
}
void CMFCOpenCVDlg::Line_Defect_Position_Select(int* Dark_PosX, int* Bright_PosX, int* Interval, int* Position, bool* AutoRun, int* Cycle) {
	int select = 0;

	if (*AutoRun == true) { // AutoRun 일 경우엔
		select = *Cycle; // Cycle 로 부터 Select 값을 받아온다
	}
	else { // AutoRun이 아니라면 ComboBox에서 선택된 값을 읽어온다.
		select = m_Combo_DefectPosition.GetCurSel();
	}

	switch (select) {
	case 0: // 기본값 그대로 사용.
		*Dark_PosX = 200;
		*Bright_PosX = 1100;
		*Interval = 150;
		*Position = 1;
		break;
	case 1: // 간격 150 → 200 변경. & x축 시작위치 -100
		*Dark_PosX = 100;
		*Bright_PosX = 1000;
		*Interval = 200;
		*Position = 2;
		break;
	case 2: // 간격 150 → 100 변경. & x축 시작위치 +100
		*Dark_PosX = 300;
		*Bright_PosX = 1200;
		*Interval = 100;
		*Position = 3;
		break;
	case 3: // 휘선암선 시작위치 변경 간격 그대로
		*Dark_PosX = 1100;
		*Bright_PosX = 200;
		*Interval = 150;
		*Position = 4;
		break;
	case 4: // 휘선암선 시작위치 변경 간격 150 → 200 & x축 시작위치 -100
		*Dark_PosX = 1000;
		*Bright_PosX = 100;
		*Interval = 200;
		*Position = 5;
		break;
	case 5: // 휘선암선 시작위치 변경 간격 150 → 100 & x축 시작위치 +100
		*Dark_PosX = 1200;
		*Bright_PosX = 300;
		*Interval = 100;
		*Position = 6;
		break;
	case 6: // 시작위치 암200 휘 350 간격 300 & x축 시작위치 +200
		*Dark_PosX = 400;
		*Bright_PosX = 550;
		*Interval = 300;
		*Position = 7;
		break;
	case 7: // 시작위치 암200 휘 350 간격 400 & x축 시작위치 +150
		*Dark_PosX = 350;
		*Bright_PosX = 700;
		*Interval = 400;
		*Position = 8;
		break;
	default:
		MessageBox(_T("Line Defect Position Setting Error"));
		return;
		break;
	}
}
void CMFCOpenCVDlg::Draw_Point(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle) { // PD
	*Defect_Type = 1; // Point Defect 의 Type 은 1
	*Position = 0; // Position 은 0으로 초기화

	int PosX = 300; // Position X축 처음 위치
	int Dark_PosY = 200; // Position 암점의 Y축 처음 위치
	int Bright_PosY = 600; // Position 휘점의 Y축 처음 위치
	int Interval = 350; // Defect 간의 X축 간격
	int Point_Size = 1; // rectangle Size를 2*2로 설정 (아래에서 상세설명)

	/*                                 시작위치            종료위치
	1로 설정함으로써 rectangle (image, (Point(x, y), Point(x + 1, y + 1), scalar(0, 0, 0), 1);
	두 번째 Point 인자값(종료위치)에 1씩 더해주는 역할을 수행한다.
	이는 곧 X축, Y축 의 종료위치에 1씩 추가되므로
	2*2 의 rectangle (사각형) 을 Drawing 한다.
	*/

	// Position Select 함수를 통해서 Defect의 처음위치, 간격 등을 설정한다.
	Point_Stain_Defect_Position_Select(&PosX, &Dark_PosY, &Bright_PosY, &Interval, Position, AutoRun, Cycle);

	for (int i = 0; i < 5; i++, PosX += Interval) { // Interval 값 PosX에 더해 불량의 간격을 증가.
		// RED
		rectangle(RED, Point(PosX, Dark_PosY), Point(PosX + Point_Size, Dark_PosY + Point_Size), Scalar(0, 0, PD_127_Dark_LEVEL[i]), 1);
		rectangle(RED, Point(PosX, Bright_PosY), Point(PosX + Point_Size, Bright_PosY + Point_Size), Scalar(0, 0, PD_127_Bright_LEVEL[i]), 1);
		// GREEN
		rectangle(GREEN, Point(PosX, Dark_PosY), Point(PosX + Point_Size, Dark_PosY + Point_Size), Scalar(0, PD_127_Dark_LEVEL[i], 0), 1);
		rectangle(GREEN, Point(PosX, Bright_PosY), Point(PosX + Point_Size, Bright_PosY + Point_Size), Scalar(0, PD_127_Bright_LEVEL[i], 0), 1);
		// BLUE
		rectangle(BLUE, Point(PosX, Dark_PosY), Point(PosX + Point_Size, Dark_PosY + Point_Size), Scalar(PD_127_Dark_LEVEL[i], 0, 0), 1);
		rectangle(BLUE, Point(PosX, Bright_PosY), Point(PosX + Point_Size, Bright_PosY + Point_Size), Scalar(PD_127_Bright_LEVEL[i], 0, 0), 1);
		// BLACK
		rectangle(BLACK, Point(PosX, Bright_PosY), Point(PosX + Point_Size, Bright_PosY + Point_Size), Scalar(PD_BLACK_Bright_LEVEL[i], PD_BLACK_Bright_LEVEL[i], PD_BLACK_Bright_LEVEL[i]), 1);
		// G32
		rectangle(G32, Point(PosX, Dark_PosY), Point(PosX + Point_Size, Dark_PosY + Point_Size), Scalar(PD_G32_Dark_LEVEL[i], PD_G32_Dark_LEVEL[i], PD_G32_Dark_LEVEL[i]), 1);
		rectangle(G32, Point(PosX, Bright_PosY), Point(PosX + Point_Size, Bright_PosY + Point_Size), Scalar(PD_G32_Bright_LEVEL[i], PD_G32_Bright_LEVEL[i], PD_G32_Bright_LEVEL[i]), 1);
		// G64
		rectangle(G64, Point(PosX, Dark_PosY), Point(PosX + Point_Size, Dark_PosY + Point_Size), Scalar(PD_G64_Dark_LEVEL[i], PD_G64_Dark_LEVEL[i], PD_G64_Dark_LEVEL[i]), 1);
		rectangle(G64, Point(PosX, Bright_PosY), Point(PosX + Point_Size, Bright_PosY + Point_Size), Scalar(PD_G64_Bright_LEVEL[i], PD_G64_Bright_LEVEL[i], PD_G64_Bright_LEVEL[i]), 1);
		// G127
		rectangle(G127, Point(PosX, Dark_PosY), Point(PosX + Point_Size, Dark_PosY + Point_Size), Scalar(PD_127_Dark_LEVEL[i], PD_127_Dark_LEVEL[i], PD_127_Dark_LEVEL[i]), 1);
		rectangle(G127, Point(PosX, Bright_PosY), Point(PosX + Point_Size, Bright_PosY + Point_Size), Scalar(PD_127_Bright_LEVEL[i], PD_127_Bright_LEVEL[i], PD_127_Bright_LEVEL[i]), 1);
		// WHITE
		rectangle(WHITE, Point(PosX, Dark_PosY), Point(PosX + Point_Size, Dark_PosY + Point_Size), Scalar(PD_WHITE_Dark_LEVEL[i], PD_WHITE_Dark_LEVEL[i], PD_WHITE_Dark_LEVEL[i]), 1);
	}
}
void CMFCOpenCVDlg::Draw_Line(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle) { // LD
	*Defect_Type = 2; // Line Defect 의 Type 은 2
	*Position = 0; // Position 은 0으로 초기화

	int Dark_PosX = 200; // 암선 x축 위치
	int Bright_PosX = 1100; // 휘선 y축 위치
	int Interval = 150; // Defect 간의 X축 간격

	// Position Select 함수를 통해서 Defect의 처음위치, 간격 등을 설정한다.
	Line_Defect_Position_Select(&Dark_PosX, &Bright_PosX, &Interval, Position, AutoRun, Cycle);

	for (int i = 0; i < 5; i++, Dark_PosX += Interval, Bright_PosX += Interval) { // x축 150px 씩 증가
		// RED
		line(RED, Point(Dark_PosX, 0), Point(Dark_PosX, 2940), Scalar(0, 0, LD_127_Dark_LEVEL[i]), 1);
		line(RED, Point(Bright_PosX, 0), Point(Bright_PosX, 2940), Scalar(0, 0, LD_127_Bright_LEVEL[i]), 1);
		// GREEN
		line(GREEN, Point(Dark_PosX, 0), Point(Dark_PosX, 2940), Scalar(0, LD_127_Dark_LEVEL[i], 0), 1);
		line(GREEN, Point(Bright_PosX, 0), Point(Bright_PosX, 2940), Scalar(0, LD_127_Bright_LEVEL[i], 0), 1);
		// BLUE
		line(BLUE, Point(Dark_PosX, 0), Point(Dark_PosX, 2940), Scalar(LD_127_Dark_LEVEL[i], 0, 0), 1);
		line(BLUE, Point(Bright_PosX, 0), Point(Bright_PosX, 2940), Scalar(LD_127_Bright_LEVEL[i], 0, 0), 1);
		// BLACK
		line(BLACK, Point(Bright_PosX, 0), Point(Bright_PosX, 2940), Scalar(LD_BLACK_Bright_LEVEL[i], LD_BLACK_Bright_LEVEL[i], LD_BLACK_Bright_LEVEL[i]), 1);
		// G32
		line(G32, Point(Dark_PosX, 0), Point(Dark_PosX, 2940), Scalar(LD_G32_Dark_LEVEL[i], LD_G32_Dark_LEVEL[i], LD_G32_Dark_LEVEL[i]), 1);
		line(G32, Point(Bright_PosX, 0), Point(Bright_PosX, 2940), Scalar(LD_G32_Bright_LEVEL[i], LD_G32_Bright_LEVEL[i], LD_G32_Bright_LEVEL[i]), 1);
		// G64
		line(G64, Point(Dark_PosX, 0), Point(Dark_PosX, 2940), Scalar(LD_G64_Dark_LEVEL[i], LD_G64_Dark_LEVEL[i], LD_G64_Dark_LEVEL[i]), 1);
		line(G64, Point(Bright_PosX, 0), Point(Bright_PosX, 2940), Scalar(LD_G64_Bright_LEVEL[i], LD_G64_Bright_LEVEL[i], LD_G64_Bright_LEVEL[i]), 1);
		// G127
		line(G127, Point(Dark_PosX, 0), Point(Dark_PosX, 2940), Scalar(LD_127_Dark_LEVEL[i], LD_127_Dark_LEVEL[i], LD_127_Dark_LEVEL[i]), 1);
		line(G127, Point(Bright_PosX, 0), Point(Bright_PosX, 2940), Scalar(LD_127_Bright_LEVEL[i], LD_127_Bright_LEVEL[i], LD_127_Bright_LEVEL[i]), 1);
		// WHITE
		line(WHITE, Point(Dark_PosX, 0), Point(Dark_PosX, 2940), Scalar(LD_WHITE_Dark_LEVEL[i], LD_WHITE_Dark_LEVEL[i], LD_WHITE_Dark_LEVEL[i]), 1);
	}
}
void CMFCOpenCVDlg::Draw_Stain(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle) {
	*Defect_Type = 3; // Stain Defect 의 Type 은 3
	*Position = 0; // Position 은 0으로 초기화

	int PosX = 300; // Position X축 처음 위치
	int Dark_PosY = 200; // Position 어두운 얼룩의 Y축 처음 위치
	int Bright_PosY = 600; // Position 밝은 얼룩의 Y축 처음 위치
	int Interval = 350; // Defect 간의 X축 간격
	int Radius = 30; // Stain의 반지름..
	/*
	Stain Defect 에 그라데이션 효과를 주기 위해서 Circle 함수를 반복하는 형식.
	반복문이 30회 돌면서 Radius 값을 1씩 감소시킨다.
	Radius 는 Circle 함수의 인자값으로 사용되며 Circle의 크기가 1px씩 감소한다.
	*/

	// Position Select 함수를 통해서 Defect의 처음위치, 간격 등을 설정한다.
	Point_Stain_Defect_Position_Select(&PosX, &Dark_PosY, &Bright_PosY, &Interval, Position, AutoRun, Cycle);

	for (int i = 0; i < 5; i++, PosX += Interval) { // Interval 값 PosX에 더해 불량의 간격을 증가.
		// RED
		for (int j = 1; j <= 30; j++, Radius -= 1) { // Circle 함수를 반복실행하여 그라데이션 효과를 준다.
			circle(RED, Point(PosX, Dark_PosY), Radius, Scalar(0, 0, 127 + Stain_127_Dark_LEVEL[i] * j), -1);
			circle(RED, Point(PosX, Bright_PosY), Radius, Scalar(0, 0, 127 + Stain_127_Bright_LEVEL[i] * j), -1);
		}
		Radius = 30;
		// GREEN
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(GREEN, Point(PosX, Dark_PosY), Radius, Scalar(0, 127 + Stain_127_Dark_LEVEL[i] * j, 0), -1);
			circle(GREEN, Point(PosX, Bright_PosY), Radius, Scalar(0, 127 + Stain_127_Bright_LEVEL[i] * j, 0), -1);
		}
		Radius = 30;
		// BLUE
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(BLUE, Point(PosX, Dark_PosY), Radius, Scalar(127 + Stain_127_Dark_LEVEL[i] * j, 0, 0), -1);
			circle(BLUE, Point(PosX, Bright_PosY), Radius, Scalar(127 + Stain_127_Bright_LEVEL[i] * j, 0, 0), -1);
		}
		Radius = 30;
		// BLACK
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(BLACK, Point(PosX, Bright_PosY), Radius, Scalar(Stain_BLACK_Bright_LEVEL[i] * j, Stain_BLACK_Bright_LEVEL[i] * j, Stain_BLACK_Bright_LEVEL[i] * j), -1);
		}
		Radius = 30;
		// G32
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(G32, Point(PosX, Dark_PosY), Radius, Scalar(32 + Stain_G32_Dark_LEVEL[i] * j, 32 + Stain_G32_Dark_LEVEL[i] * j, 32 + Stain_G32_Dark_LEVEL[i] * j), -1);
			circle(G32, Point(PosX, Bright_PosY), Radius, Scalar(32 + Stain_G32_Bright_LEVEL[i] * j, 32 + Stain_G32_Bright_LEVEL[i] * j, 32 + Stain_G32_Bright_LEVEL[i] * j), -1);
		}
		Radius = 30;
		// G64
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(G64, Point(PosX, Dark_PosY), Radius, Scalar(64 + Stain_G64_Dark_LEVEL[i] * j, 64 + Stain_G64_Dark_LEVEL[i] * j, 64 + Stain_G64_Dark_LEVEL[i] * j), -1);
			circle(G64, Point(PosX, Bright_PosY), Radius, Scalar(64 + Stain_G64_Bright_LEVEL[i] * j, 64 + Stain_G64_Bright_LEVEL[i] * j, 64 + Stain_G64_Bright_LEVEL[i] * j), -1);
		}
		Radius = 30;
		// G127
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(G127, Point(PosX, Dark_PosY), Radius, Scalar(127 + Stain_127_Dark_LEVEL[i] * j, 127 + Stain_127_Dark_LEVEL[i] * j, 127 + Stain_127_Dark_LEVEL[i] * j), -1);
			circle(G127, Point(PosX, Bright_PosY), Radius, Scalar(127 + Stain_127_Bright_LEVEL[i] * j, 127 + Stain_127_Bright_LEVEL[i] * j, 127 + Stain_127_Bright_LEVEL[i] * j), -1);
		}
		Radius = 30;
		// WHITE
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(WHITE, Point(PosX, Dark_PosY), Radius, Scalar(255 + Stain_WHITE_Dark_LEVEL[i] * j, 255 + Stain_WHITE_Dark_LEVEL[i] * j, 255 + Stain_WHITE_Dark_LEVEL[i] * j), -1);
		}
		Radius = 30;
	}
}
void CMFCOpenCVDlg::Draw_Stain_Color(Mat Color_WHITE_red, Mat Color_WHITE_green, Mat Color_WHITE_blue, int* Defect_Type, int* Position, bool* AutoRun, int* Cycle) {
	*Defect_Type = 3; // Stain Defect 의 Type 은 3
	*Position = 0; // Position 은 0으로 초기화

	int PosX = 300; // Position X축 처음 위치
	int Dark_PosY = 200; // Position 어두운 얼룩의 Y축 처음 위치이나.. Color Stain 에서는 밝은 얼룩을 Drawing 하고있다.
	int Bright_PosY = 600; // Position 밝은 얼룩의 Y축 처음 위치
	int Interval = 350; // Defect 간의 X축 간격
	int Radius = 30; // Stain의 반지름..
	/*
	Stain Defect 에 그라데이션 효과를 주기 위해서 Circle 함수를 반복하는 형식.
	반복문이 30회 돌면서 Radius 값을 1씩 감소시킨다.
	Radius 는 Circle 함수의 인자값으로 사용되며 Circle의 크기가 1px씩 감소한다.
	*/

	// Position Select 함수를 통해서 Defect의 처음위치, 간격 등을 설정한다.
	Point_Stain_Defect_Position_Select(&PosX, &Dark_PosY, &Bright_PosY, &Interval, Position, AutoRun, Cycle);

	for (int i = 0; i < 5; i++, PosX += Interval) { // Interval 값 PosX에 더해 불량의 간격을 증가.
		// RED
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(Color_WHITE_red, Point(PosX, Dark_PosY), Radius, Scalar(255, 255, 255 + Stain_Color_WHITE_Dark_LEVEL[i] * j), -1);
			circle(Color_WHITE_red, Point(PosX, Bright_PosY), Radius, Scalar(255, 255, 255 + Stain_Color_WHITE_Dark_LEVEL[i] * j), -1);
		}
		Radius = 30;
		// GREEN
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(Color_WHITE_green, Point(PosX, Dark_PosY), Radius, Scalar(255, 255 + Stain_Color_WHITE_Dark_LEVEL[i] * j, 255), -1);
			circle(Color_WHITE_green, Point(PosX, Bright_PosY), Radius, Scalar(255, 255 + Stain_Color_WHITE_Dark_LEVEL[i] * j, 255), -1);
		}
		Radius = 30;
		// BLUE
		for (int j = 1; j <= 30; j++, Radius -= 1) {
			circle(Color_WHITE_blue, Point(PosX, Dark_PosY), Radius, Scalar(255 + Stain_Color_WHITE_Dark_LEVEL[i] * j, 255, 255), -1);
			circle(Color_WHITE_blue, Point(PosX, Bright_PosY), Radius, Scalar(255 + Stain_Color_WHITE_Dark_LEVEL[i] * j, 255, 255), -1);
		}
		Radius = 30;
	}
}
void CMFCOpenCVDlg::Show_Image(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE) {
	// 현재 사용 안 하는 함수
	imshow("RED", RED);
	waitKey(0);
	imshow("GREEN", GREEN);
	waitKey(0);
	imshow("BLUE", BLUE);
	waitKey(0);
	imshow("BLACK", BLACK);
	waitKey(0);
	imshow("G32", G32);
	waitKey(0);
	imshow("G64", G64);
	waitKey(0);
	imshow("G127", G127);
	waitKey(0);
	imshow("WHITE", WHITE);
	waitKey(0);
}
void CMFCOpenCVDlg::Mono_Save_Image(Mat RED, Mat GREEN, Mat BLUE, Mat BLACK, Mat G32, Mat G64, Mat G127, Mat WHITE, int* Defect_Type, int* Position) {

	// 기본 저장경로
	string save_path = "D:\\Auto_Curved(국책)_그래픽_이미지";
	// make directory 함수에서의 사용을 위해 string -> const char* 형식으로 형변환해준다.
	char* Create_Directory = const_cast<char*>(save_path.c_str());
	_mkdir(Create_Directory); // 적용

	string Defect_Type_path; // Defect Type에 따른 image naming을 위한 변수.
	string Position_path; // Defect Position에 따른 image naming을 위한 변수.

	switch (*Position) {
	case 1:
		Position_path = "\\01_";
		break;
	case 2:
		Position_path = "\\02_";
		break;
	case 3:
		Position_path = "\\03_";
		break;
	case 4:
		Position_path = "\\04_";
		break;
	case 5:
		Position_path = "\\05_";
		break;
	case 6:
		Position_path = "\\06_";
		break;
	case 7:
		Position_path = "\\07_";
		break;
	case 8:
		Position_path = "\\08_";
		break;
	default:
		MessageBox(_T("Mono Save Image Defect Position Error"));
		return;
		break;
	}

	switch (*Defect_Type) {
	case 1:
		Defect_Type_path = "PD_";
		break;
	case 2:
		Defect_Type_path = "LD_";
		break;
	case 3:
		Defect_Type_path = "Stain_";
		break;
	default:
		MessageBox(_T("Mono Save Image Defect Type Error"));
		return;
		break;
	}

	// bmp 형식으로 지정.
	string RED_path = save_path + Position_path + Defect_Type_path + "RED.bmp";
	string GREEN_path = save_path + Position_path + Defect_Type_path + "GREEN.bmp";
	string BLUE_path = save_path + Position_path + Defect_Type_path + "BLUE.bmp";
	string BLACK_path = save_path + Position_path + Defect_Type_path + "BLACK.bmp";
	string G32_path = save_path + Position_path + Defect_Type_path + "G32.bmp";
	string G64_path = save_path + Position_path + Defect_Type_path + "G64.bmp";
	string G127_path = save_path + Position_path + Defect_Type_path + "G127.bmp";
	string WHITE_path = save_path + Position_path + Defect_Type_path + "WHITE.bmp";
	
	// 저장
	imwrite(RED_path, RED);
	imwrite(GREEN_path, GREEN);
	imwrite(BLUE_path, BLUE);
	imwrite(BLACK_path, BLACK);
	imwrite(G32_path, G32);
	imwrite(G64_path, G64);
	imwrite(G127_path, G127);
	imwrite(WHITE_path, WHITE);
}
void CMFCOpenCVDlg::Color_Save_Image(Mat Color_WHITE_red, Mat Color_WHITE_green, Mat Color_WHITE_blue, int* Defect_Type, int* Position) {

	// 기본 저장경로
	string save_path = "D:\\Auto_Curved(국책)_그래픽_이미지";
	// make directory 함수에서의 사용을 위해 string -> const char* 형식으로 형변환해준다.
	char* Create_Directory = const_cast<char*>(save_path.c_str());
	_mkdir(Create_Directory); // 적용

	string Defect_Type_path;  // Defect Type에 따른 image naming을 위한 변수.
	string Position_path; // Defect Position에 따른 image naming을 위한 변수.

	switch (*Position) {
	case 1:
		Position_path = "\\01_";
		break;
	case 2:
		Position_path = "\\02_";
		break;
	case 3:
		Position_path = "\\03_";
		break;
	case 4:
		Position_path = "\\04_";
		break;
	case 5:
		Position_path = "\\05_";
		break;
	case 6:
		Position_path = "\\06_";
		break;
	case 7:
		Position_path = "\\07_";
		break;
	case 8:
		Position_path = "\\08_";
		break;
	default:
		MessageBox(_T("Color Save Image Defect Position Error"));
		return;
		break;
	}

	switch (*Defect_Type) {
	case 3:
		Defect_Type_path = "Stain_";
		break;
	default:
		MessageBox(_T("Mono Save Image Defect Type Error"));
		return;
		break;
	}

	// bmp 형식으로 지정.
	string Color_WHITE_red_path = save_path + Position_path + Defect_Type_path + "WHITE_red.bmp";
	string Color_WHITE_green_path = save_path + Position_path + Defect_Type_path + "WHITE_green.bmp";
	string Color_WHITE_blue_path = save_path + Position_path + Defect_Type_path + "WHITE_blue.bmp";

	// 저장
	imwrite(Color_WHITE_red_path, Color_WHITE_red);
	imwrite(Color_WHITE_green_path, Color_WHITE_green);
	imwrite(Color_WHITE_blue_path, Color_WHITE_blue);
}

// MFC 컨트롤 함수
void CMFCOpenCVDlg::OnBnClickedButtonCreate() {
	AutoRun = false;
	Defect_Type = m_Combo_DefectType.GetCurSel(); // 첫 번째 ComboBox에서 무엇을 선택했는지 확인
	switch (Defect_Type) {
	case 0: // Point (Mono)
		Draw_Point(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position, &AutoRun, &Cycle);
		break;
	case 1: // Line (Mono)
		Draw_Line(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position, &AutoRun, &Cycle);
		break;
	case 2: // Stain (Mono)
		Draw_Stain(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position, &AutoRun, &Cycle);
		break;
	case 3: // Stain (Color)
		Draw_Stain_Color(Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue, &Defect_Type, &Position, &AutoRun, &Cycle);
		break;
	default: // ComboBox 에서 값을 가져오기 때문에 예외가 발생할 수 없음.
		MessageBox(_T("Defect Type ComboBox Error"));
		break;
	}
}
void CMFCOpenCVDlg::OnBnClickedButtonPreview() { // 미리보기
	int nPattern = m_Combo_Pattern.GetCurSel();
	switch (nPattern) {
	case 0: // RED
		imshow("RED", RED);
		break;
	case 1: // GREEN
		imshow("GREEN", GREEN);
		break;
	case 2: // BLUE
		imshow("BLUE", BLUE);
		break;
	case 3: // BLACK
		imshow("BLACK", BLACK);
		break;
	case 4: // G32
		imshow("G32", G32);
		break;
	case 5: // G64
		imshow("G64", G64);
		break;
	case 6: // G127
		imshow("G127", G127);
		break;
	case 7: // WHITE
		imshow("WHITE", WHITE);
		break;
	case 8: // Color_WHITE_red
		imshow("Color_WHITE_red", Color_WHITE_red);
		break;
	case 9: // Color_WHITE_green
		imshow("Color_WHITE_green", Color_WHITE_green);
		break;
	case 10: // Color_WHITE_blue
		imshow("Color_WHITE_blue", Color_WHITE_blue);
		break;
	default: // ComboBox 에서 값을 가져오기 때문에 예외가 발생할 수 없음.
		MessageBox(_T("Pattern ComboBox Error"));
		break;
	}
}
void CMFCOpenCVDlg::OnBnClickedButtonMonosave() {
	Mono_Save_Image(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position);
	Canvas_Clear(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue);
}
void CMFCOpenCVDlg::OnBnClickedButtonColorsave() {
	Color_Save_Image(Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue, &Defect_Type, &Position);
	Canvas_Clear(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue);
}
void CMFCOpenCVDlg::OnBnClickedExit() {
	EndDialog(IDD_MFC_OPENCV_DIALOG);
}
void CMFCOpenCVDlg::OnBnClickedButtonCanvasclear() {
	Canvas_Clear(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue);
}
void CMFCOpenCVDlg::OnBnClickedButtonAutorun() {
	AutoRun = true;
	float ProgressBar_Count = 0; // 진행상황 표기용.

	for (int i = 0; i < 8; i++) { // PD 자동 생성
		Draw_Point(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position, &AutoRun, &Cycle);
		Mono_Save_Image(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position);
		Canvas_Clear(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue);
		Cycle++; // Cycle에 따라 Position이 자동으로 선택된다.
		ProgressBar_Count += 6.75; // 이 값만큼 증가시키면서
		m_progressBar.SetPos(ProgressBar_Count); // 진행 상황을 보여준다.
	}
	Cycle = 0;

	for (int i = 0; i < 8; i++) { // LD 자동 생성
		Draw_Line(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position, &AutoRun, &Cycle);
		Mono_Save_Image(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position);
		Canvas_Clear(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue);
		Cycle++; // Cycle에 따라 Position이 자동으로 선택된다.
		ProgressBar_Count += 6.75; // 이 값만큼 증가시키면서
		m_progressBar.SetPos(ProgressBar_Count); // 진행 상황을 보여준다.
	}
	Cycle = 0;

	for (int i = 0; i < 8; i++) { // Stain 자동 생성
		Draw_Stain(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position, &AutoRun, &Cycle);
		Mono_Save_Image(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, &Defect_Type, &Position);
		Canvas_Clear(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue);
		Cycle++; // Cycle에 따라 Position이 자동으로 선택된다.
		ProgressBar_Count += 6.75; // 이 값만큼 증가시키면서
		m_progressBar.SetPos(ProgressBar_Count); // 진행 상황을 보여준다.
	}
	Cycle = 0;

	for (int i = 0; i < 8; i++) { // Stain 자동 생성
		Draw_Stain_Color(Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue, &Defect_Type, &Position, &AutoRun, &Cycle);
		Color_Save_Image(Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue, &Defect_Type, &Position);
		Canvas_Clear(RED, GREEN, BLUE, BLACK, G32, G64, G127, WHITE, Color_WHITE_red, Color_WHITE_green, Color_WHITE_blue);
		Cycle++; // Cycle에 따라 Position이 자동으로 선택된다.
		ProgressBar_Count += 6.75; // 이 값만큼 증가시키면서
		m_progressBar.SetPos(ProgressBar_Count); // 진행 상황을 보여준다.
	}
	Cycle = 0;

	MessageBox(_T("Auto Run Complete"));
	m_progressBar.SetPos(0); // AutoRun이 완료되고나면 ProgressBar를 초기화해준다.
}

주석 좀 더 자세히 달고…
자동생성 할 때 switch 문쪽에 조금 수정한거랑
프로그레스 바 UI 추가한거 정도?
그 외엔 손댄거 없고 잘 돌아간다!

image-20230429205327247

프로그램의 실행모습 ㅋㅋ 윈도우 네임이랑 아이콘을 변경해주었다.
역시 코드 짜는것도 재밌지만… 눈에 보이는 것을 꾸밀 때가 가장 재밌는 것 같다.

콤보박스에서 이것저것 선택해 Create 버튼을 클릭하고
Preview 버튼을 클릭하면 생성된 이미지를 미리 볼 수 있게끔 만들었고..
Save 버튼은 저장이고
Auto Run 버튼을 누르면 프로그레스 바가 증가하면서
자동으로 생성 및 저장을 하게끔 만들어놨다.

image-20230429205651864

요로코롬!

image-20230429205930475

자동으로 생성된 이미지들이 저장된 모습.

끝!

댓글남기기