個人實驗程式碼記錄 | 數字影像處理實驗3·影像直方圖與均衡化處理

tututupro發表於2020-11-04

個人實驗記錄 | 數字影像處理實驗3·影像直方圖與均衡化處理

參考文章:【數字影像處理】四.MFC對話方塊繪製灰度直方圖

CTest2ZFTDlg.cpp: 實現檔案

// CTest2ZFTDlg.cpp: 實現檔案
//

#include "pch.h"
#include "Test2.h"
#include "CTest2ZFTDlg.h"
#include "afxdialogex.h"


// CTest2ZFTDlg 對話方塊

IMPLEMENT_DYNAMIC(CTest2ZFTDlg, CDialogEx)

CTest2ZFTDlg::CTest2ZFTDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DIALOG_ZFT, pParent)
	/*, m_redBZC(_T(""))
	, m_redPJHD(_T(""))
	, m_redXS(_T(""))
	, m_redZZHD(_T(""))
	, m_blueBZC(_T(""))
	, m_bluePJHD(_T(""))
	, m_blueXS(_T(""))
	, m_blueZZHD(_T(""))
	, m_greenBZC(_T(""))
	, m_green_PJHD(_T(""))
	, m_greenXS(_T(""))
	, m_greenZZHD(_T(""))*/
	, m_blueBZC(_T(""))
	, m_bluePJHD(_T(""))
	, m_blueXS(_T(""))
	, m_blueZZHD(_T(""))
	, m_greenBZC(_T(""))
	, m_greenPJHD(_T(""))
	, m_greenXS(_T(""))
	, m_greenZZHD(_T(""))
	, m_redBZC(_T(""))
	, m_redPJHD(_T(""))
	, m_redXS(_T(""))
	, m_redZZHD(_T(""))
	, m_blueF(_T(""))
	, m_blueMax(_T(""))
	, m_blueMin(_T(""))
	, m_blueMost(_T(""))
	, m_greenF(_T(""))
	, m_greenMax(_T(""))
	, m_greenMin(_T(""))
	, m_greenMost(_T(""))
	, m_redF(_T(""))
	, m_redMax(_T(""))
	, m_redMin(_T(""))
	, m_redMost(_T(""))
{

}

CTest2ZFTDlg::~CTest2ZFTDlg()
{
}

void CTest2ZFTDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	//  DDX_Control(pDX, IDC_STATIC_R_BZC, m_redBZC);
	//  DDX_Control(pDX, IDC_STATIC_R_PJHD, m_redPJHD);
	//  DDX_Control(pDX, IDC_STATIC_R_XS, m_redXS);
	//  DDX_Control(pDX, IDC_STATIC_R_ZZHD, m_redZZHD);
	//  DDX_Control(pDX, IDC_STATIC_B_BZC, m_blueBZC);
	//  DDX_Control(pDX, IDC_STATIC_B_PJHD, m_bluePJHD);
	//  DDX_Control(pDX, IDC_STATIC_B_XS, m_blueXS);
	//  DDX_Control(pDX, IDC_STATIC_B_ZZHD, m_blueZZHD);
	//  DDX_Control(pDX, IDC_STATIC_G_BZC, m_greenBZC);
	//  DDX_Control(pDX, IDC_STATIC_G_PJHD, m_green_PJHD);
	//  DDX_Control(pDX, IDC_STATIC_G_XS, m_greenXS);
	//  DDX_Control(pDX, IDC_STATIC_G_ZZHD, m_greenZZHD);
	DDX_Text(pDX, IDC_STATIC_B_BZC, m_blueBZC);
	DDX_Text(pDX, IDC_STATIC_B_PJHD, m_bluePJHD);
	DDX_Text(pDX, IDC_STATIC_B_XS, m_blueXS);
	DDX_Text(pDX, IDC_STATIC_B_ZZHD, m_blueZZHD);
	DDX_Text(pDX, IDC_STATIC_G_BZC, m_greenBZC);
	DDX_Text(pDX, IDC_STATIC_G_PJHD, m_greenPJHD);
	DDX_Text(pDX, IDC_STATIC_G_XS, m_greenXS);
	DDX_Text(pDX, IDC_STATIC_G_ZZHD, m_greenZZHD);
	DDX_Text(pDX, IDC_STATIC_R_BZC, m_redBZC);
	DDX_Text(pDX, IDC_STATIC_R_PJHD, m_redPJHD);
	DDX_Text(pDX, IDC_STATIC_R_XS, m_redXS);
	DDX_Text(pDX, IDC_STATIC_R_ZZHD, m_redZZHD);
	DDX_Text(pDX, IDC_STATIC_B_F, m_blueF);
	DDX_Text(pDX, IDC_STATIC_B_MAX, m_blueMax);
	DDX_Text(pDX, IDC_STATIC_B_MIN, m_blueMin);
	DDX_Text(pDX, IDC_STATIC_B_MOST, m_blueMost);
	DDX_Text(pDX, IDC_STATIC_G_F, m_greenF);
	DDX_Text(pDX, IDC_STATIC_G_MAX, m_greenMax);
	DDX_Text(pDX, IDC_STATIC_G_MIN, m_greenMin);
	DDX_Text(pDX, IDC_STATIC_G_MOST, m_greenMost);
	DDX_Text(pDX, IDC_STATIC_R_F, m_redF);
	DDX_Text(pDX, IDC_STATIC_R_MAX, m_redMax);
	DDX_Text(pDX, IDC_STATIC_R_Min, m_redMin);
	DDX_Text(pDX, IDC_STATIC_R_MOST, m_redMost);
}


BEGIN_MESSAGE_MAP(CTest2ZFTDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_NCPAINT()
END_MESSAGE_MAP()


// CTest2ZFTDlg 訊息處理程式


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

	// TODO:  在此新增額外的初始化

	return TRUE;  // return TRUE unless you set the focus to a control
				  // 異常: OCX 屬性頁應返回 FALSE
}


void CTest2ZFTDlg::OnPaint()
{
	CPaintDC dc(this); // device context for painting
					   // TODO: 在此處新增訊息處理程式程式碼
					   // 不為繪圖訊息呼叫 CDialogEx::OnPaint()

	extern int Red[256], Green[256], Blue[256];

	/*寫在該空間中可以省略Invalidate()語句*/
	/*獲取控制元件的CDC指標*/
	CRect rectpic;
	GetDlgItem(IDC_STATIC_Control)->GetWindowRect(&rectpic);

	int x, y;
	x = rectpic.Width();
	y = rectpic.Height();

	CWnd* pWnd = GetDlgItem(IDC_STATIC_Control);
	CDC* pDC = pWnd->GetDC();

	/***********************/
	/*重點:畫直方圖 紅色
	/**********************/
	CPen* RedPen = new CPen();                              //建立畫筆物件
	RedPen->CreatePen(PS_SOLID, 1, RGB(255, 0, 0));           //紅色畫筆
	CGdiObject* RedOlderPen = pDC->SelectObject(RedPen);    //選中當前紅色畫筆並儲存以前的畫筆

	/*畫圖*/
	pDC->Rectangle(9, 16, 312, 147);      //畫一個矩形框
	pDC->MoveTo(15, 20);                //繪製座標軸
	pDC->LineTo(15, 128);               //Y豎軸
	pDC->LineTo(305, 128);              //X橫軸

	pDC->MoveTo(305, 128);              //繪製X箭頭
	pDC->LineTo(300, 123);              //繪製上邊箭頭
	pDC->MoveTo(305, 128);
	pDC->LineTo(300, 133);              //繪製下邊箭頭

	pDC->MoveTo(15, 20);                //繪製Y箭頭
	pDC->LineTo(10, 25);                //繪製左邊箭頭
	pDC->MoveTo(15, 20);
	pDC->LineTo(20, 25);                //繪製右邊箭頭

	/**********************************************************************/
	/* TextOut函式功能:
	/* 該函式用當前選擇的字型、背景顏色和正文顏色將一個字串寫到指定位置
	/* BOOL TextOut(HDC hdc,int x,int y,LPCTSTR str,int numStr)
	/* 表示:x起始座標,y起始座標,字串,字串中字元個數
	/*
	/* SetTextColor函式功能:
	/* 設定指定裝置環境(HDC)的字型顏色
	/* SetTextColor (HDC, COLORREF) 如:SetTextColor(HDC,RGB(255,0,0));
	/**********************************************************************/

	CString str;
	int i;
	for (i = 0;i <= 5;i++)                    //寫X軸刻度線
	{
		str.Format(_T("%d"), i * 50);               //0-255之間新增6個刻度值
		pDC->SetTextColor(RGB(255, 0, 255));   //設定字型顏色
		pDC->TextOut(15 + 48 * i, 130, str);       //輸出字型
		pDC->MoveTo(15 + 48 * i, 128);            //繪製X軸刻度
		pDC->LineTo(15 + 48 * i, 125);
	}
	for (i = 0;i <= 5;i++)                        //寫Y軸刻度線
	{
		pDC->MoveTo(15, 128 - 20 * i);            //繪製Y軸刻度
		pDC->LineTo(18, 128 - 20 * i);
	}

	/*繪製直方圖主要的程式碼*/
	for (i = 1;i < 256;i++)
	{
		pDC->MoveTo(15 + i, 128);
		if ((128 - 16) > (Red[i] / 40))
			pDC->LineTo(15 + i, 128 - (Red[i] / 40));
		else
			pDC->LineTo(15 + i, 16);            //超過矩形的畫矩形高
	}


	/**********************/
	/*重點:畫直方圖 綠色
	/**********************/
	CPen* GreenPen = new CPen();                             //建立畫筆物件
	GreenPen->CreatePen(PS_SOLID, 1, RGB(0, 255, 0));          //綠色畫筆
	CGdiObject* GreenOlderPen = pDC->SelectObject(GreenPen);

	pDC->Rectangle(9, 167, 312, 308);     //畫一個矩形框
	pDC->MoveTo(15, 171);               //繪製座標軸
	pDC->LineTo(15, 288);               //Y豎軸
	pDC->LineTo(305, 288);              //X橫軸

	pDC->MoveTo(305, 288);              //繪製X箭頭
	pDC->LineTo(300, 283);              //繪製上邊箭頭
	pDC->MoveTo(305, 288);
	pDC->LineTo(300, 293);              //繪製下邊箭頭

	pDC->MoveTo(15, 171);                //繪製Y箭頭
	pDC->LineTo(10, 176);                //繪製左邊箭頭
	pDC->MoveTo(15, 171);
	pDC->LineTo(20, 176);                //繪製右邊箭頭

	for (i = 0;i <= 5;i++)                   //寫X軸刻度線
	{
		str.Format(_T("%d"), i * 50);               //0-255之間新增6個刻度值
		pDC->SetTextColor(RGB(255, 0, 255));   //設定字型顏色
		pDC->TextOut(15 + 48 * i, 290, str);       //輸出字型

		pDC->MoveTo(15 + 48 * i, 288);            //繪製X軸刻度
		pDC->LineTo(15 + 48 * i, 285);
	}
	for (i = 0;i <= 5;i++)                        //寫Y軸刻度線
	{
		pDC->MoveTo(15, 288 - 20 * i);            //繪製Y軸刻度
		pDC->LineTo(18, 288 - 20 * i);
	}

	/*繪製直方圖主要的程式碼*/
	for (i = 1;i < 256;i++)
	{
		pDC->MoveTo(15 + i, 288);
		if ((288 - 167) > (Green[i] / 40))
			pDC->LineTo(15 + i, 288 - (Green[i] / 40));
		else
			pDC->LineTo(15 + i, 167);            //超過矩形的畫矩形高
	}


	/**********************/
	/*重點:畫直方圖 藍色
	/***************((*****/
	CPen* BluePen = new CPen();                            //建立畫筆物件
	BluePen->CreatePen(PS_SOLID, 1, RGB(0, 0, 255));         //藍色畫筆
	CGdiObject* BlueOlderPen = pDC->SelectObject(BluePen);

	pDC->Rectangle(9, 327, 312, 468);      //畫一個矩形框
	pDC->MoveTo(15, 331);                //繪製座標軸
	pDC->LineTo(15, 448);                //Y豎軸
	pDC->LineTo(305, 448);               //X橫軸

	pDC->MoveTo(305, 448);               //繪製X箭頭
	pDC->LineTo(300, 443);               //繪製上邊箭頭
	pDC->MoveTo(305, 448);
	pDC->LineTo(300, 453);               //繪製下邊箭頭

	pDC->MoveTo(15, 331);                //繪製Y箭頭
	pDC->LineTo(10, 336);                //繪製左邊箭頭
	pDC->MoveTo(15, 331);
	pDC->LineTo(20, 336);                //繪製右邊箭頭


	for (i = 0;i <= 5;i++)                   //寫X軸刻度線
	{
		str.Format(_T("%d"), i * 50);               //0-255之間新增6個刻度值
		pDC->SetTextColor(RGB(255, 0, 255));   //設定字型顏色
		pDC->TextOut(15 + 48 * i, 450, str);       //輸出字型

		pDC->MoveTo(15 + 48 * i, 448);            //繪製X軸刻度
		pDC->LineTo(15 + 48 * i, 445);
	}
	for (i = 0;i <= 5;i++)                        //寫Y軸刻度線
	{
		pDC->MoveTo(15, 448 - 20 * i);            //繪製Y軸刻度
		pDC->LineTo(18, 448 - 20 * i);
	}

	/*繪製直方圖主要的程式碼*/
	for (i = 1;i < 256;i++)
	{
		pDC->MoveTo(15 + i, 448);
		if ((448 - 327) > (Blue[i] / 40))
			pDC->LineTo(15 + i, 448 - (Blue[i] / 40));
		else
			pDC->LineTo(15 + i, 327);            //超過矩形的畫矩形高
	}


	//恢復以前的畫筆
	pDC->SelectObject(RedOlderPen);
	pDC->SelectObject(GreenOlderPen);
	pDC->SelectObject(BlueOlderPen);
	delete RedPen;
	delete GreenPen;
	delete BluePen;
	ReleaseDC(pDC);
	return;

}


void CTest2ZFTDlg::OnNcPaint()
{
	// TODO: 在此處新增訊息處理程式程式碼
	// 不為繪圖訊息呼叫 CDialogEx::OnNcPaint()
}

View.cpp實現:


// Test2View.cpp: CTest2View 類的實現
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在實現預覽、縮圖和搜尋篩選器控制程式碼的
// ATL 專案中進行定義,並允許與該專案共享文件程式碼。
#ifndef SHARED_HANDLERS
#include "Test2.h"
#endif

#include "Test2Doc.h"
#include "Test2View.h"
#include "CTest2ZFTDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CTest2View

IMPLEMENT_DYNCREATE(CTest2View, CView)

BEGIN_MESSAGE_MAP(CTest2View, CView)
	// 標準列印命令
	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_OPEN, &CTest2View::OnFileOpen)
	ON_COMMAND(ID_FILE_SAVE_AS, &CTest2View::OnFileSaveAs)
	ON_COMMAND(ID_ZFT_YT, &CTest2View::OnZftYt)
	ON_COMMAND(ID_JHH, &CTest2View::OnJhh)
	ON_COMMAND(ID_GGH, &CTest2View::OnGgh)
	ON_COMMAND(ID_EZH, &CTest2View::OnEzh)
END_MESSAGE_MAP()

// CTest2View 構造/析構



int Red[256], Green[256], Blue[256];
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
CString debugMess;
CTest2View::CTest2View() noexcept
{
	// TODO: 在此處新增構造程式碼
	m_dib = NULL;
}

CTest2View::~CTest2View()
{
	if (m_dib != NULL) {
		delete m_dib;
		m_dib = NULL;
	}
}

BOOL CTest2View::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此處通過修改
	//  CREATESTRUCT cs 來修改視窗類或樣式

	return CView::PreCreateWindow(cs);
}

// CTest2View 繪圖

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

	if (SaveName.Compare(_T("bmp")) == 0)      //bmp格式
	{
		ShowBitmap(pDC, BmpName,0,0);               //顯示圖片
	}

}


// CTest2View 列印

BOOL CTest2View::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 預設準備
	return DoPreparePrinting(pInfo);
}

void CTest2View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 新增額外的列印前進行的初始化過程
}

void CTest2View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 新增列印後進行的清理過程
}


// CTest2View 診斷

#ifdef _DEBUG
void CTest2View::AssertValid() const
{
	CView::AssertValid();
}

void CTest2View::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CTest2Doc* CTest2View::GetDocument() const // 非除錯版本是內聯的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTest2Doc)));
	return (CTest2Doc*)m_pDocument;
}
#endif //_DEBUG


// CTest2View 訊息處理程式


void CTest2View::OnFileOpen()
{

	if (m_dib)
	{
		delete m_dib;
		m_dib = NULL;
	}

	CString filter;
	filter = "所有檔案(*.bmp,*.jpg,*.gif,*tiff)|*.bmp;*.jpg;*.gif;*.tiff| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg| GIF(*.gif)|*.gif| TIFF(*.tiff)|*.tiff||";
	CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, filter, NULL);

	//按下確定按鈕 dlg.DoModal() 函式顯示對話方塊
	if (dlg.DoModal() == IDOK)
	{
		BmpName = dlg.GetPathName();      //獲取檔案路徑名   如D:\pic\abc.bmp
		SaveName = dlg.GetFileExt();      //獲取副檔名
		SaveName.MakeLower();             //將副檔名轉換為一個小寫字元
		m_dib = new MyDIB;
		m_dib->Read(BmpName);

		Invalidate();                     //呼叫該函式就會呼叫OnDraw重繪畫圖
	}

}


void CTest2View::OnFileSaveAs()
{
	if(m_dib == NULL) {
		return;
	}

	CDC* pDC = GetWindowDC();

	CFileDialog fDlg(FALSE, _T("bmp"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("點陣圖檔案|*.bmp"), this);
	if (fDlg.DoModal() == IDOK)
	{

		CString bmpfile = fDlg.GetPathName();
		m_dib->Write(bmpfile, pDC, m_dib->m_width, m_dib->m_height);
	}

}


//****************顯示BMP格式圖片****************//
void CTest2View::ShowBitmap(CDC* pDC, CString BmpName,int x ,int y)
{
	//定義bitmap指標 呼叫函式LoadImage裝載點陣圖
	HBITMAP m_hBitmap;
	m_hBitmap = (HBITMAP)LoadImage(NULL, BmpName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE | LR_CREATEDIBSECTION);

	/*************************************************************************/
	/* 1.要裝載OEM影像,則設此引數值為0  OBM_ OEM點陣圖 OIC_OEM圖示 OCR_OEM游標
	/* 2.BmpName要裝載圖片的檔名
	/* 3.裝載影像型別:
	/*   IMAGE_BITMAP-裝載點陣圖 IMAGE_CURSOR-裝載游標 IMAGE_ICON-裝載圖示
	/* 4.指定圖示或游標的畫素寬度和長度 以畫素為單位
	/* 5.載入選項:
	/*   IR_LOADFROMFILE-指明由lpszName指定檔案中載入影像
	/*   IR_DEFAULTSIZE-指明使用影像預設大小
	/*   LR_CREATEDIBSECTION-當uType引數為IMAGE_BITMAP時,建立一個DIB項
	/**************************************************************************/

	if (m_bitmap.m_hObject)
	{
		m_bitmap.Detach();           //切斷CWnd和視窗聯絡
	}
	m_bitmap.Attach(m_hBitmap);      //將控制程式碼HBITMAP m_hBitmap與CBitmap m_bitmap關聯

	//邊界
	CRect rect;
	GetClientRect(&rect);

	//圖片顯示(x,y)起始座標
	int m_nWindowWidth = rect.right - rect.left;   //計算客戶區寬度
	int m_nWindowHeight = rect.bottom - rect.top;  //計算客戶區高度

	//定義並建立一個記憶體裝置環境DC
	CDC dcBmp;
	if (!dcBmp.CreateCompatibleDC(pDC))   //建立相容性的DC
		return;

	BITMAP m_bmp;                          //臨時bmp圖片變數
	m_bitmap.GetBitmap(&m_bmp);            //將圖片載入點陣圖中

	CBitmap* pbmpOld = NULL;
	dcBmp.SelectObject(&m_bitmap);         //將點陣圖選入臨時記憶體裝置環境


	m_dib->m_height = m_bmp.bmHeight;
	m_dib->m_width = m_bmp.bmWidth;

	//圖片顯示呼叫函式stretchBlt
	pDC->StretchBlt(x, y, m_bmp.bmWidth, m_bmp.bmHeight, &dcBmp, 0, 0, m_bmp.bmWidth, m_bmp.bmHeight, SRCCOPY);

	/*******************************************************************************/
	/* BOOL StretchBlt(int x,int y,int nWidth,int nHeight,CDC* pSrcDC,
	/*                 int xSrc,int ySrc,int nSrcWidth,int nSrcHeight,DWORD dwRop );
	/* 1.引數x、y點陣圖目標矩形左上角x、y的座標值
	/* 2.nWidth、nHeigth點陣圖目標矩形的邏輯寬度和高度
	/* 3.pSrcDC表示源裝置CDC指標
	/* 4.xSrc、ySrc表示點陣圖源矩形的左上角的x、y邏輯座標值
	/* 5.dwRop表示顯示點陣圖的光柵操作方式 SRCCOPY用於直接將點陣圖複製到目標環境中
	/*******************************************************************************/

	dcBmp.SelectObject(pbmpOld);           //恢復臨時DC的點陣圖
	DeleteObject(&m_bitmap);               //刪除記憶體中的點陣圖
	dcBmp.DeleteDC();                      //刪除CreateCompatibleDC得到的圖片DC
}

void CTest2View::OnZftYt()
{
	CTest2ZFTDlg dlg;
	//開啟臨時的圖片
	CFile fp(BmpName, CFile::modeRead | CFile::typeBinary);
	
	fp.Read(&bfh, sizeof(BITMAPFILEHEADER));
	fp.Read(&bih, sizeof(BITMAPINFOHEADER));
	int bytesPerLine = ((bih.biWidth * bih.biBitCount + 31) / 32) * 4;
	int real_size = bytesPerLine * bih.biHeight;
	
	int m_nImage = real_size;
	int i,j;
	for(j=0;j<256;j++) { //定義陣列並清零
		Red[j]=0;
		Green[j]=0;
		Blue[j]=0;
	}
	//計算4個資料
	unsigned char red,green,blue;
	int IntRed,IntGreen,IntBlue;                  //強制轉換
	int MaxRed = 0, MaxBlue = 0, MaxGreen = 0;
	int MinRed = 255, MinBlue = 255, MinGreen = 255;

	double sumRedHD=0,sumGreenHD=0,sumBlueHD=0;   //記錄影素總的灰度值和
	for(i=0; i<m_nImage/3; i++ ) 
	{
		//24位真彩影像中一個畫素:(R,G,B),分別讀取
		//讀取紅色畫素灰度值
		fp.Read(&red, sizeof(char));
		IntRed=int(red);
		//紅色最大最小灰度值確定
		if (IntRed >= MaxRed) {
			MaxRed = IntRed;
		}
		if (IntRed <= MinRed) {
			MinRed = IntRed;
		}
		//對畫素紅色灰度求和
		sumRedHD=sumRedHD+IntRed;
		//統計對應灰度值的個數
		if( IntRed>=0 && IntRed<256 ) Red[IntRed]++; //畫素0-255之間
		
		//之後的操作與紅色類似
		fp.Read(&green, sizeof(char));
		IntGreen=int(green);

		if (IntGreen >= MaxGreen) {
			MaxGreen = IntGreen;
		}
		if (IntGreen <= MinGreen) {
			MinGreen = IntGreen;
		}
		sumGreenHD=sumGreenHD+IntGreen;
		if( IntGreen>=0 && IntGreen<256 ) Green[IntGreen]++;
		
		fp.Read(&blue, sizeof(char));
		IntBlue=int(blue);

		if (IntBlue >= MaxBlue) {
			MaxBlue = IntBlue;
		}
		if (IntBlue <= MinBlue) {
			MinBlue = IntBlue;
		}

		sumBlueHD=sumBlueHD+IntBlue;
		if( IntBlue>=0 && IntBlue<256 ) Blue[IntBlue]++;
	}
	fp.Close();

	dlg.m_redMax.Format(_T("%d"), MaxRed);
	dlg.m_blueMax.Format(_T("%d"), MaxBlue);
	dlg.m_greenMax.Format(_T("%d"), MaxGreen);
	dlg.m_redMin.Format(_T("%d"), MinRed);
	dlg.m_blueMin.Format(_T("%d"), MinBlue);
	dlg.m_greenMin.Format(_T("%d"), MinGreen);
	/*******************************************************/
	/*		經過以上操作已經獲取了畫素的
	/*		全部資訊以及畫素灰度最大最小值
	/*		接下來獲取灰度值出現頻率最高的值
	/*		Red[]     Blue[]    Green[]
	/*		分別記錄了紅藍綠每種畫素灰度出現的次數
	/*		找到這裡的最大值即可
	/*******************************************************/
	int MostRed = 0, MostBlue = 0, MostGreen = 0;
	int MostRed_G = 0, MostBlue_G = 0, MostGreen_G = 0;
	for (j = 0;j < 256;j++) { 
		if (MostRed <= Red[j]) {
			MostRed = Red[j];
			MostRed_G = j;
		}
		if (MostBlue <= Blue[j]) {
			MostBlue = Blue[j];
			MostBlue_G = j;
		}
		if (MostGreen <= Green[j]) {
			MostGreen = Green[j];
			MostGreen_G = j;
		}
	}
	dlg.m_redMost.Format(_T("%d"), MostRed_G);
	dlg.m_blueMost.Format(_T("%d"), MostBlue_G);
	dlg.m_greenMost.Format(_T("%d"), MostGreen_G);
	dlg.m_redF.Format(_T("%d"), MostRed);
	dlg.m_blueF.Format(_T("%d"), MostBlue);
	dlg.m_greenF.Format(_T("%d"), MostGreen);
	//畫素:int型轉換為CString型 
	dlg.m_redXS.Format(_T("%d"),m_nImage);
	dlg.m_greenXS.Format(_T("%d"),m_nImage);
	dlg.m_blueXS.Format(_T("%d"),m_nImage);
	//平均灰度值:計算24位bmp圖片的灰度值,我是記錄RGB中的所有平均值	
	float pinRedHD,pinGreenHD,pinBlueHD; 
	pinRedHD=sumRedHD*3/m_nImage;
	pinGreenHD=sumGreenHD*3/m_nImage;     //平均灰度=總灰度/總畫素
	pinBlueHD=sumBlueHD*3/m_nImage;

	dlg.m_redPJHD.Format(_T("%.2f"),pinRedHD);
	dlg.m_greenPJHD.Format(_T("%.2f"),pinGreenHD);
	dlg.m_bluePJHD.Format(_T("%.2f"),pinBlueHD);
	/****************************************************************/
	/* 中值灰度:演算法重點(黃凱大神提供)                              
	/* 中值灰度:所有畫素中的中位數,應該所有畫素排序找到中間的灰度值 
	/* 演算法:num[256]記錄各灰度出現次數,sum+=num[i],找到sum=總畫素/2 
	/****************************************************************/
	int sumRedZZHD=0,sumGreenZZHD=0,sumBlueZZHD=0;
	int redZZHD,greenZZHD,blueZZHD;

	for(i=0;i<256;i++)
	{
		sumRedZZHD=sumRedZZHD+Red[i];
		if(sumRedZZHD>=m_nImage/6)          //m_nImage被分成3份RGB並且sum=總畫素/2
		{
			redZZHD=i;
			break;
		}
	}
	for(i=0;i<256;i++)
	{
		sumGreenZZHD=sumGreenZZHD+Green[i];
		if(sumGreenZZHD>=m_nImage/6)          //m_nImage被分成3份RGB並且sum=總畫素/2
		{
			greenZZHD=i;
			break;
		}
	}
	for(i=0;i<256;i++)
	{
		sumBlueZZHD=sumBlueZZHD+Blue[i];
		if(sumBlueZZHD>=m_nImage/6)          //m_nImage被分成3份RGB並且sum=總畫素/2
		{
			blueZZHD=i;
			break;
		}
	}
	
	dlg.m_redZZHD.Format(_T("%d"),redZZHD);
	dlg.m_greenZZHD.Format(_T("%d"),greenZZHD);
	dlg.m_blueZZHD.Format(_T("%d"),blueZZHD);
	
	/******************************************************************/
	/*標準差:標準差=方差的算術平方根                                   
	/*       方差s^2=[(x1-x)^2+(x2-x)^2+......(xn-x)^2]/n             
	/* 演算法:不用開m_nImage陣列進行計算 用num[256]中數進行             
	/* 方差=(平均灰度-i)*(平均灰度-i)*Red[i]  有Red[i]個灰度值為i的數 
	/******************************************************************/
	float redBZC,greenBZC,blueBZC;       //標準差
	double redFC=0,greenFC=0,blueFC=0;    //方差
	for(i=0;i<256;i++)
	{
		redFC=redFC+(pinRedHD-i)*(pinRedHD-i)*Red[i];   //有Red[i]個畫素i
		greenFC=greenFC+(pinGreenHD-i)*(pinGreenHD-i)*Green[i];
		blueFC=blueFC+(pinBlueHD-i)*(pinBlueHD-i)*Blue[i];
	}

	redBZC=sqrt(redFC*3/m_nImage);
	greenBZC=sqrt(greenFC*3/m_nImage);
	blueBZC=sqrt(blueFC*3/m_nImage);
	
	dlg.m_redBZC.Format(_T("%.2lf"),redBZC);
	dlg.m_greenBZC.Format(_T("%.2lf"),greenBZC);
	dlg.m_blueBZC.Format(_T("%.2lf"),blueBZC);	
 
	//重點必須新增該語句才能彈出對話方塊
	if(dlg.DoModal()==IDOK)
	{
 
	}
}


void CTest2View::OnJhh()
{
	//第一步:獲取影像的資料資訊
//此操作可以在開啟圖片時就進行 在直方圖取樣(ZFTCY)中也有該程式碼

	CFile fpo(BmpName,CFile::modeRead | CFile::typeBinary );

	fpo.Read(&bfh, sizeof(BITMAPFILEHEADER));
	fpo.Read(&bih, sizeof(BITMAPINFOHEADER));
	int i, j, k;
	for (j = 0;j < 256;j++) { //定義陣列並清零
		Red[j] = 0;
		Green[j] = 0;
		Blue[j] = 0;
	}
	//計算4個資料
	unsigned char red, green, blue;
	int IntRed, IntGreen, IntBlue; //強制轉換
	double sumRedHD = 0, sumGreenHD = 0, sumBlueHD = 0; //記錄影素總的灰度值和
	int bytesPerLine = ((bih.biWidth * bih.biBitCount + 31) / 32) * 4;
	int real_size = bytesPerLine * bih.biHeight;
	int m_nImage = real_size;

	for (i = 0; i < m_nImage / 3; i++)
	{
		fpo.Read(&red, sizeof(char));
		IntRed = int(red);
		sumRedHD = sumRedHD + IntRed;
		if (IntRed >= 0 && IntRed < 256) Red[IntRed]++;


		fpo.Read(&green, sizeof(char));
		IntGreen = int(green);
		sumGreenHD = sumGreenHD + IntGreen;
		if (IntGreen >= 0 && IntGreen < 256) Green[IntGreen]++;

		fpo.Read(&blue, sizeof(char));
		IntBlue = int(blue);
		sumBlueHD = sumBlueHD + IntBlue;
		if (IntBlue >= 0 && IntBlue < 256) Blue[IntBlue]++;

	}
	fpo.Close();
	/*****************************************************************/

	/* 影像均衡化處理
	/* 利用全域性變數 Red[256] Blue[256] Green[256]
	/* 第一步:用3個陣列Count..記錄0-255灰度出現的概率,即
	/* 概率=該灰度出現次數*3/總得畫素 (因為分成3部分RGB)
	/* 第二步:i從1開始,令s[i]=s[i]+s[i-1] 記錄新概率數
	/* 第三步:用一個陣列L記錄新的調色盤索引值,即
	/* L[i]=s[i]×(256-1)結果四捨五入2.8即為3
	/* 第四步:將老的索引值對應的概率合併,作為對應的新的索引值的概率
	/* 1.原來的索引值0,1都對應了新的索引值0,則灰度索引值為0的概率
	/* 為P0+P1=0.03
	/* 2.新的索引值3和7找不到老的索引值與之對應,所以令Q3和Q7為0
	/*****************************************************************/

	//記錄出現的概率,會加到1 用於相加到調色盤

	float CountRed[256], CountGreen[256], CountBlue[256];

	//記錄原始資料,不會相加到1 用於計算新灰度概率

	float CountRedLin[256], CountGreenLin[256], CountBlueLin[256];


	for (k = 0; k < 256; k++)		//p(Sk)

	{
		CountRed[k] = (float)(Red[k]) * 3 / m_nImage;
		CountRedLin[k] = CountRed[k];
		CountGreen[k] = (float)(Green[k]) * 3 / m_nImage;
		CountGreenLin[k] = CountGreen[k];
		CountBlue[k] = (float)(Blue[k]) * 3 / m_nImage;
		CountBlueLin[k] = CountBlue[k];
	}

	for (k = 1; k < 256; k++)		//tk
	{
		CountRed[k] = CountRed[k] + CountRed[k - 1];
		CountGreen[k] = CountGreen[k] + CountGreen[k - 1];
		CountBlue[k] = CountBlue[k] + CountBlue[k - 1];
	}


	/****************************************************/
	/* 此處一個四捨五入浮點型的演算法:
	/* float a=3.456; 保留到小數點後兩位
	/* float b=(int)((a * 100) + 0.5) / 100.0;
	/* output b=3.46
	/****************************************************/

	int LRed[256], LGreen[256], LBlue[256]; //記錄調色盤
	for (k = 0; k < 256; k++)
	{		
		//四捨五入演算法,求最近灰度級,記錄在LRed、LBlue、LGreen中,作為新影像的灰度級
		LRed[k] = (int)(CountRed[k] * (256 - 1) + 0.5);
		LGreen[k] = (int)(CountGreen[k] * (256 - 1) + 0.5);
		LBlue[k] = (int)(CountBlue[k] * (256 - 1) + 0.5);
	}


	//第三步:處理均衡化影像寫入 開啟臨時的圖片

	CString BmpNameJHH = BmpName.Left(BmpName.GetLength() - 4) + _T("JHH.bmp");
	MessageBox(L"檔名為:" + BmpNameJHH + L"\n原始檔名為:" + BmpName, L"(路徑提示)", MB_OK);
	MessageBox(L"處理中,請稍候", L"提示", MB_OK);

	fpo.Open(BmpName, CFile::modeRead | CFile::typeBinary);
	CFile fpw(BmpNameJHH, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite);
	fpo.Read(&bfh, sizeof(BITMAPFILEHEADER));
	fpw.Write(&bfh, sizeof(BITMAPFILEHEADER));

	//計算調色盤大小,如果不是24位彩圖,多讀入一個調色盤資料
	int panelsize = 0;
	int width, height, count;
	fpo.Read(&bih, sizeof(BITMAPINFOHEADER));
	fpw.Write(&bih, sizeof(BITMAPINFOHEADER));
	width = bih.biWidth;
	height = bih.biHeight;
	count = bih.biBitCount;
	debugMess.Format(_T("%d"), sizeof(RGBQUAD));
	
	if (count < 24) //非真彩色    
	{
		panelsize = pow((double)2, count);
	/*	debugMess.Format(_T("%d"), panelsize);
		MessageBox(L"panelsize是:"+debugMess, L"(提示)", MB_OK);*/

		debugMess.Format(_T("此圖為%d位點陣圖,不是24位真彩色影像"), panelsize);
		MessageBox(debugMess, L"提示", MB_OK);
	}
	bytesPerLine = ((width * count + 31) / 32) * 4;
	real_size = bytesPerLine * height;
	m_nImage = real_size;


	//m_nWidth*m_nHeight 讀取圖片最後一行不為m_nWidth時會報錯 改為m_nImage/3

	for (i = 0; i < m_nImage / 3; i++)
	{
		fpo.Read(&red, sizeof(char));
		fpo.Read(&green, sizeof(char));
		fpo.Read(&blue, sizeof(char));


		red = LRed[int(red)];
		green = LGreen[int(green)];
		blue = LBlue[int(blue)];

		fpw.Write(&red, sizeof(char));
		fpw.Write(&green, sizeof(char));
		fpw.Write(&blue, sizeof(char));

	}
	fpw.Close();
	fpo.Close();
	MessageBox(L"處理完畢,請在根目錄檢視", L"提示", MB_OK);

	Invalidate();

}


void CTest2View::OnGgh()
{

	// TODO: 在此新增命令處理程式程式碼
}


void CTest2View::OnEzh()
{
	/***********************************************/
	/*二值化是根據一個閾值,將灰度大於閾值設定為255,
	/*	小於閾值的設定為0,輸出二值化影像
	/*	這裡設定閾值為128,從中間分化
	/**********************************************/


	CString BmpNameEzh = BmpName.Left(BmpName.GetLength()-4) + _T("EZH.bmp");
	MessageBox(L"檔名為:"+BmpNameEzh+L"\n原始檔名為:"+BmpName ,L"(路徑提示)", MB_OK );
	MessageBox(L"處理中,請稍候", L"(提示)", MB_OK);

	CFile fpo(BmpName, CFile::modeRead | CFile::typeBinary);
	CFile fpw(BmpNameEzh, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite);


	fpo.Read(&bfh, sizeof(BITMAPFILEHEADER));
	fpo.Read(&bih, sizeof(BITMAPINFOHEADER));
	fpw.Write(&bfh, sizeof(BITMAPFILEHEADER));
	fpw.Write(&bih, sizeof(BITMAPINFOHEADER));

	int bytesPerLine = ((bih.biWidth * bih.biBitCount + 31) / 32) * 4;
	int real_size = bytesPerLine * bih.biHeight;
	int m_nImage = real_size;

	//處理
	unsigned char color;
	unsigned char red, green, blue;

	for (int i = 0; i < m_nImage / 3; i++)

	{
		fpo.Read(&red, sizeof(char));
		fpo.Read(&green, sizeof(char));
		fpo.Read(&blue, sizeof(char));

		if ((int)red > 128)
			red = 255;
		else
			red = 0;

		if ((int)green > 128)
			green = 255;
		else
			green = 0;

		if ((int)blue > 128)
			blue = 255;
		else
			blue = 0;

		fpw.Write(&red, sizeof(char));
		fpw.Write(&green, sizeof(char));
		fpw.Write(&blue, sizeof(char));
	}
	fpo.Close();
	fpw.Close();
	MessageBox(L"處理完畢,請在根目錄檢視", L"提示", MB_OK);

	Invalidate();

}

相關文章