高级程序语言课程设计&&MFC&&opencv&&并行计算openmp

又到一学期期末课程设计周
计科小学生又来发布课程设计

本次是高级程序设计
用MFC构建界面,调用opencv动态链接库,再加上openmp实现并行计算。
看起来高大上很多。

提示
如果要使用openmp要在配置中打开
在这里插入图片描述

业务流程大致如此:
在这里插入图片描述
高斯滤波:
在这里插入图片描述
伪色彩增强:
在这里插入图片描述
在进行线性增强和灰度处理时可以选择多线程处理来缩减响应时间
,分别以2线程和8线程展示:

在这里插入图片描述
在这里插入图片描述
代码部分细节:

点击打开图片按钮响应对应的代码细节展示:
点击“确定”按钮后获取文件路径到strPathName,并将文件路径显示到编辑框

if (dlg.DoModal() == IDOK) 
	{
		strPathName = dlg.GetPathName();
		m_file.SetWindowText(strPathName); 
	}

使用StretchDIBits函数显示图片

StretchDIBits(GetDlgItem(IDC_STATIC)->GetDC()->GetSafeHdc()
			, 0, 0, std::min(rect.Width(), rect.Height()), std::min(rect.Width(), rect.Height())
			, 0, 0, cvImgTmp.cols, cvImgTmp.rows,
			cvImgTmp.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);

声明图片大小

        bmiHeader = &bitmapInfo.bmiHeader;
		bmiHeader->biSize = sizeof(BITMAPINFOHEADER);
		bmiHeader->biWidth = cvImgTmp.cols;
		bmiHeader->biHeight = -cvImgTmp.rows;
		bmiHeader->biPlanes = 1;
		bmiHeader->biBitCount = 24;
		bmiHeader->biCompression = BI_RGB;
		bitmapInfo.bmiHeader.biSizeImage = 0;
		bmiHeader->biXPelsPerMeter = GetSystemMetrics(SM_CXSCREEN);
		bmiHeader->biYPelsPerMeter = GetSystemMetrics(SM_CYSCREEN);
		bmiHeader->biClrUsed = 0;
		bmiHeader->biClrImportant = 0;

使用IsIconic函数来判断当前界面是否已经有图像打开
若没有则按照路径打开图片,若已存在图片
使用CPaintDC函数对当前图层关闭,然后再显示选中图片

if (IsIconic())//IsIconic()作用是判断窗口是否处于最小化状态(点击了最小化按钮之后
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);//窗口调用窗口程序

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);//窗体显示区域的宽度和高度、滚动条的宽度和高度
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);//GetClientRect用于取得指定窗口的客户区域大小
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}

对图片进行高斯滤波处理

if (str == "")
	{
		AfxMessageBox(_T("请先打开图片!"));
		return;
	}
	Mat image = imread(str, 1);
	Mat out;
	//进行滤波操作
	GaussianBlur(image, out, Size(9, 9), 10, 0);//X方向上的高斯核标准偏差;
	imwrite("高斯滤波.jpg", image);
	waitKey();

点击伪色彩增强

if (str == "")
	{
		AfxMessageBox(_T("请先打开图片!"));
		return;
	}


	Mat im_gray = imread(str, 1);
	Mat im_color;
	applyColorMap(im_gray, im_color, COLORMAP_JET);
	imwrite("伪彩色增强.jpg", im_color);
	waitKey(0);

对图像进行腐蚀操作

if (str == "")
	{
		AfxMessageBox(_T("请先打开图片!"));
		return;
	}
	Mat src = imread(str, 1);
	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
	Mat dsImage;
	erode(src, dsImage, element);
	imwrite("腐蚀操作.jpg", dsImage);
	waitKey(0);

对图片进行线性增强
分别使用三个通道存储之前的图像RGB色彩信息,然后使用saturate_cast函数对图片进行线性处理,如果图片位灰度图片则只使用一个变量来存储色阶信息。

if (str == "")
	{
		AfxMessageBox(_T("请先打开图片!"));
		return;
	}
	Mat src1, dst;
	src1 = imread(str,1);
	double alpha = 1.2, beta = 50;
	dst = Mat::zeros(src1.size(), src1.type());
	Mat src2 = src1, dst1 = dst;
	float begintime = omp_get_wtime();
	for (int row = 0; row < src1.rows; row++)
	{
		for (int col = 0; col < src1.cols; col++)
		{
			if (src1.channels() == 3)
			{
				int b = src1.at<Vec3b>(row, col)[0];
				int g = src1.at<Vec3b>(row, col)[1];
				int r = src1.at<Vec3b>(row, col)[2];

				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);
				dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g*alpha + beta);
				dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r*alpha + beta);
			}
			else if (src1.channels() == 1)
			{
				float v = src1.at<uchar>(row, col);
				dst.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);
			}
		}
	}
	float endtime = omp_get_wtime();
	float before = endtime - begintime;

使用多线程加速处理。
使用omp parallel for num_threads(n)语句来进行多线程加速,n为输入的线程数,最后减去初始的时间得到多线程加速后节约的时间。

begintime = omp_get_wtime();
#pragma omp parallel for num_threads(n)
	for (int row = 0; row < src2.rows; row++)
	{
		for (int col = 0; col < src2.cols; col++)
		{
			if (src2.channels() == 3)
			{
				int b = src2.at<Vec3b>(row, col)[0];
				int g = src2.at<Vec3b>(row, col)[1];
				int r = src2.at<Vec3b>(row, col)[2];

				dst1.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);
				dst1.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g*alpha + beta);
				dst1.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r*alpha + beta);
			}
			else if (src2.channels() == 1)
			{
				float v = src2.at<uchar>(row, col);
				dst1.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);
			}
		}
	}
	endtime = omp_get_wtime();
	float after = endtime - begintime;
	float gap = before - after;

对图片进行灰度处理
使用max函数将图像原本的rgb信息压缩成一个通道

dst.create(src.size(), src.type());
	Mat src1 = src, dst1 = dst;
	float begintime = omp_get_wtime();
	for (int row = 0; row < src.rows; row++)

	{
		for (int col = 0; col < src.cols; col++)

		{

			int b = src.at<Vec3b>(row, col)[0];

			int g = src.at<Vec3b>(row, col)[1];

			int r = src.at<Vec3b>(row, col)[2];

			dst.at<Vec3b>(row, col)[0] = max(r, max(g, b));

			dst.at<Vec3b>(row, col)[1] = max(r, max(g, b));

			dst.at<Vec3b>(row, col)[2] = max(r, max(g, b));
		}
	}
	float endtime = omp_get_wtime();
	float before = endtime - begintime;

使用omp parallel for num_threads(n)进行多线程加速处理

	begintime = omp_get_wtime();
#pragma omp parallel for num_threads(n)
	for (int row = 0; row < src1.rows; row++)

	{
		for (int col = 0; col < src1.cols; col++)

		{

			int b = src1.at<Vec3b>(row, col)[0];

			int g = src1.at<Vec3b>(row, col)[1];

			int r = src1.at<Vec3b>(row, col)[2];

			dst1.at<Vec3b>(row, col)[0] = max(r, max(g, b));

			dst1.at<Vec3b>(row, col)[1] = max(r, max(g, b));

			dst1.at<Vec3b>(row, col)[2] = max(r, max(g, b));
		}
	}
	endtime = omp_get_wtime();
	float after = endtime - begintime;
	float gap = before - after;
	

以上就是整体框架了

1. 设计目的、意义(功能描述) 蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是二十世纪四十年代中期由于科学技术的发展和电子计算机的发明,而被提出的一种以概率统计理论为指导的一类非常重要的数值计算方法。本次大作业主要是对蒙特·卡罗方法进行并行处理,通过OpenMP、MPI、.NET、Java、Win32API等一系列并行技术和并行机制对该算法进行并行处理,从而也进一步熟悉了蒙特·卡罗方法的串行算法和并行算法,实现了用蒙特·卡罗方法计算出半径为1单位的球体的体积,体会到了并行技术在实际生活中的应用。 2. 方案分析(解决方案) 蒙特·卡罗方法(Monte Carlo method)是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。球的体积可以估算为:位于点模型内随机点个数与全体随机点个数的比值乘以包围盒的体积算的。 3. 设计分析 3.1 串行算法设计 假定球体用B表示,半径r=1单位,B1是包含B的参考立方体(在本例中是边长为2的正方体),在B1中产生N个均匀分布的伪随机点。对每个随机点检测其是否在B内,假设位于B内的随机点个数为N(in)(<=N),应用蒙特卡洛算法,则B的体积为 V=V1(N(in)/N) 其中V1是B1的体积。如果产生足够多的随机点,理论上可以获得任意逼近精度。 算法描述如下: BEGIN N=_MAX; FOR I=0;I<_MAX;I++ X=RANDOM(); Y=RANDOM(); Z=RANDOM(); IF (X*X+Y*Y+Z*Z)<=1 COUNT++; END IF; END FOR; BULK=V1*(COUNT/_MAX); END; 本算法主要是在参考立方体的选取上和定义的_MAX的值对结果影响较大,所以应该选择合适的数。 3.2 并行算法设计 对FOR循环进行划分使用两个处理器完成计算。例如对一个长为n的序列,首先划分得到两个长为n/2的序列,将其交给两个处理器分别处理;而后进一步划分得到四个长为n/4的序列,再分别交给四个处理器处理;如此递归下去最终得到结果。当然这是理想的划分情况,如果划分步骤不能达到平均分配的目的,那么结果的效率会相对较差。 伪代码如下: BEGIN N=_MAX; FOR1 I=0;I<_MAX/2;I++ X1=RANDOM(); Y1=RANDOM(); Z1=RANDOM(); IF (X1*X1+Y1*Y1+Z1*Z1)<=1 COUNT1++; END IF; END FOR1; FOR2 I=_MAX/2+1;I<_MAX;I++ X2=RANDOM(); Y2=RANDOM(); Z2=RANDOM(); IF (X2*X2+Y2*Y2+Z2*Z2)<=1 COUNT2++; END IF; END FOR2; BULK=V1*((COUNT1+ COUNT2)/_MAX); END; 3.3 理论加速比分析 实验中大量数据所产生的加速比比小量数据所产生的加速比要体现得更明显,并且数据生成的并行加速比随着处理器核的增加而增加。设处理器个数为p,数据量为n,由于正常情况下该快速排序算法的复杂度为O(nlogn),并行处理的时间复杂度为O(klogk),其中k=n/p,所以并行算法的时间复杂度为O((n/p)log(n/p)),理论加速比为nlogn/((n/p)log(n/p))=p+logp. 4. 功能模块实现与最终结果分析 4.1 基于OpenMP的并行算法实现 4.1.1 主要功能模块与实现方法 利用了OpenMP里面的#omp parallel sections将对两个for循环用两个线程并行化执行,以多线程方式并行运行程序,并行的算法步骤如下: (1)初始化_max = 10000000; (2)创建两个线程; (3)由OpenMP编译指导语句控制产生并行执行代码区段; (4)将数据存放到tianqing_count; (5)各线程调用算法得出结果; 并行算法的部分代码如下: #pragma omp parallel for private(tianqing_x,tianqing_y,tianqing_z) reduction(+:tianqing_count2) for (tianqing_i = 0; tianqing_i<tianqing_max; tianqing_i++) { tianqing_x = rand(); tianqing_x = tianqing_x / 32767; tianqing_y = rand(); tianqing_y = tianqing_y / 32767; tianqing_z = rand(); tianqing_z = tianqing_z / 32767; if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) work1.pSumto(b, 0, MAXN - 1)); Thread newthread1 = new Thread(thread1); 创建Work类的对象work2; ThreadStart thread2 = new ThreadStart(() => work2.pSumto(c, 0, MAXN - 1)); Thread newthread2 = new Thread(thread2); stopwatch.Start(); 启动线程1和线程2; 等待进程结束; stopwatch.Stop(); 得到结果; 4.5.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.6~2.7左右。 4.6 并行计算技术在实际系统中的应用 4.6.1 主要功能模块与实现方法 该飞机订票系统主要实现了对机票的一些基本信息进行存储和管理的功能。在系统中实现了对机票信息的增删改查,考虑到查询的方便性,对机票按照航班号进行排序,而此排序方法用并行快速排序运用进来。利用OpenMP的并行技术,对机票信息按顺序排列好,并分析了实验过程中的加速比。 4.6.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:当数据量比较大时,加速比理论在1.9左右。数据量较大时体现出来的加速比更准确。由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.2~2.4左右。 5. 设计体会 虽然没有按时完成作业,但这份报告花了我好几天的时间,从开始的搭建并行计算平台到最后的程序运行成功可以说是对我的一个锻炼。每一次的遇到问题与每一次的解决问题都是一个成长。每一次遇到问题和解决问题都是一种锻炼,一种尝试,从我们上并行计算课我懂得了很多电脑硬件和软件的知识,这些可能对于我们这个专业以后都是没有机会接触的,所以我觉得选择了并行计算与多核多线程技术这门课是非常正确的。对OpenMP、MPI、WIN32API、Java、.NET的并行技术有了一定的了解。在搭建MPI并行程序这块,学习的知识尤为增加,这些都是在不断的摸索、学习中学会的。 这次的大作业虽然是对以前实验的整合,但它加深了我对并行计算的印象,也使我对并行计算知识的理解更加深刻,也使我认识到了自己很多不足之处。学习并行计算的历程不会因为完成本次大作业而停止,我们是为了用知识武装大脑而学习,通过学习充实自己的生活,要努力学习,争取以后能够完成规模更大的程序。
1. 设计目的、意义(功能描述) 蒙特·卡罗方法(Monte Carlo method),也称统计模拟方法,是二十世纪四十年代中期由于科学技术的发展和电子计算机的发明,而被提出的一种以概率统计理论为指导的一类非常重要的数值计算方法。本次大作业主要是对蒙特·卡罗方法进行并行处理,通过OpenMP、MPI、.NET、Java、Win32API等一系列并行技术和并行机制对该算法进行并行处理,从而也进一步熟悉了蒙特·卡罗方法的串行算法和并行算法,实现了用蒙特·卡罗方法计算出半径为1单位的球体的体积,体会到了并行技术在实际生活中的应用。 2. 方案分析(解决方案) 蒙特·卡罗方法(Monte Carlo method)是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。球的体积可以估算为:位于点模型内随机点个数与全体随机点个数的比值乘以包围盒的体积算的。 3. 设计分析 3.1 串行算法设计 假定球体用B表示,半径r=1单位,B1是包含B的参考立方体(在本例中是边长为2的正方体),在B1中产生N个均匀分布的伪随机点。对每个随机点检测其是否在B内,假设位于B内的随机点个数为N(in)(<=N),应用蒙特卡洛算法,则B的体积为 V=V1(N(in)/N) 其中V1是B1的体积。如果产生足够多的随机点,理论上可以获得任意逼近精度。 算法描述如下: BEGIN N=_MAX; FOR I=0;I<_MAX;I++ X=RANDOM(); Y=RANDOM(); Z=RANDOM(); IF (X*X+Y*Y+Z*Z)<=1 COUNT++; END IF; END FOR; BULK=V1*(COUNT/_MAX); END; 本算法主要是在参考立方体的选取上和定义的_MAX的值对结果影响较大,所以应该选择合适的数。 3.2 并行算法设计 对FOR循环进行划分使用两个处理器完成计算。例如对一个长为n的序列,首先划分得到两个长为n/2的序列,将其交给两个处理器分别处理;而后进一步划分得到四个长为n/4的序列,再分别交给四个处理器处理;如此递归下去最终得到结果。当然这是理想的划分情况,如果划分步骤不能达到平均分配的目的,那么结果的效率会相对较差。 伪代码如下: BEGIN N=_MAX; FOR1 I=0;I<_MAX/2;I++ X1=RANDOM(); Y1=RANDOM(); Z1=RANDOM(); IF (X1*X1+Y1*Y1+Z1*Z1)<=1 COUNT1++; END IF; END FOR1; FOR2 I=_MAX/2+1;I<_MAX;I++ X2=RANDOM(); Y2=RANDOM(); Z2=RANDOM(); IF (X2*X2+Y2*Y2+Z2*Z2)<=1 COUNT2++; END IF; END FOR2; BULK=V1*((COUNT1+ COUNT2)/_MAX); END; 3.3 理论加速比分析 实验中大量数据所产生的加速比比小量数据所产生的加速比要体现得更明显,并且数据生成的并行加速比随着处理器核的增加而增加。设处理器个数为p,数据量为n,由于正常情况下该快速排序算法的复杂度为O(nlogn),并行处理的时间复杂度为O(klogk),其中k=n/p,所以并行算法的时间复杂度为O((n/p)log(n/p)),理论加速比为nlogn/((n/p)log(n/p))=p+logp. 4. 功能模块实现与最终结果分析 4.1 基于OpenMP的并行算法实现 4.1.1 主要功能模块与实现方法 利用了OpenMP里面的#omp parallel sections将对两个for循环用两个线程并行化执行,以多线程方式并行运行程序,并行的算法步骤如下: (1)初始化_max = 10000000; (2)创建两个线程; (3)由OpenMP编译指导语句控制产生并行执行代码区段; (4)将数据存放到tianqing_count; (5)各线程调用算法得出结果; 并行算法的部分代码如下: #pragma omp parallel for private(tianqing_x,tianqing_y,tianqing_z) reduction(+:tianqing_count2) for (tianqing_i = 0; tianqing_i<tianqing_max; tianqing_i++) { tianqing_x = rand(); tianqing_x = tianqing_x / 32767; tianqing_y = rand(); tianqing_y = tianqing_y / 32767; tianqing_z = rand(); tianqing_z = tianqing_z / 32767; if ((tianqing_x*tianqing_x + tianqing_y*tianqing_y + tianqing_z*tianqing_z) work1.pSumto(b, 0, MAXN - 1)); Thread newthread1 = new Thread(thread1); 创建Work类的对象work2; ThreadStart thread2 = new ThreadStart(() => work2.pSumto(c, 0, MAXN - 1)); Thread newthread2 = new Thread(thread2); stopwatch.Start(); 启动线程1和线程2; 等待进程结束; stopwatch.Stop(); 得到结果; 4.5.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.6~2.7左右。 4.6 并行计算技术在实际系统中的应用 4.6.1 主要功能模块与实现方法 该飞机订票系统主要实现了对机票的一些基本信息进行存储和管理的功能。在系统中实现了对机票信息的增删改查,考虑到查询的方便性,对机票按照航班号进行排序,而此排序方法用并行快速排序运用进来。利用OpenMP的并行技术,对机票信息按顺序排列好,并分析了实验过程中的加速比。 4.6.2 实验加速比分析 实验中创建了两个线程,通过多次测试,得出实验结果:当数据量比较大时,加速比理论在1.9左右。数据量较大时体现出来的加速比更准确。由上面的理论加速比分析可知,当线程数为2时,理论加速比为2+log2=3.但由于实际操作中硬件设备以及内存分配的影响,实验加速比达不到理论值3.实验加速比在2.2~2.4左右。 5. 设计体会 虽然没有按时完成作业,但这份报告花了我好几天的时间,从开始的搭建并行计算平台到最后的程序运行成功可以说是对我的一个锻炼。每一次的遇到问题与每一次的解决问题都是一个成长。每一次遇到问题和解决问题都是一种锻炼,一种尝试,从我们上并行计算课我懂得了很多电脑硬件和软件的知识,这些可能对于我们这个专业以后都是没有机会接触的,所以我觉得选择了并行计算与多核多线程技术这门课是非常正确的。对OpenMP、MPI、WIN32API、Java、.NET的并行技术有了一定的了解。在搭建MPI并行程序这块,学习的知识尤为增加,这些都是在不断的摸索、学习中学会的。 这次的大作业虽然是对以前实验的整合,但它加深了我对并行计算的印象,也使我对并行计算知识的理解更加深刻,也使我认识到了自己很多不足之处。学习并行计算的历程不会因为完成本次大作业而停止,我们是为了用知识武装大脑而学习,通过学习充实自己的生活,要努力学习,争取以后能够完成规模更大的程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值