在空间域对图像可以进行加噪声(椒盐噪声,高斯噪声),对比度增强(直方图均衡化),平滑滤波,锐化
首先是椒盐噪声,究其原理,其实就是随机在图像上将一些点设置为纯白色(盐)或者纯黑色(椒),那么我们只要知道需要加的个数,就可以通过生成随机数的方式加噪声。
def sp_noise(img, prob, is_gray = False):
image = np.array(img)
height = img.shape[0]
width = img.shape[1]
image_noise = image.copy()
# 得到需要增加噪声的个数
num_noise = int(prob * height * width)
for i in range(num_noise):
# 随机生成当前噪声的坐标
rows = np.random.randint(0, height - 1)
cols = np.random.randint(0, width - 1)
if is_gray: # 灰度图只需要在当前位置置为0/255
if np.random.randint(0, 2) == 0:
image_noise[rows, cols] = 0
else:
image_noise[rows, cols] = 255
else: # RGB彩色图,需要在三个通道都置为0/255
if np.random.randint(0, 2) == 0:
image_noise[rows, cols, :] = 0
else:
image_noise[rows, cols, :] = 255
return image_noise
原图:
加入椒盐噪声(prob=0.1):
第二种是高斯噪声,这个的原理是产生指定均值和方差的高斯噪声值,然后直接加在全图上,由于可能有超过[0,255]范围的值,最后再进行修正就行。
def gasuss_noise(img, mean=0, std=0.01):
img = np.array(img / 255, dtype=float)
# 产生高斯随机值
noise = np.random.normal(mean, std ** 0.5, img.shape)
out = img + noise
# 修正
if out.min() < 0:
low_clip = -1.
else:
low_clip = 0.
out = np.clip(out, low_clip, 1.0)
out = np.round(out * 255).astype(np.uint8)
return out
加入高斯噪声(mean=0, std=0.01):
由于有些图片偏亮或者偏暗,通道的像素值会集中于某个区域,所以将其展开平均到整个区域内,会得到类似对比度增强的效果。
对于灰度图像,直接调用cv2.equalizeHist(image)即可,多通道的图片需要对每个通道进行操作然后合并
def equalizeHist_rgb(img):
# 通道分离
r, g, b = cv2.split(img)
r_hist = cv2.equalizeHist(r)
g_hist = cv2.equalizeHist(g)
b_hist = cv2.equalizeHist(b)
# 通道合并
equal_out = cv2.merge((r_hist, g_hist, b_hist))
return equal_out
图像和原图对比远处森林和近处倒影都清晰了不少
在空域中的滤波操作,其实就是采用不同算子的卷积操作
常用平滑滤波器(低通滤波器):
平均模板:
中心加权模板:
高斯模板:
常用锐化模板:
def sharp(img):
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32)
img_sharp = cv2.filter2D(img, -1, kernel=kernel)
return img_sharp
def smooth(img):
kernel = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], np.float32)
img_smooth = cv2.filter2D(img, -1, kernel=kernel)
return img_smooth
平滑处理结果(11*11高斯低通核):
锐化处理结果(3*3高斯高通核)
空域到频域的变化是傅里叶变换,于是在空域中的卷积操作就等于在频域中的乘积
由于理想低通滤波器傅里叶变换之后会产生振铃现象,产生不必要的噪声,所以我们采用高斯滤波器
高斯低通滤波器函数:
首先,由于图像直接傅里叶变换之后低频部分在四个角落,所以我们要先变换到中间,而在处理之后还需要还原
傅里叶预处理函数:
def stdFftImage(img_gray, rows, cols):
fimg = np.copy(img_gray)
fimg = fimg.astype(np.float32)
# 中心化
for r in range(rows):
for c in range(cols):
if (r+c) % 2:
fimg[r][c] = -1 * img_gray[r][c]
img_fft = fftImage(fimg, rows, cols)
return img_fft
def fftImage(img_gray, rows, cols):
rPadded = cv2.getOptimalDFTSize(rows)
cPadded = cv2.getOptimalDFTSize(cols)
imgPadded = np.zeros((rPadded, cPadded), dtype=np.float32)
imgPadded[:rows, :cols] = img_gray
img_fft = cv2.dft(imgPadded, flags=cv2.DFT_COMPLEX_OUTPUT)
return img_fft
def graySpectrum(fft_img):
real = np.power(fft_img[:, :, 0], 2.0)
imaginary = np.power(fft_img[:, :, 1], 2.0)
amplitude = np.sqrt(real+imaginary)
spectrum = np.log(amplitude+1.0)
spectrum = cv2.normalize(spectrum, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)
spectrum *= 255
return amplitude, spectrum
平滑处理:
def createLPFilter(shape, center, radius, n=2):
rows, cols = shape[:2]
r, c = np.mgrid[0:rows:1, 0:cols:1]
c -= center[0]
r -= center[1]
d = np.power(c, 2.0) + np.power(r, 2.0)
lpFilter_matrix = np.zeros(shape, np.float32)
# 低通高斯函数
lpFilter = np.exp(-d/(2*pow(radius, 2.0)))
lpFilter_matrix[:, :, 0] = lpFilter
lpFilter_matrix[:, :, 1] = lpFilter
return lpFilter_matrix
def smooth_fft(img, radius=100):
rows, cols = img_gray.shape[:2]
img_fft = stdFftImage(img_gray, rows, cols)
amplitude, _ = graySpectrum(img_fft)
minValue, maxValue, minLoc, maxLoc = cv2.minMaxLoc(amplitude)
max_radius = np.sqrt(pow(rows, 2) + pow(cols, 2))
nrows, ncols = img_fft.shape[:2]
# 构建低通高斯函数
ilpFilter = createHPFilter(img_fft.shape, maxLoc, radius)
# 频域相乘
img_filter = ilpFilter * img_fft
# 图像逆变换
img_ift = cv2.dft(img_filter, flags=cv2.DFT_INVERSE + cv2.DFT_REAL_OUTPUT + cv2.DFT_SCALE)
out_img = np.copy(img_ift[:rows, :cols])
for r in range(rows):
for c in range(cols):
if (r + c) % 2:
out_img[r][c] = -1 * out_img[r][c]
# 数值溢出修正
out_img[out_img < 0] = 0
out_img[out_img > 255] = 255
out_img = out_img.astype(np.uint8)
out_img += img
return out_img
以上函数适用于单通道图像,类似地,我们在使用三通道图像的时候需要三个通道分别处理:
def smooth_fft_rgb(img, radius=100):
img_r, img_g, img_b = cv2.split(img)
img_r_sharp = smooth_fft(img_r)
img_g_sharp = smooth_fft(img_g)
img_b_sharp = smooth_fft(img_b)
out_img = cv2.merge((img_r, img_g, img_b))
return out_img
与平滑处理唯一不同的就是滤波函数变成了高通函数,而在频域中表现高通函数就是1-低通函数
而纯粹的高通滤波出来的是图像的轮廓信息,加上原图信息就是锐化后的图像
def sharp_fft(img, radius=100):
rows, cols = img_gray.shape[:2]
img_fft = stdFftImage(img_gray, rows, cols)
amplitude, _ = graySpectrum(img_fft)
minValue, maxValue, minLoc, maxLoc = cv2.minMaxLoc(amplitude)
max_radius = np.sqrt(pow(rows, 2) + pow(cols, 2))
nrows, ncols = img_fft.shape[:2]
ilpFilter = createHPFilter(img_fft.shape, maxLoc, radius)
img_filter = ilpFilter * img_fft
img_ift = cv2.dft(img_filter, flags=cv2.DFT_INVERSE + cv2.DFT_REAL_OUTPUT + cv2.DFT_SCALE)
out_img = np.copy(img_ift[:rows, :cols])
for r in range(rows):
for c in range(cols):
if (r + c) % 2:
out_img[r][c] = -1 * out_img[r][c]
out_img[out_img < 0] = 0
out_img[out_img > 255] = 255
out_img = out_img.astype(np.uint8)
out_img += img
return out_img
def sharp_fft_rgb(img, radius=100):
img_r, img_g, img_b = cv2.split(img)
img_r_sharp = sharp_fft(img_r)
img_g_sharp = sharp_fft(img_g)
img_b_sharp = sharp_fft(img_b)
out_img = cv2.merge((img_r, img_g, img_b))
return out_img
锐化处理效果(radius=100):
(十)OpenCV-Python学习—频率域滤波 - silence_cho - 博客园