2015-06-09 20:29:55 lvlitc 阅读数 6171
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4099 人正在学习 去看看 贾志刚

         图像滤波大多数用于图像的模糊处理和减小噪声(个人理解)。常见的滤波有:均值滤波,中值滤波,高斯滤波等。在这我主要介绍一下中值滤波,它对于处理椒盐噪声十分有效。下面我简单介绍下它的原理,以及我自己写的中值滤波函数。

          均值滤波:    

           对一副图像上的某个点进行中值滤波处理,先将掩模内欲求的像素及其邻域的像素值排序,确定出中值,然后将这个中值赋值给该像素。如图所示一个5 x 5邻域中,用中值124代替中心的像素值。

 

                                  

          

Mat MedianFilter(Mat img) //中值滤波器
{
	int count = 0;   //领域中像素个数
	int index=0;
	int pixel1[9];     //数组存放像素值
	int pixel2[9];
	int pixel3[9];
	for (int x = 1; x < img.rows-1; x++)   //遍历像素,并用邻域像素的中值代替该像素
	{
		for (int y = 1; y < img.cols-1; y++)
		{
			count = 0;
			for (int row = -kernel_size / 2; row <= kernel_size / 2; row++)  //计算邻域像素
			{		
				int row2 = x + row;		
				for (int col = -kernel_size / 2; col <= kernel_size / 2; col++)
				{
					int col2 = y + col;		
					pixel1[count] = *(img.data + img.step[0] * row2 + img.step[1] * col2);  //将邻域像素放入数组
					pixel2[count] = *(img.data + img.step[0] * row2 + img.step[1] * col2 + img.elemSize1());
					pixel3[count] = *(img.data + img.step[0] * row2 + img.step[1] * col2 + img.elemSize1()*2);
					count++;
				}
			}
			bubblingsort(pixel1,count);  //排序
			bubblingsort(pixel2, count);
			bubblingsort(pixel3, count);
			*(img.data + img.step[0] * x + img.step[1] * y) = pixel1[count/2];  //用邻域像素的中值代替该像素
			*(img.data + img.step[0] * x + img.step[1] * y + img.elemSize1()) = pixel2[count/2];
			*(img.data + img.step[0] * x + img.step[1] * y + img.elemSize1()*2) = pixel3[count / 2];
		}

	}
	return img;
}

           

 注:我的代码中没有对图像的边缘像素进行处理,由于输入输出是同一张图,所以边缘像素依旧为原来的像素。
             运行结果:
           原图(带椒盐噪声):                                                                                                     处理后(中值滤波):

     

                   

        显然中值滤波对去除椒盐噪声有着明显的作用,但由于能力有限,并没有完全达到去除的效果,而且感觉有部分细节丢失,欢迎大神随时指点补充交流! 

      转载请说明出处!谢谢


2018-11-06 15:57:18 Monster_H7 阅读数 3253
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4099 人正在学习 去看看 贾志刚

1.什么是滤波?

图像滤波:即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。

消除图像中的噪声成分叫作图像的平滑化或滤波操作。信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信息经常被噪声淹没。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。

2.平滑处理的目的

图像滤波的目的有两个:

一是抽出对象的特征作为图像识别的特征模式;
另一个是为适应图像处理的要求,消除图像数字化时所混入的噪声。

而对滤波处理的要求也有两条:

一是不能损坏图像的轮廓及边缘等重要信息;
二是使图像清晰视觉效果好。

3.平滑处理的应用

关于滤波器,一种形象的比喻法是:
我们可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。

举一个滤波在我们生活中的应用:
美颜的磨皮功能。如果将我们脸上坑坑洼洼比作是噪声的话,那么滤波算法就是来取出这些噪声,使我们自拍的皮肤看起来很光滑。

4.中值滤波的处理方法

中值滤波是一种典型的非线性滤波,是基于排序统计理论的一种能够有效抑制噪声的非线性信号处理技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,让周围的像素值接近真实的值从而消除孤立的噪声点。该方法在取出脉冲噪声、椒盐噪声的同时能保留图像的边缘细节。这些优良特性是线性滤波所不具备的。

中值滤波首先也得生成一个滤波模板,将该模板内的各像素值进行排序,生成单调上升或单调下降的二维数据序列,二维中值滤波输出为

g(x, y)=medf{f(x-k, y-1),(k, l∈w)}

	其中f(x,y)和g(x,y)分别是原图像和处理后图像, w为输入的二维模板,能够在整幅图像上滑动,通常尺寸为3*3或5*5区域,也可以是不同的形状如线状、圆形、十字形、圆环形等。通过从图像中的二维模板取出奇数个数据进行排序,用排序后的中值取代要处理的数据即可。 

5.中值滤波的示意图

首先,我们复习中值。在一连串数字{1,4,6,8,9}中,数字6就是这串数字的中值。由此我们可以应用到图像处理中。依然我们在图像中去3*3的矩阵,里面有9个像素点,我们将9个像素进行排序,最后将这个矩阵的中心点赋值为这九个像素的中值。

引用

中值滤波示意图

椒盐噪声

椒盐噪声(salt-and-pepper noise)是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声。
  所谓椒盐,椒就是黑,盐就是白,椒盐噪声就是在图像上随机出现黑色白色的像素。椒盐噪声是一种因为信号脉冲强度引起的噪声,产生该噪声的算法也比较简单。
  椒盐噪声往往由图像切割引起,去除脉冲干扰及椒盐噪声最常用的算法是中值滤波。大量的实验研究发现,由摄像机拍摄得到的图像受离散的脉冲、椒盐噪声和零均值的高斯噪声的影响较严重。噪声给图像处理带来很多困难,对图像分割、特征提取、图像识别等具有直接影响。因此,实时采集的图像需进行滤波处理。消除图像中的噪声成份叫做图像的平滑化或滤波操作。滤波的目的有两个:一是抽出对象的特征作为图像识别的特征模式;二是为适应计算机处理的要求,消除图像数字化时所混入的噪声。对滤波处理的要求有两条:一是不能损坏图像轮廓及边缘等重要信息;二是使图像清晰,视觉效果好。

我们使用信噪比(Signal NoiseRate)衡量图像噪声,图象的信噪比应该等于信号与噪声的功率谱之比,但通常功率谱难以计算,有一种方法可以近似估计图象信噪比,即信号与噪声的方差之比(其实在均值为零的情况下,功率就是方差)。首先计算图象所有像素的局部方差,将局部方差的最大值认为是信号方差,最小值是噪声方差,求出它们的比值,再转成dB数,最后用经验公式修正。

6.椒盐处理和中值滤波的效果展示

在这里插入图片描述

7.代码(面向过程)

#%matplotlib inline
from matplotlib import pyplot as plt
import cv2
import numpy as np
from copy import deepcopy


filename = input("请输入图像名称:")
winname = "figure"
img = cv2.imread(filename)

def add_salt_noise(img, snr=0.5):
    # 指定信噪比
    SNR = snr
    # 获取总共像素个数
    size = img.size
    print(size)
    # 因为信噪比是 SNR ,所以噪声占据百分之10,所以需要对这百分之10加噪声
    noiseSize = int(size * (1 - SNR))
    # 对这些点加噪声
    for k in range(0, noiseSize):
        # 随机获取 某个点
        xi = int(np.random.uniform(0, img.shape[1]))
        xj = int(np.random.uniform(0, img.shape[0]))
        # 增加噪声
        if img.ndim == 2:
            img[xj, xi] = 255
        elif img.ndim == 3:
            img[xj, xi] = 0
    return img

img_demo = deepcopy(img)
snr = float(input("请输入一个信噪比(小数表示):"))
img_salt = add_salt_noise(img_demo, snr)
img_medianblur = cv2.medianBlur(img, 11)

img_all = np.hstack([
    img, img_salt, img_medianblur
])

plt.figure(figsize=(20,10))
plt.imshow(img_all[:,:,::-1])
plt.show()

8.程序演示(面向对象)

用tkinter 做的界面化处理操作

面向对象制作的界面程序处理中值滤波

完整代码(码云):码云分享
完整代码(github):github分享

觉得不错的朋友,可以与我交流关注,以及去码云和github点星,真的感谢!~

有问题可以联系

2019-11-05 00:07:52 qq_36511401 阅读数 4217
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4099 人正在学习 去看看 贾志刚

1、选择一张椒盐噪声比较明显的图片。椒盐噪声,椒盐噪声又称脉冲噪声,它随机改变一些像素值,是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声。椒盐噪声往往由图像切割引起。

2、代码。生成模版半径分别是3、5和7的图片。

package com.zxj.reptile.test.mnist;

import com.zxj.reptile.utils.image.ImageService;
import com.zxj.reptile.utils.image.ImageUtils;

public class ImgTest {

    private static final String File_Path = "G:\\xiaojie-java-test\\img\\";

    public static void main(String[] args) {
        //中值滤波
        String gaussSourcePath = File_Path + "滤波\\椒盐滤波\\椒盐噪声.jpg";
        String averageTargetPath = File_Path + "滤波\\椒盐滤波\\椒盐滤波_";
        ImageService.middleFilter(gaussSourcePath, averageTargetPath, ImageUtils.Gray_Type_Default, 3);//中值过滤
        ImageService.middleFilter(gaussSourcePath, averageTargetPath, ImageUtils.Gray_Type_Default, 5);//中值过滤
        ImageService.middleFilter(gaussSourcePath, averageTargetPath, ImageUtils.Gray_Type_Default, 7);//中值过滤
    }
}
package com.zxj.reptile.utils.image;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;

public class ImageService {
    /**
     * 中值过滤
     *
     * @param sourcePath   原图像
     * @param targetPath   目标图像
     * @param grayType     灰度化方式
     * @param filterLength 过滤的长度(阈值)
     */
    public static void middleFilter(String sourcePath, String targetPath, int grayType, int filterLength) {
        try {
            //获取原图像对象,并获取原图像的二维数组
            BufferedImage image = ImageIO.read(new File(sourcePath));
            int[][] imgArrays = ImageUtils.getTwoDimension(image);
            //生成新图像的二维数组
            imgArrays = ImageUtils.getGrayImg(imgArrays, grayType);//灰度化
            int[][] newImgArrays = ImageUtils.getMiddleFilter(imgArrays, filterLength);//中值过滤
            //生成新图片对象,填充像素
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
            ImageUtils.setTwoDimension(newImage, newImgArrays, ImageUtils.Channel_Type_1);
            //生成图片文件
            ImageIO.write(newImage, "JPEG", new File(targetPath + filterLength + ".jpg"));
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.zxj.reptile.utils.image;

import com.zxj.reptile.utils.algorithm.SortUtils;

import java.awt.image.BufferedImage;

public class ImageUtils {
    /**
     * 中值滤波
     *
     * @param imgArrays    图像二维数组
     * @param filterLength 过滤的长度(阈值)
     */
    public static int[][] getMiddleFilter(int[][] imgArrays, int filterLength) {
        final int imgHeight = imgArrays.length;
        final int imgWidth = imgArrays[0].length;
        int[][] newImgArrays = new int[imgHeight][imgWidth];
        //模版半径
        final int filterRadius = (filterLength - 1) / 2;
        final int filterSize = filterLength * filterLength;
        //获取数据
        for (int h = 0; h < imgHeight; h++) {//图片第几行
            for (int w = 0; w < imgWidth; w++) {//图片第几列
                int count = 0;
                int[] templateArray = new int[filterSize];
                for (int templateH = -filterRadius; templateH <= filterRadius; templateH++) {//模版第几行
                    int rowIndex = h + templateH;
                    if (rowIndex < 0 || rowIndex > imgHeight - 1) {
                        continue;
                    }
                    for (int templateW = -filterRadius; templateW <= filterRadius; templateW++) {//模版第几列
                        int columnIndex = w + templateW;
                        if (columnIndex < 0 || columnIndex > imgWidth - 1) {
                            continue;
                        }
                        templateArray[count++] = imgArrays[rowIndex][columnIndex];
                    }
                }
                //
                int[] newTemplateArray;
                if (count != templateArray.length) {
                    newTemplateArray = new int[count];
                    for (int i = 0; i < count; i++) {
                        newTemplateArray[i] = templateArray[i];
                    }
                    SortUtils.countSort(newTemplateArray);//计数排序
                    newImgArrays[h][w] = newTemplateArray[count / 2];
                } else {
                    SortUtils.countSort(templateArray);//计数排序
                    newImgArrays[h][w] = templateArray[filterRadius];
                }
            }
        }
        return newImgArrays;
    }

    //灰度处理的方法
    public static final byte Gray_Type_Default = 0;//默认加权法
    public static final byte Gray_Type_Min = 1;//最大值法
    public static final byte Gray_Type_Max = 2;//最小值法
    public static final byte Gray_Type_Average = 3;//平均值法
    public static final byte Gray_Type_Weight = 4;//加权法
    public static final byte Gray_Type_Red = 5;//红色值法
    public static final byte Gray_Type_Green = 6;//绿色值法
    public static final byte Gray_Type_Blue = 7;//蓝色值法

    //生成的图片是几通道的
    public static final byte Channel_Type_Default = 0;//默认三通道
    public static final byte Channel_Type_1 = 1;//单通道
    public static final byte Channel_Type_3 = 3;//三通道

    /**
     * 灰度化处理
     *
     * @param imgArrays 图像二维数组
     * @param grayType  灰度化方法
     */
    public static int[][] getGrayImg(int[][] imgArrays, int grayType) throws Exception {
        final int imgHeight = imgArrays.length;
        final int imgWidth = imgArrays[0].length;
        int[][] newImgArrays = new int[imgHeight][imgWidth];
        for (int h = 0; h < imgHeight; h++) {
            for (int w = 0; w < imgWidth; w++) {
                final int[] grb = getRgb(imgArrays[h][w]);
                newImgArrays[h][w] = getGray(grb, grayType);
            }
        }
        return newImgArrays;
    }

    /**
     * 通过像素值,返回r、g、b颜色通道的值
     *
     * @param pixel 像素值
     */
    public static int[] getRgb(int pixel) {
        int[] rgb = new int[3];
        rgb[0] = (pixel >> 16) & 0xff;
        rgb[1] = (pixel >> 8) & 0xff;
        rgb[2] = pixel & 0xff;
        return rgb;
    }

    /**
     * 根据不同的灰度化方法,返回灰度值
     *
     * @param rgb      r、g、b颜色通道的值
     * @param grayType 不同灰度处理的方法
     */
    public static int getGray(int[] rgb, int grayType) throws Exception {
        if (grayType == Gray_Type_Average) {
            return (rgb[0] + rgb[1] + rgb[2]) / 3;   //rgb之和除以3
        } else if (grayType == Gray_Type_Weight || grayType == Gray_Type_Default) {
            return (int) (0.3 * rgb[0] + 0.59 * rgb[1] + 0.11 * rgb[2]);
        } else if (grayType == Gray_Type_Red) {
            return rgb[0];//取红色值
        } else if (grayType == Gray_Type_Green) {
            return rgb[1];//取绿色值
        } else if (grayType == Gray_Type_Blue) {
            return rgb[2];//取蓝色值
        }
        //比较三个数的大小
        int gray = rgb[0];
        for (int i = 1; i < rgb.length; i++) {
            if (grayType == Gray_Type_Min) {
                if (gray > rgb[i]) {
                    gray = rgb[i];//取最小值
                }
            } else if (grayType == Gray_Type_Max) {
                if (gray < rgb[i]) {
                    gray = rgb[i];//取最大值
                }
            } else {
                throw new Exception("grayType出错");
            }
        }
        return gray;
    }

    /**
     * 获取二维像素
     *
     * @param image BufferedImage图像对象
     */
    public static int[][] getTwoDimension(BufferedImage image) {
        final int imgWidth = image.getWidth();
        final int imgHeight = image.getHeight();
        int[][] imgArrays = new int[imgHeight][imgWidth];
        for (int i = 0; i < imgHeight; i++) {
            for (int j = 0; j < imgWidth; j++) {
                imgArrays[i][j] = image.getRGB(j, i);
            }
        }
        return imgArrays;
    }

    /**
     * 将二维像素填充到图像中
     *
     * @param image       BufferedImage图像对象
     * @param imgArrays   二维像素
     * @param channelType 单通道还是三通道
     */
    public static void setTwoDimension(BufferedImage image, int[][] imgArrays, int channelType) throws Exception {
        final int imgWidth = image.getWidth();
        final int imgHeight = image.getHeight();
        for (int i = 0; i < imgHeight; i++) {
            for (int j = 0; j < imgWidth; j++) {
                if (channelType == Channel_Type_1) {
                    image.setRGB(j, i, (byte) imgArrays[i][j]);
                } else if (channelType == Channel_Type_3 || channelType == Channel_Type_Default) {
                    image.setRGB(j, i, imgArrays[i][j]);
                } else {
                    throw new Exception("channelType错误");
                }
            }
        }
    }
}

3、结果。半径越长,图像越模糊,效果越不理想。

4、结论。

        中值滤波采用非线性的方法,它在平滑脉冲噪声方面非常有效,同时它可以保护图像尖锐的边缘,选择适当的点来替代污染点的值,所以处理效果好,对椒盐噪声表现较好,对高斯噪声表现较差。半径越长,图像越模糊,效果越不理想。

 

 

2015-01-22 11:11:40 EbowTang 阅读数 6335
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4099 人正在学习 去看看 贾志刚

自适应中值滤波的原理

     自适应中值滤波的思想是根据噪声密度改变滤波窗口的大小,同时对噪声点和信号点采取不同的处理方法。对噪声点进行中值滤波,对信号点保持其灰度值不变。

       设为fij为点(i,j)的灰度值,Sij为当前工作窗口,fmin,fmax和fmed分别为Sij中的灰度最小值、灰度最大值和灰度中值,令maxize为预设的允许最大窗口。自适应中值滤波的步骤如下:

1)若 fmin< fmed <fmax,则转至第2步;否则增大窗口的尺寸。若的尺寸小于的尺寸,则重复第1步;否则输出。

2)若 fmin< fij <fmax,则输出fij;否则输出fmed

可以看出,算法中噪声的检测和认定时以 fmin fmax为基准的,如果 fmin< fmed <fmax,表明fmed 不是噪声,

接着根据fmin< fij <fmax判断fij 是否为噪声,当fmedfij 都不是脉冲噪声时,优先输出fij

引入自适应中值滤波算法主要有3 个目的: 

一是去除脉冲噪声;

二是平滑其他非脉冲噪声;

三是减少诸如物体边界细化或粗化等失真。

自适应中值滤波的流程图如下图所示。



参考代码:

/////////////自适应中值滤波/////////////////////////////////
int adp_media_filter(unsigned char* inbuffer,int width,int height,int maxwinsize,unsigned char* outbuffer)
{
	int pos = (maxwinsize - 1) / 2;
	memcpy(outbuffer,inbuffer,width*height);       
	for (int m = pos; m < height - pos; m++)//当前中心位置(m,n)
	{
		for (int n = pos; n < width - pos; n++)
		{
			int curwinsize = 3;     //设置初始滤波窗口大小
			while (curwinsize <= maxwinsize)
			{
				int curpos = (curwinsize - 1) / 2;
				int winpos = 0;
				int lens = curwinsize*curwinsize;
				int* windows = new int[lens];
				for (int i = -curpos; i < curpos + 1; i++)
					for (int j = -curpos; j < curpos + 1; j++)
						windows[winpos++] = inbuffer[(m + i)*width + n + j];
				
				sort(windows, lens);
				int fmin = windows[0];
				int fmax = windows[lens - 1];
				int fmed = windows[(lens - 1) / 2];
				int A1 = fmed - fmin;
				int A2 = fmed - fmax;
				if (A1 > 0 && A2 < 0)//第一层噪声检测,fmed是不是噪声
				{
					//满足fmin< fmed < fmax,表明fmed不是噪声
					int B1 = inbuffer[m*width + n] - fmin;//当前窗口中心值inbuffer[m*width + n]
					int B2 = inbuffer[m*width + n] - fmax;
					//满足fmin< fmn < fmax,表明fmn不是噪声
					if (B1 > 0 && B2 < 0)//第二层检测,fmn是不是噪声
						outbuffer[m*width + n] = inbuffer[m*width + n];//fmn和fmed都不是噪声优先输出当前窗口中心值
					else
						outbuffer[m*width + n] = fmed;//fmn是噪声,输出中间值重新估计该点
					delete[] windows;
					windows = NULL;
					break;
				}
				curwinsize += 2;
				delete[] windows;
				windows = NULL;
			}
		}
	}
	//对边界进行处理,与中值滤波一样
	for (int k = 0;k < pos;k++)
		for (int l =pos;l < width-pos;l++)
			outbuffer[k*width+l] = outbuffer[pos*width+l];
	for(int a=height-pos;a < height;a++)
		for(int b=pos;b < width-pos;b++)
			outbuffer[a*width+b] = outbuffer[(height-pos-1)*width+b];
	for(int c = 0;c < pos;c++)
		for(int d=0;d < height;d++)
			outbuffer[d*width+c] = outbuffer[d*width+pos];
	for (int e = width-pos;e < width;e++)
		for(int f = 0;f < height;f++)
			outbuffer[f*width+e] = outbuffer[f*width+width-pos-1];

	return 0;	
}


实验结果:

以下所有结果均为C++处理。
1,对原图像进行处理的结果(左为原图)
可以发现,自适应中值滤波对图像边缘的保护相当好


2,对乘性噪声图像进行处理的结果(左为噪声图)

注意该噪声为matlab中的乘性噪声,可以发现对乘性噪声的处理效果相当差。



3,对椒盐噪声图像进行处理的结果(左为噪声图)

注意该噪声为matlab中的椒盐噪声,可以发现对椒盐噪声的处理效果优秀。



最后在此处收录一份别人写的matlab程序:

function f = adpmedian(g, Smax)
%ADPMEDIAN Perform adaptive median filtering.
%   F = ADPMEDIAN(G, SMAX) performs adaptive median filtering of
%   image G.  The median filter starts at size 3-by-3 and iterates up
%   to size SMAX-by-SMAX. SMAX must be an odd integer greater than 1.

%   Copyright 2002-2004 R. C. Gonzalez, R. E. Woods, & S. L. Eddins
%   Digital Image Processing Using MATLAB, Prentice-Hall, 2004
%   $Revision: 1.5 $  $Date: 2003/11/21 14:19:05 $

% SMAX must be an odd, positive integer greater than 1.
if (Smax <= 1) | (Smax/2 == round(Smax/2)) | (Smax ~= round(Smax))
   error('SMAX must be an odd integer > 1.')
end
[M, N] = size(g);

% Initial setup.
f = g;
f(:) = 0;
alreadyProcessed = false(size(g));

% Begin filtering.
for k = 3:2:Smax
   zmin = ordfilt2(g, 1, ones(k, k), 'symmetric');
   zmax = ordfilt2(g, k * k, ones(k, k), 'symmetric');
   zmed = medfilt2(g, [k k], 'symmetric');
   
   processUsingLevelB = (zmed > zmin) & (zmax > zmed) & ...
       ~alreadyProcessed; 
   zB = (g > zmin) & (zmax > g);
   outputZxy  = processUsingLevelB & zB;
   outputZmed = processUsingLevelB & ~zB;
   f(outputZxy) = g(outputZxy);
   f(outputZmed) = zmed(outputZmed);
   
   alreadyProcessed = alreadyProcessed | processUsingLevelB;
   if all(alreadyProcessed(:))
      break;
   end
end

% Output zmed for any remaining unprocessed pixels. Note that this
% zmed was computed using a window of size Smax-by-Smax, which is
% the final value of k in the loop.
f(~alreadyProcessed) = zmed(~alreadyProcessed);




参考资源:

【1】自适应中值滤波算法在图像处理中的应用,刘 颖,陈谨女,长安大学电子与控制工程工程学院
【2】一种改进的自适应中值滤波方法,卫保国,西北工业大学电子信息学院,2008

2017-10-08 21:53:37 linxid 阅读数 3293
  • OpenCV3.2 Java图像处理视频学习教程

    OpenCV3.2 Java图像处理视频培训课程:基于OpenCV新版本3.2.0详细讲述Java OpenCV图像处理部分内容,包括Mat对象使用、图像读写、 基于常用核心API讲述基本原理、使用方法、参数、代码演示、图像处理思路与流程讲授。主要内容包括opencv像素操作、滤波、边缘提取、直线与圆检测、形态学操作与分水岭、图像金子塔融合重建、多尺度模板匹配、opencv人脸检测、OpenCV跟Tomcat使用实现服务器端图像处理服务。

    4099 人正在学习 去看看 贾志刚

滤波是图像处理很重要的一部分,主要分为空间滤波和频域滤波,此节主要说明空间滤波。空间滤波可以分为线性空间滤波和非线性空间滤波。所用函数包括:imfliter, colfit, padarray, fspecial, ordfilt2, medfilt2。

滤波函数

线性空间滤波

线性空间滤波是对区域的像素做先行处理,将领域内的每个像素与对应的系数相乘。其中所用到的矩阵,是滤波器或者说是掩模。线性空间滤波主要有两种方式,一是相关,另一个是卷积。二者的区别是滤波器是否发生反转,介绍可以参阅信号。

imfilter

  • 函数语法:
    g = imfilter(f,w,filtering_mode,boundary _options,size _options)
    • f:输入图像
    • w:掩模(滤波器)
    • filtering_mode:滤波方式,相关还是卷积
    • boundary_options:零填充的方法
    • 选项介绍:
      Paste_Image.png
    • 注意:显示图像类型问题,可能会出现显示发白问题。
      http://blog.csdn.net/linxid/article/details/78145516
  • 代码示例:
img1 = imread('key2.jpg');
imshow(img1);
img2 = rgb2gray(img1);
imshow(img2);
w = [0 1 0;1 -4 1;0 1 0];
%默认的边界选项,滤波
gd = imfilter(img2,w);
figure,imshow(gd,[ ]);
%通过复制边界进行填充
gr = imfilter(img2,w,'replicate');
figure,imshow(gr,[]);
%通过边界对称填充
gs = imfilter(img2,w,'symmetric');
figure,imshow(gs,[ ]);
%包括循环边界...

%注意图像类型

非线性空间滤波

线性空间滤波是基于计算像素的乘积之和,是一个线性运算。而非线性空间滤波,是对像素做函数运算。两个常用的非线性滤波函数是colfilt和nlfilter。由于colfilt执行起来比nlfilter快得多,所以我们多采用colfilt。

colfilt

  • 函数语法:
    g = colfilt(f, [m n], 'sliding', @fun, parameters);
    • f:输入图像
    • [m n]:滤波区域的维数
    • ‘sliding’:滤波器逐个像素滑动
    • ‘@fun’:‘@’称为函数句柄,fun为处理函数
    • ‘parameters’:函数可能用到的参数

colfiltu不同于imfilter,填充方式没有确定,进行滤波之前,我们需要自行对图像进行填充,这里我们使用padarray函数。
除此之外此函数很重要的一部分是定义所用到的函数,首先要定义非线性函数。

padarray

  • 函数语法:
    fp = padarray(f, [ r c ], method, direction);
    • f,fp:输出和填充后的图像
    • [r c]:填充f的行数和列数,是填充的数目,不是填充后矩阵的数目
    • method和direction:

空间滤波器

MATLAB的图像工具箱可以自动生成一些规定的滤波器。

线性空间滤波器

fspecial

该函数可以生成工具箱预定义的二维线性空间滤波器。

  • 函数语法:
    w = fspecial('type', parameters);

‘type’为滤波器类型,‘parameters’为定义参数,详细情况如下:

Paste_Image.png
经典的一个滤波器是拉普拉斯滤波器,定义算子和通用的近似数字表达式,可查阅信号课本。
1.对图像做卷积操作可实现此变换,掩模如下所示:
Paste_Image.png
2.另一种定义考虑对角线元素,掩模是:
Paste_Image.png
3. fspecial实现一个更为常见的拉普拉斯算子掩模:
Paste_Image.png
fspecial仅仅是为了生成一个滤波器,滤波器同样可以手动设置。我们在使用拉普拉斯算子处理后,可以用原图减去操作后的结果,还原失去的灰度的色调。通过变换后我们可以得到更清晰的图像。

  • 代码示例:
img1 = imread('night.jpg');
%定义两个不同的滤波方法
w4 = fspecial('laplacian',0);
w8 = [1 1 1;1 -8 1;1 1 1];
%进行类型转换,保证显示图像更好
img1 = im2double(img1);
%拉普拉斯滤波后的图像
img_f1 = imfilter(img1,w4,'replicate');
img_f2 = imfilter(img1,w8,'replicate');
%进行图像相减
img_out1 = img1 - img_f1;
img_out2 = img1 - img_f2;
imshow(img1);
figure,imshow(img_out1);
figure,imshow(img_out2);

非线性空间滤波器

用于生成非线性空间滤波的一个工具是函数ordfilt2,可以生成统计排序的滤波器,而这些都是非线性滤波器。

  • 函数语法:
    g = ordfilt2(f, order, domain);
    f为输入图像,函数用一组元素中第order个元素来代替f中的每一个元素。domain来指定领域,是一个m*n的矩阵。对领域内的元素进行排序后,再代替。常用此类滤波器:
    1.最小滤波器:
    g = ordfilt2(f,1,ones(m, n));
    ones(m,n)用于创建矩阵。
    2.最大滤波器:
    g = ordfilt2(f,m*n,ones(m,n));
    3.中值滤波器:
    g = ordfilt2(f,median(1:m*n),ones(m,n));
    median(1:m*n)是指1到m *n的中值。median的通用语法为:
    v = median(A,dim);
    v是一个向量,是A矩阵沿行(或列)的中值所构成的向量。dim = 1,取相应列的中值,dim = 2,取相应行的中值。
    中值滤波是一种非常重要的非线性滤波器。是降低图像椒盐噪声的一种有效工具。
  • medfilt2
    工具箱所提供的一个专门的二维中值滤波函数。
    g = medfilt2(f,[m n],padopt);
    [m n]定义领域矩阵,padopt指定边界填充选项。
    中值滤波前后对比效果:

原图.png

Paste_Image.png

中值滤波算法

阅读数 30204

中值滤波器

阅读数 1390

没有更多推荐了,返回首页