空间域滤波器(1)
来源:互联网 发布:简单手机平面图软件 编辑:程序博客网 时间:2024/05/24 15:38
Spatial Filtering
(newsuppy
1平滑线性滤波器(或称均值滤波器)
使用一个m*n
2中值滤波器
同样使用一个m*n
3处理细节
掩模在图像边缘时,会遇到覆盖了非图像部分的情况,这里可以有多种方式处理,比较常见的有部分滤波和补零法
4 图示处理过程(程序实现过程
(1)获取一个准备滤波的原始图像,大小为Width*Height;准备一个m*n大小的滤波器掩模
要求m,n必须为大于1的奇数,如果是偶数,自动加1改为奇数
(2)复制原图像并使用补零法(zero-padding)在复制后的图像边缘补零,宽度两边补上(m-1)/2个像素,高度两边补上(n-1)/2个像素,
则复制后的图像尺寸变为(Width+m-1)*(Height+n-1)。这一步不在原图像上直接补零是因为,图像处理时取各个像素的邻域的原
始值,所以前一个像素处理后,要保留其原始值为下一个像素的处理所用。
(3)将掩模覆盖在复制图像上,依次处理各个像素(非补零像素)。
(a)对于均值滤波器,将掩模覆盖下的像素值分别与其对应的掩模的权值相乘,最后将这些乘积的和除以掩模的权值和所得既为
响应,赋给当前处理像素。遇到特殊的全1权值掩模,为方便计算只需将掩模覆盖下的像素值求和除以m*n,即为响应。
(b)对于中值滤波器,将掩模覆盖下的像素值取出成为一有m*n个元素的序列,排序后取中值,即为响应,赋给当前处理像素。
(4)完成处理,删除复制后图像。
5
程序使用
代码如下
// Author: newsuppy
// E-mail: newsuppy@msn.com
// Date: Nov. 1, 2004
// Version: v0.1.0 (it include in newsuppy's image process toolkit)
// Declaration: You can copy&rewirte the code yourself, but please put me in your acknowledgments
#ifndef SPATIALFILTER_H
#define SPATIALFILTER_H
#include <vector>
#include <numeric>
#include <algorithm>
#include <gdiplus.h>
namespace nsimgtk
{
// function: filter a width*height rectangle portion of a bitmap one pixel by one pixel with the filterMask
// template parameter:
// pixelType: pixel's type depend on pixelFormat
// pixelFormat: pixel's format, but this function doesn't support all the PixelFormat define in Gdiplus
// | supported PixelFormat | pixel type |
// 1, PixelFormat8bppIndexed ----------------------- unsigned char(8bit)
// 2, PixelFormat16bppARGB1555 ---------------- unsigned short int(16bit)
// 3, PixelFormat16bppGrayScale ---------------- unsigned short int(16bit)
// 4, PixelFormat16bppRGB555 ---------------- unsigned short int(16bit)
// 5, PixelFormat16bppRGB565 ---------------- unsigned short int(16bit)
// 6, PixelFormat32bppARGB ----------------- unsigned int(32bit)
// 6, PixelFormat32bppPARGB ----------------- unsigned int(32bit)
// 6, PixelFormat32bppRGB ----------------- unsigned int(32bit)
// FilterMask: FilterMask is a functor, it should inherit class "__filterMask"
// and it must support member function "response" like this:
// pixelType::FilterMask response();
// function parameter:
// p_bitmap: a pointer to Gdiplus::Bitmap class
// filterMask: the filterMask's instance
// x, y, width, height: they are the parameters of the rectangle which should be process
// (x,y) are the left-up point of the rectangle
// return value: if failed,return false; else if success, return true;
template <typename pixelType, Gdiplus::PixelFormat pixelFormat, class FilterMask>
bool SpatialFilterAlgo(Gdiplus::Bitmap* const p_bitmap, FilterMask filterMask, unsigned int x, unsigned int y,
unsigned int width, unsigned int height)
{
if (p_bitmap == NULL)
{
return false;
}
if ((width + x > p_bitmap->GetWidth()) || (height + y >p_bitmap->GetHeight()))
{
return false;
}
Gdiplus::BitmapData bitmapData;
Gdiplus::Rect rect(x, y, width,height);
if (p_bitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite, pixelFormat, &bitmapData) != Gdiplus::Ok)
{
return false;
}
pixelType *pixels = (pixelType*)bitmapData.Scan0;
const unsigned int m = filterMask.d_m; // mask's width
const unsigned int n = filterMask.d_n; // mask's height
std::vector<pixelType> tmpImage((m-1+width)*(n-1+height)); // extend image to use zero-padding
// copy original bitmap to extended image with zero-padding method
for (unsigned int row=0; row<height; ++row)
{
for (unsigned int col=0; col<width; ++col)
{
tmpImage[(col+m/2)+(row+n/2)*(bitmapData.Stride/sizeof(pixelType)+m-1)] =
pixels[col+row*bitmapData.Stride/sizeof(pixelType)];
}
}
// process every pixel with filterMask
for (unsigned int row=0; row<height; ++row)
{
for (unsigned int col=0; col<width; ++col)
{
// fill the "m*n" mask with the current pixel's neighborhood
for (unsigned int i=0; i<n; ++i)
{
for (unsigned int j=0; j<m; ++j)
{
filterMask.d_mask[i*m+j] = tmpImage[(col+j)+(row+i)*(bitmapData.Stride/sizeof(pixelType)+m-1)];
}
}
// replace the current pixel with filter mask's response
pixels[col+row*bitmapData.Stride/sizeof(pixelType)] = filterMask.response();
}
}
if (p_bitmap->UnlockBits(&bitmapData) != Gdiplus::Ok)
{
return false;
}
return true;
}
// base class for filterMask, be only used for the library
// others filterMask should inherit it
template <typename pixelType>
struct __filterMask
{
const unsigned int d_m;
const unsigned int d_n;
std::vector<pixelType> d_mask;
// filter mask's width and heigh must be a odd, if not, it will plus one for the width or the height
__filterMask(unsigned int m, unsigned int n)
: d_m(m%2 ? m:m+1), d_n(n%2 ? n:n+1), d_mask(d_m*d_n)
{
}
};
// special averaging(smoothing) filter mask, its' weights are all 1
template <typename pixelType>
class averagingFilterMaskSp
: public __filterMask<pixelType>
{
public:
averagingFilterMaskSp(unsigned int m, unsigned int n)
: __filterMask<pixelType>(m, n)
{ }
pixelType response()
{
return std::accumulate(d_mask.begin(), d_mask.end(), 0) / (d_m * d_n);
}
};
// averaging(smoothing) filter mask
template <typename pixelType>
class averagingFilterMask
: public __filterMask<pixelType>
{
private:
std::vector<pixelType> d_weight; // weights' vector(m*n)
int d_weight_sum; // all weights' sum
public:
averagingFilterMask(unsigned int m, unsigned int n, const std::vector<pixelType>& weightVec)
: __filterMask<pixelType>(m, n), d_weight(weightVec)
{
if (weightVec.size() != d_mask.size())
{
// if weight's size isn't equal to mask's size, it will change filter mask as a special filter mask
d_weight.resize(d_mask.size(), 1);
}
d_weight_sum = std::accumulate(d_weight.begin(), d_weight.end(), 0);
}
pixelType response()
{
return std::inner_product(d_mask.begin(), d_mask.end(), d_weight.begin(), 0) / d_weight_sum;
}
};
// median filter mask
template <typename pixelType>
class medianFilterMask
: public __filterMask<pixelType>
{
public:
medianFilterMask(unsigned int m, unsigned int n)
: __filterMask<pixelType>(m, n)
{ }
pixelType response()
{
std::sort(d_mask.begin(), d_mask.end());
return d_mask[d_mask.size()/2];
}
};
}
#endif
// 创建一个Bitmap类实例
Bitmap bitmapWith3x3MaskSp(L"image/Fig3.35(a).jpg");
// 创建一个3x3均值滤波器
// 注意对于averagingFilterMask类,其构造函数必须为其第三参数传入一个std::vector作为掩模权值,大小和掩模大小相同。
// 如: std::vector<unsigned char> weight(9);
// weight[0] = 1, weight[1] = 2, weight[2] = 1,
// weight[0] = 2, weight[1] = 4, weight[2] = 2,
// weight[0] = 1, weight[1] = 2, weight[2] = 1;
// averagingFilterMask<unsigned char> avgfilterMask3x3(3,3,weight);
averagingFilterMaskSp<unsigned char> avgfilterMaskSp3x3(3,3);
// 使用SpatialFilterAlgo算法,第一参数为上述Bitmap类实例,由于该图像为8阶灰度图,模版参数的第一为unsigned char,一般为8位
// 第三模版参数为PixelFormat8bppIndexed(参考GDI+文档),函数第二参数为滤波器掩模对象,其余参数分别为图像起始点坐标及宽度和高度
SpatialFilterAlgo<unsigned char,PixelFormat8bppIndexed>(&bitmapWith3x3MaskSp,
avgfilterMaskSp3x3, 0, 0, bitmapWith3x3MaskSp.GetWidth(), bitmapWith3x3MaskSp.GetHeight())==false)
6
中值滤波器的作用主要在于消除椒盐噪声,所谓椒盐噪声就是图像中分布广泛的黑白点,通过取邻域内的中值,有效地将灰度的极大极小值消去。另外不宜取太大的掩模,这样会在滤去椒盐噪声的同时使得图像细节被模糊化。
7
- 空间域滤波器(1)
- 空间滤波器
- 3.6 锐化空间滤波器
- 平滑空间滤波器
- 锐化空间滤波器
- 平滑空间滤波器
- 【3.6】锐化空间滤波器
- 频域处理 之 从空间滤波器获得频域滤波器
- 数字图像处理--锐化空间滤波器
- 数字图像处理---平滑空间滤波器
- Matlab图像处理系列2———空间域平滑滤波器
- Matlab图像处理系列3———空间域锐化滤波器
- 【图像处理笔记】平滑空间滤波器
- 【图像处理笔记】锐化空间滤波器
- 【图像处理笔记】平滑空间滤波器
- 【图像处理笔记】锐化空间滤波器
- MATLAB 函数fspecial支持的空间滤波器
- 图像滤波处理:空间滤波器实现
- 一MM从10楼跳下后……
- 琐碎日记
- A*算法实现8数或者15数问题
- RSS新闻阅读器-inewsware0.56中文版发布
- [转]学C++ 的50条建议
- 空间域滤波器(1)
- 深度和广度优先分油问题
- 由于刚刚拿到nba live 2005,还没有爽够,所以翻译计划暂停一天。
- Visaul C#托盘程序制作心得
- “王者”再临==希望之“邱”==又来了!?嗯?我为什么会说“又”这个字!?
- B/S与C/S的概念
- 乘客
- 被窝里发短信
- 且听风吟(朴树)