图像处理之快速滤波

快速中值滤波

在中值滤波中,需要计算每一块小的直方图的中值,如果每次都算一个新的直方图就会很麻烦,但是像素点每右移一个单位,直方图实际上只改变了最左侧一列和最右侧一列,其余的数据可以继续使用,并且这个中值的改变也不会太大,用这种方法避免了重复访问和重复运算。
代码如下:

int calMidValue(int hist[], int midLocation)
{
    
    
	int sum = 0;
	for (int i = 0; i < 256; ++i)
	{
    
    
		sum += hist[i];
		if (sum >= midLocation)
			return i;
	}
	return 255;
}
void midFilt(BYTE *pImg, int width, int height,int windowLength)
{
    
    
	BYTE *pSrc=pImg;
	int hist[256];
	int edge = (windowLength - 1) >> 1;//未处理边界大小
	int windowSize = windowLength * windowLength;//矩形窗大小
	int midLocation = (windowSize >> 1) + 1;//中值的位置
	int realWidth = width - edge, realHeight = height - edge;//实际处理的宽高

	for (int i = edge; i < realWidth; i++)
		for (int j = edge; j < realHeight; j++) 
		{
    
    
			if (j == edge)
			{
    
    
				memset(hist, 0, 256 * sizeof(int));
				for(int h=i-edge;h<=i+edge;h++)
					for (int w = j - edge; w <= j + edge; w++) {
    
    
						BYTE value = pSrc[h*width + w];
						hist[value]++;
					}
			}
			else
			{
    
    
				int left = j - edge - 1, right = j + edge;
				for (int y = i - edge; y <= i + edge; y++)
				{
    
    
					int l = y * width + left, r = y * width + right;
					hist[pSrc[l]]--;
					hist[pSrc[r]]++;
				}
			}
			pSrc[i*width + j] = calMidValue(hist, midLocation);
		}
	return;
}

3*3模板滤波结果:
在这里插入图片描述在这里插入图片描述

快速均值滤波

快速均值滤波可以用类似于快速中值滤波的方法,移动边界时,仅仅关注改变的区域,减少了数据的访存
代码如下:

int calAverValue(int hist[],int windowSize)
{
    
    
	int sum = 0;
	for (int i = 0; i < 256; ++i)
	{
    
    
		sum += hist[i] * i;
	}
	return (sum / windowSize);
}
void averFilt1(BYTE *pImg, int width, int height, int windowLength)
{
    
    
	BYTE *pSrc = pImg;
	int hist[256];
	int edge = (windowLength - 1) >> 1;//未处理边界大小
	int windowSize = windowLength * windowLength;//矩形窗大小
	int realWidth = width - edge, realHeight = height - edge;//实际处理的宽高

	for (int i = edge; i < realWidth; i++)
		for (int j = edge; j < realHeight; j++)
		{
    
    
			if (j == edge)
			{
    
    
				memset(hist, 0, 256 * sizeof(int));
				for (int h = i - edge; h <= i + edge; h++)
					for (int w = j - edge; w <= j + edge; w++) {
    
    
						BYTE value = pSrc[h*width + w];
						hist[value]++;
					}
			}
			else
			{
    
    
				int left = j - edge - 1, right = j + edge;
				for (int y = i - edge; y <= i + edge; y++)
				{
    
    
					int l = y * width + left, r = y * width + right;
					hist[pSrc[l]]--;
					hist[pSrc[r]]++;
				}
			}
			pSrc[i*width + j] = calAverValue(hist, windowSize);
		}
}


快速积分图滤波

`
另一种方法就是基于积分图的算法,图像积分图指的是积分图上的点的值=所有该点及该点左上方的像素值之和,即s(x,y)=g(x,y)+s(x-1,y)+s(x,y-1)-s(x-1,y-1)用这个方法可以快速算出某区域的像素值之和,即sum=s(x,y)-s(x-m,y)-s(x,y-n)+s(x-m,y-n)再除以窗口大小,即为均值。
代码如下:

void averFilt2(BYTE *pImg, int width, int height, int windowLength,BYTE *pDst)
{
    
    
	int windowSize = windowLength * windowLength;
	int edge = (windowLength - 1) >> 2;
	int realWidth = width - edge, realHeight = height - edge;//实际处理的宽高
	for (int i = 0; i < width*height; i++)
	{
    
    
		pDst[i] = pImg[i];
	}
		for (int i = 0; i < height; i++)
			for (int j = 0; j < height; j++)
		
		{
    
    
				pDst[i*width + j] = pDst[i*width + j - 1] + pDst[(i - 1)*width + j] - pDst[(i - 1)*width + j - 1] + pImg[i*width + j];
		}
	
		for (int i = 0; i < realWidth; i++)
			for (int j = 0; j < realHeight; j++)
			{
    
    
				pDst[i*width + j] = (pDst[(i + edge)*width + j + edge] - pDst[(i - edge)*width + j + edge] - pDst[(i + edge)*width + j - edge] + pDst[(i - edge)*width + j - edge]) / windowSize;
			}
	return;
}

滤波结果:

在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_36587495/article/details/108164741
今日推荐