目录
一,空间滤波器
使用空间模板进行的图像处理,被称为空间滤波。模板本身被称为空间滤波器。
二,平滑滤波器
1,用途
模糊处理,去除图像中一些不重要的细节,减小噪声
2,线性滤波器
就是做加权平均
(1)均值滤波器
其中,一种特例就是每个元素都相等,这种叫均值滤波器,也叫归一化滤波器,如下:
imageBlur = cv2.blur(image2,(5,7))
第二个参数是核大小
C++版:
int maxScaleUp = 100;
int scaleFactor = 1;
string windowName = "Resize Image";
string trackbarValue = "Scale";
Mat image;
void scaleImage(int, void*)
{
Mat scaledImage;
if (scaleFactor == 0)scaleFactor = 1;
// Resize the image
blur(image, scaledImage, Size(scaleFactor, scaleFactor));
imshow(windowName, scaledImage);
waitKey(0);
//destroyAllWindows();
}
int main()
{
image = imread("D:/2.png");
resize(image, image, Size(400, 400));
namedWindow(windowName, WINDOW_AUTOSIZE);
createTrackbar(trackbarValue, windowName, &scaleFactor, maxScaleUp, scaleImage);
scaleImage(25, 0);
return 0;
}
(2)高斯滤波器
以高斯卷积作为滤波器
卷积(Convolution)_nameofcsdn的博客-CSDN博客_卷积
imageBlur = cv2.GaussianBlur(image2,(5,5),1)
第二个参数是核大小,第三个参数是标准差
3,非线性滤波器
(1)排序统计滤波器
基于滤波器所在图像区域中像素的排序,由排序结果决定的值代替中心像素的值。
如中值滤波器、最大值滤波器、最小值滤波器,作用分别是去除噪声、寻找最亮点、寻找最暗点。
中值滤波:
int main()
{
Mat image = imread("D:/img6.png");
Mat image2;
medianBlur(image, image2, 5);
imshow("image", image);
imshow("image2", image2);
waitKey(0);
return 0;
}
(2)其他
略
三,锐化滤波器
1,用途
突出图像中的细节,增强被模糊了的细节
印刷中的细微层次强调。弥补扫描对图像的钝化
超声探测成像,分辨率低,边缘模糊,通过锐化来改善
图像识别中,分割前的边缘提取
锐化处理恢复过度钝化、曝光不足的图像
尖端武器的目标识别、定位
2,原理
根据微积分中的偏微分,达到锐化效果。
锐化滤波器分为一阶微分滤波器(梯度算子)、二阶微分滤波器(拉普拉斯算子)。
3,梯度算子
(1)梯度的模
各种梯度算子,都是这个公式的离散近似。
所有的梯度算子,梯度计算都是由两个模板组成,第一个求得梯度的第一项,第二个求得梯度的第二项,然后求和,得到梯度。
(2)简化近似梯度算子
平方和再开方的计算过于复杂,于是又有了一些简化的近似计算非方案。
(3)Roberts交叉梯度算子
相当于旋转了45度求梯度。
(4)Prewitt梯度算子
(5)Sobel梯度算子
int main()
{
Mat image = imread("D:/2.png");
Mat image2;
Sobel(image, image2, image.depth(), 1, 1);
imshow("image", image);
imshow("image2", image2);
waitKey(0);
return 0;
}
(6)梯度总结
不同梯度算子的运算结果,换算到梯度的常数是不一样的。
Roberts交叉梯度算子的方向不太一样(坐标系旋转了45度),其他几个算子都是正常方向,x和y方向分别计算。
4,拉普拉斯算子
对应的核:
int main()
{
Mat image = imread("D:/2.png");
Mat image2;
Laplacian(image, image2, image.depth(), 1);
imshow("image", image);
imshow("image2", image2);
waitKey(0);
return 0;
}
图像中的边缘往往是斜坡而不是悬崖,二阶微分关注的是斜坡的端点,一阶微分关注的是整个斜坡,从这个角度看,二阶微分效果更好。
4.25 从这开始:
写了个这种斜坡边缘的图,对比sobel和拉普拉斯的效果:
int main()
{
Mat img = Mat(400, 400, CV_8UC1);
for (int i = 0; i < img.rows; i++)for (int j = 0; j < img.cols; j++) {
int d = min(abs(i - 200), abs(j - 200));
if (d <= 100)img.at<uchar>(i, j) = 240;
else if (d >= 108)img.at<uchar>(i, j) = 80;
else img.at<uchar>(i, j) = 240 - 10 * (d - 100);
}
Mat img2;
Sobel(img, img2, img.depth(), 1, 1);
Mat img3;
Laplacian(img, img3, img.depth(), 1);
cv::imshow("img", img);
cv::imshow("img2*8", img2 * 8);
cv::imshow("img3*8", img3 * 8);
cv::waitKey(0);
return 0;
}
ps:2个结果都和想象的不完全一样,这可能需要深究源代码才能搞清楚。
5,非锐化掩蔽、高提升滤波
(1)非锐化掩蔽
int main()
{
Mat img = Mat(400, 400, CV_8UC1);
for (int i = 0; i < img.rows; i++)for (int j = 0; j < img.cols; j++) {
int d = min(abs(i - 200), abs(j - 200));
if (d <= 100)img.at<uchar>(i, j) = 240;
else if (d >= 108)img.at<uchar>(i, j) = 80;
else img.at<uchar>(i, j) = 240 - 10 * (d - 100);
}
Mat img3;
Laplacian(img, img3, img.depth(), 1);
Mat img4;
blur(img, img4, Size(5, 5));
cv::imshow("img", img);
cv::imshow("img-img3", img - img3);
cv::imshow("img + (img - img4 )", img + (img - img4));
cv::waitKey(0);
return 0;
}
(img同上)
边界非常突出
比原图的边界清楚一点,不过并不明显。
(2)高提升滤波
高提升滤波就是把模板的k倍加到原图上,k>1
int main()
{
Mat img = Mat(400, 400, CV_8UC1);
for (int i = 0; i < img.rows; i++)for (int j = 0; j < img.cols; j++) {
int d = min(abs(i - 200), abs(j - 200));
if (d <= 100)img.at<uchar>(i, j) = 240;
else if (d >= 108)img.at<uchar>(i, j) = 80;
else img.at<uchar>(i, j) = 240 - 10 * (d - 100);
}
Mat img3;
Laplacian(img, img3, img.depth(), 1);
Mat img4;
blur(img, img4, Size(5, 5));
cv::imshow("img", img);
cv::imshow("img + (img - img4 )", img + (img - img4)*3);
cv::waitKey(0);
return 0;
}
四,模糊集合
使用模糊处理,可以在一定程度上消除输出结果对于阈值精确性的依赖。
1,使用模糊集进行灰度变换
我们把直方图均衡表示为:
按照模糊集合论,每个像素点以不同的程度同时分别属于暗集、灰集、亮集。
我们根据常见去模糊公式(重心法)的简化公式来计算变换结果:
即根据像素属于暗集、灰集、亮集的程度进行加权平均,vd,vg,vb取常数。
const int d = 40;
double isDark(int pix)
{
if (pix < 128 - d)return 1;
if (pix > 128)return 0;
return (128.0 - pix) / d;
}
double isBright(int pix)
{
if (pix > 128 + d)return 1;
if (pix < 128)return 0;
return (pix - 128.0) / d;
}
double isGray(int pix)
{
if (pix < 128 - d)return 0;
if (pix > 128 + d)return 0;
return 1 - abs(pix - 128.0) / d;
}
int main()
{
Mat img = imread("D:/img9.png", 0);
Mat img2;
equalizeHist(img, img2);
Mat img3(img.rows, img.cols, img.type());
for (int i = 0; i < img.rows; i++)for (int j = 0; j < img.cols; j++) {
int p = int(img.at<uchar>(i, j));
int p2 = (isDark(p) * 20 + isBright(p) * 240 + isGray(p) * 128) / (isDark(p) + isBright(p) + isGray(p));
img3.at<uchar>(i, j) = uchar(p2);
}
cv::imshow("img", img);
cv::imshow("img2", img2);
cv::imshow("img3", img3);
cv::waitKey(0);
return 0;
}
2,使用模糊集进行边缘检测
double isSame(int dp)
{
dp = abs(dp);
if (dp < 30)return 1 - dp / 30.0;
return 0;
}
int deblur(double isSame)
{
if (isSame < 0.9)return (1 - isSame / 0.9) * 255;
return 0;
}
int main()
{
Mat img = imread("D:/img10.png", 0);
Mat img2(img.rows, img.cols, img.type());
img2 = 0;
for (int i = 1; i < img.rows - 1; i++)for (int j = 1; j < img.cols - 1; j++) { // 四邻居
int p = img.at<uchar>(i, j);
int up = img.at<uchar>(i - 1, j), down = img.at<uchar>(i + 1, j);
int left = img.at<uchar>(i, j - 1), right = img.at<uchar>(i, j + 1);
up -= p, down -= p, left -= p, right -= p; //计算四个方向的差分
double sup = isSame(up), sdown = isSame(down);
double sleft = isSame(left), sright = isSame(right);
double smin1 = min(sup, sleft), smin2 = min(sup, sright), smin3 = min(sdown, sleft), smin4 = min(sdown, sright);
double smax = max(max(smin1, smin2), max(smin3, smin4));
img2.at<uchar>(i, j) = deblur(smax);
}
cv::imshow("img", img);
cv::imshow("img2", img2);
Canny(img, img, 200, 100, 3);
cv::imshow("img3", img);
cv::waitKey(0);
return 0;
}
输入人的头部扫描图像:
输出2个结果:
canny边缘检测(图三)的轮廓更清晰,没有噪点,模糊边缘检测的结果(图二)有很多噪点,但是保留了更多的边缘信息。
五,可分离滤波器
可分离滤波器:如果一个核可以表示成2个向量的乘积,那么采用分离式的计算就可以节省大量时间。
(1)sobel
分离式:
这个例子可以节约大概一半时间。
(2)高斯
分离式:
这个例子可以节约大概3/5时间
(3)opencv中相关实现
六,双边滤波器
- 目前我们了解的滤波器都是为了 平滑 图像, 问题是有些时候这些滤波器不仅仅削弱了噪声, 连带着把边缘也给磨掉了。 为避免这样的情形 (至少在一定程度上 ), 我们可以使用双边滤波。
- 类似于高斯滤波器,双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。
opencv 接口:
void bilateralFilter( InputArray src, OutputArray dst, int d,
double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT );