踩坑一(python+数字图像)


踩坑(一)

python实现中值滤波算法

有一幅图像被椒盐噪声所污染,写中值滤波算法来去噪。

预想中的中值滤波效果:

实际上。。。

这波是反向滤波。。。提取出了噪声点???

import numpy as np
import MDIP
import cv2

if __name__ == '__main__':
    image = MDIP.open_raw("E:\\test\\testopencv\\Pulse_Noised_Image.raw")
    width = image.shape[1]
    height = image.shape[0]     # image.shape(高,宽)
    outimg = np.zeros([height,width])

    for i in range(1,height-1):
        for j in range(1,width-1):
            # 取滤波区域 
            block = []  # 滤波区域
            for m in [-1,0,1]:
                for n in [-1,0,1]:
                    block.append(image[i+m][j+n]) # 取中值
            block.sort      # 排序
            value = block[int(len(block)/2)]
            outimg[i][j] = value# 取中值
    cv2.imshow("out",outimg)
    cv2.imshow("pic_noise",image)
    cv2.waitKey(0)

犯病一:block. sort

列表有一个方法sort可以排序,但是它并不能赋值,sort之后还是block本身。所以这里取的“中值”就是这个3*3矩阵的中第二行第二列的值即它本身。整个循环所实现的就成为了逐个像素点赋值(不包括最外圈一层),没有达到中值滤波的效果。

犯病二: 数制问题

在程序中添加如下代码,查看输入输出图像的数据类型:

print(type(image[0][0]),type(outimg[0][0]))

结果如下:

 

......

输入输出的数据格式好像。。。不一样

检查后发现是这里出了问题:

outimg = np.zeros([height,width])
'''
	zeros(shape, dtype=float, order=‘C’)
    shape:形状
    dtype:数据类型,可选参数,默认numpy.float64
    order:可选参数,c代表与c语言类似,行优先;F代表列优先
'''

(??)

那就给输出加上数值转换应该就好了...

outimg = outimg.astype(np.uint8) 

但是

还有一个问题

为什么cv2.imshow()显示出的正好是噪声图像的黑点噪声???

查!

cv2.imshow()的描述:

Displays an image in the specified window.

The function imshow displays an image in the specified window. If the window was created with the cv::WINDOW_AUTOSIZE flag, the image is shown with its original size, however it is still limited by the screen resolution. Otherwise, the image is scaled to fit the window. The function may scale the image, depending on its depth:

If the image is 8-bit unsigned, it is displayed as is.
If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to [0,255].
If the image is 32-bit or 64-bit floating-point, the pixel values are multiplied by 255. That is, the value range [0,1] is mapped to [0,255].
'''
函数 imshow 在指定窗口中显示图像。如果窗口是使用cv::WINDOW_AUTOSIZE标志创建的,则图像以其原始大小显示,但仍受屏幕分辨率的限制。否则,将缩放图像以适合窗口。该函数可以缩放图像,具体取决于其深度:

如果图像是 8 位无符号,则按原样显示。
如果图像是 16 位无符号或 32 位整数,则将像素除以 256。即值范围 [0,255*256] 映射到 [0,255]。
如果图像是 32 位或 64 位浮点,则像素值乘以 255。即值范围 [0,1] 映射到 [0,255]。
'''

图像中黑色噪点灰度值为0,乘255还是0,它不会变,显示为黑色。但是其余的值为64位浮点乘以255后一定会超出上限,直接被255截断,显示为白色。

低通滤波算法实现

#pul_img_men = MDIP.mean_filter(pul_img)     # 脉冲噪声均值滤波
#pul_img_gau = MDIP.gaussian_filter(pul_img) # 脉冲噪声高斯滤波
pul_img_mid = MDIP.median_filter(pul_img)   # 脉冲噪声中值滤波

直接滤波效果没问题,效果如上文。

但是前面两句取消注释之后就出现了这种情况,变糊了:

很明显输入的pul_img经过均值和高斯滤波器后直接被赋值了。

但是连续三局代码中并没有对它进行赋值操作。

(??)

看一下源码,发现了。。。

def mean_filter(image): # 均值滤波
    meth = [1,1,1,
            1,1,1,
            1,1,1]			# 卷积核
    outimg = image			# 致命错误
    width = image.shape[1]
    height = image.shape[0]     # image.shape(高,宽)
    for i in range(1,height-1):
        for j in range(1,width-1):
            # 取滤波区域 
            block = []  # 滤波区域
            for m in [-1,0,1]:
                for n in [-1,0,1]:
                    block.append(image[i+m][j+n])
            outimg[i][j]=int(convolution(block,meth)/9)
    return outimg

在Python语言中,对象是通过引用传递的。在赋值时,不管这个对象是新创建的,还是一个已经存在的,都是将该对象的引用(并不是值)赋值给变量。outimg是新创建的对象,直接引用image,导致二者地址相等,也就是说。。。这一句我只是给存储image的这块空间增加了一个新的名字——outimg。所以后面在对outimg赋值的时候也相当于直接更改了image的值。

改为如下语句即可

outimg = np.zeros([height,width])#不要忘记这里生成的是numpy.float64,需要转化(直接加参数也行)