个人实验代码记录 | 数字图像处理实验3·图像直方图与均衡化处理

个人实验记录 | 数字图像处理实验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();

}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值