高性能计算-openmp-图像卷积滤波算法(12)

1. 目标:使用openmp实现图像滤波算法

给定一个输入图像,你的任务是将其划分为多个块,并使用多个进程对每个块进行滤波操作。
要求:
1、使用分段并行结构和指令section来并行执行不同的计算步骤。
2、使用单线程指令single或master确保某些代码段只在单个线程中执行。
3、使用线程同步和阻塞机制来确保所有线程在进入下一步处理之前完成当前步骤的计算。
4、使用任务池并行化来处理滤波操作,并根据图像块的大小和数量选择静态任务或动态任务。

2. 思路

思路:

(1). 根据结果目标元素位置,判断出要计算的原始图像数据和卷积核的位置边界

(2). 输出图像每个元素的计算当做一个任务

(3). 如果对数据分块的处理:

(a) 每个分块需要根据卷积核大小增加冗余数据空间,决定不采用分块模式。
(b) 遍历分块分配任务仍需要放在single单线程内处理
(c) 分块处理增加了代码复杂性,并无其他优点。决定不采用分快处理

3. 代码

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>

#define N 5   //输入图像方阵列维度
#define FN 3    //卷积核方阵列维度

void print_matrixS(unsigned char* matrix, int rows, int cols)
{
	printf("matrix:\n");
	for (size_t i = 0; i < rows; i++)
	{
		for (size_t j = 0; j < cols; j++)
			printf("%d\t",matrix[i*cols+j]);
		printf("\n");
	}
}

void main()
{
    unsigned char inPic[N][N] = {0};    //输入图像
    unsigned char outPic[N][N] = {0};   //输出图像
    unsigned char conv[FN][FN] = {0};   //卷积核
    double startTime,endTime;             //计算的起始终止时间
    //输入图像初始化
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
            inPic[i][j] = rand()%256;
    }
    //初始化卷积核,中值滤波初始化为1
    for(int i=0;i<FN;i++)
    {
        for(int j=0;j<FN;j++)
            conv[i][j] = 1;
    }
    omp_set_num_threads(10);
    startTime = omp_get_wtime();
    //计算  
    #pragma omp parallel proc_bind(close)
    {
        //在单线程内分配任务
        #pragma omp single
        {
            // #pragma omp for collapse(2) schedule(guided) 
            for(int i=0;i<N;i++)
            {
                for(int j=0;j<N;j++)
                {
                    //将每个输出图像数据的计算都作为一个task
                    #pragma omp task shared(conv)
                    {
                        //确定计算结果每个元素卷积要参与的输入图像的数据位置边界
                        int up,down,left,right;
                        int half = FN/2;    //卷积核一半向下取整
                        left = (j - half)>=0 ? j-half : 0;
                        right = (j+half)<=N-1 ? j+half : N-1;
                        up = (i - half)>=0 ? i-half : 0;
                        down = (i+half)<=N-1 ? i+half : N-1;
                        int rNums,cNums;    //参与计算的行列数
                        rNums = down - up +1;
                        cNums = right - left +1;
                        //需要确定卷积核参与计算的边界,只需要左上角坐标
                        int rBegin,cBegin;
                        rBegin = FN/2-(i-up);
                        cBegin = FN/2-(j-left);
                        // 计算: 均值滤波,采用先求和再平均,减少乘法次数和误差
                        int sum=0;
                        int weightSum = 0;
                        for(int r=up;r<=down;r++,rBegin++)
                        {
                            for(int c=left,cTempBegin=cBegin;c<=right;c++,cTempBegin++)
                            {
                                    sum += inPic[r][c] * conv[rBegin][cTempBegin];
                                    weightSum += conv[rBegin][cTempBegin];
                            }     
                        }
                        double e = 1.0/(double)weightSum;
                        outPic[i][j] = (short)(sum*e);
                    }   
                }
            }
        }
    }
    #pragma omp taskwait
    endTime = omp_get_wtime();
    printf("inPicSize %d useSec %f\n",N,(double)(endTime-startTime));
    print_matrixS((unsigned char*)inPic,N,N);
    print_matrixS((unsigned char*)outPic,N,N);
    // print_matrixF((float*)conv,FN,FN);
}
posted @ 2024-11-23 10:24  安洛8  阅读(87)  评论(0)    收藏  举报