#encoding:utf-8
"""
@author: Dragon Liu
Operating environment: Python 3.7.1
lib: opencv-python
Date: 2020/3/16
"""
#导入库
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图片
img = cv2.imread('02.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#方框滤波
img_box = cv2.boxFilter(source, -1, (5,5), normalize=1)
# 均值滤波
img_blur = cv2.blur(source, (5,5))
#中值滤波
img_median = cv2.medianBlur(source, 3)
# 高斯滤波
img_Guassian = cv2.GaussianBlur(source, (5,5), 0)
#显示图形
titles = ['Source Image', 'BoxFilter Image', 'Blur Image',
'Median Image', 'Guassian Image']
images = [source, img_box, img_blur, img_Guassian, img_median]
for i in range(5):
plt.subplot(2, 3, i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
参考:我跳
#encoding:utf-8
"""
@author: Dragon Liu
Operating environment: Python 3.7.1
lib: opencv-python
Date: 2020/3/16
"""
#导入库
import cv2
import numpy as np
import matplotlib.pyplot as plt
#读取图片
img = cv2.imread('02.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
#双边滤波
img_bilateral = cv2.bilateralFilter(source, 7, 50, 50)
#显示图形
titles = ['Source Image', 'bilateralFilter Image']
images = [source, img_bilateral]
for i in range(2):
plt.subplot(1, 2, i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([]) #禁止输出坐标轴
plt.show()
引导滤波的思想用一张引导图像产生权重,从而对输入图像进行处理。引导滤波除了可以用于图像平滑,还可以用于HDR压缩、细节增强、图像去雾、联合上采样等图像处理任务。引导滤波中空间域的贡献自然取决于窗口的大小,即由参数 r 决定。而标准差则是评判颜色差异性的参数,窗口中标准差越大,说明局部的像素相似性越差。
第一个代码块是手写实现引导滤波。时间复杂度O(N),当 r 与 ϵ 越大,图像被平滑的程度越大。伪代码中:r是窗口半径, f m e a n ( I , r ) f_{mean}(I,r) fmean(I,r) 表示在(r, r)窗口对图像做均值滤波。大佬博客:我跳
第二个代码块是使用的现有库。参考:我跳
# -*- coding: utf-8 -*-
"""
@First_author: 不用先生
@Second_author: Dragon Liu
Operating environment: Python 3.7.1
lib: opencv-python
Date: 2020/3/16
"""
import cv2
import numpy as np
input_fn = '03.png'
# 函数名:my_guidedFilter_oneChannel
# 函数功能:用于单通道图像(灰度图)的引导滤波函数;
# 参数:srcImg:输入图像,为单通道图像;
# 参数:guideImg:引导图像,为单通道图像,尺寸与输入图像一致;
# 参数:rad:滤波器大小r,应该保证为奇数,默认值为9;
# 参数:eps:防止a过大的正则化参数ϵ,
# 返回:dstImg:输出图像,尺寸、通道数与输入图像吻合;
def my_guidedFilter_oneChannel(srcImg, guidedImg, rad=13, eps=0.1):
# 转换数值类型,并归一化
srcImg = srcImg/255.0
guidedImg = guidedImg/255.0
img_shape = np.shape(srcImg)#查看矩阵或者数组的维数。
# 在(rad, rad)窗口的内对图像做均值滤波。
P_mean = cv2.boxFilter(srcImg, -1, (rad, rad), normalize=True) # p的均值平滑
I_mean = cv2.boxFilter(guidedImg,-1, (rad, rad), normalize=True) # I的均值平滑
I_square_mean = cv2.boxFilter(np.multiply(guidedImg, guidedImg), -1, (rad, rad), normalize=True) #I*I的均值平滑
I_mul_P_mean = cv2.boxFilter(np.multiply(srcImg, guidedImg), -1, (rad, rad), normalize=True)# I*p的均值平滑
var_I = I_square_mean-np.multiply(I_mean,I_mean)# 方差
cov_I_P = I_mul_P_mean-np.multiply(I_mean,P_mean)# 协方差
a = cov_I_P/(var_I+eps)# 相关因子a
b = P_mean-np.multiply(a,I_mean)# 相关因子b
a_mean = cv2.boxFilter(a, -1, (rad, rad), normalize=True) # 对a进行均值平滑
b_mean = cv2.boxFilter(b, -1, (rad, rad), normalize=True) # 对b进行均值平滑
dstImg = np.multiply(a_mean,guidedImg)+b_mean
return dstImg*255.0
# 函数名:my_guidedFilter_threeChannel
# 函数功能:用于三通道图像(RGB彩色图)的引导滤波函数;
# 参数:srcImg:输入图像,为三通道图像;
# 参数:guideImg:引导图像,为三通道图像,尺寸与输入图像一致;
# 参数:rad:滤波器大小r,应该保证为奇数,默认值为9;
# 参数:eps:防止a过大的正则化参数ϵ,
# 返回:dstImg:输出图像,尺寸、通道数与输入图像吻合;
def my_guidedFilter_threeChannel(srcImg, guidedImg, rad=9, eps=0.01):
img_shape = np.shape(srcImg)
dstImg = np.zeros(img_shape, dtype=float)
for ind in range(0,img_shape[2]):
dstImg[:,:,ind] = my_guidedFilter_oneChannel(srcImg[:,:,ind],
guidedImg[:,:,ind], rad, eps)
dstImg = dstImg.astype(np.uint8)
return dstImg
def main():
img = cv2.imread(input_fn)#读入图像
print( np.shape(img) )
dstimg = my_guidedFilter_threeChannel(img, img, 9 , 0.01)#输入图像作为自身的引导图
print( np.shape(dstimg) )
# cv2.imwrite('output.jpg',dstimg)
cv2.imshow('output', dstimg)
cv2.waitKey(0)
if __name__ == '__main__':
main()
# -*- coding: utf-8 -*-
"""
@First_author: Jin ZhangYu
@Second_author: Dragon Liu
Operating environment: Python 3.7.1
lib: opencv-contrib-python
Date: 2020/3/16
"""
# 导入库
import argparse
import cv2
import matplotlib.pyplot as plt
import skimage
import numpy as np
# 构造参数解析器
# ap = argparse.ArgumentParser()
# ap.add_argument("-H:\project_work\Machine_Vision_Lab\thesis\Gaussian\code", "--02.png", required=True, help = "Path to the image")
# args = vars(ap.parse_args())
# 加载图像并显示
input_fn = '02.png'
# img = cv2.imread(args["image"],1)
img = cv2.imread(input_fn)
img = img[:,:,::-1]
guide = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 进行导向滤波
dst1 = cv2.ximgproc.guidedFilter(
guide=guide, src=img, radius=16, eps=50, dDepth=-1)
dst2 = cv2.ximgproc.guidedFilter(
guide=guide, src=img, radius=16, eps=200, dDepth=-1)
dst3 = cv2.ximgproc.guidedFilter(
guide=guide, src=img, radius=16, eps=1000, dDepth=-1)
# 绘制图片
images = [img,[dst1,dst2,dst3]]
titles = [
'Original',
['Guided Filter eps=50','Guided Filter eps=200','Guided Filter eps=1000']
]
# 绘制原图
plt.figure(figsize=(9,4))
plt.subplot(2, 3, 2),plt.imshow(images[0])
plt.title(titles[0], fontsize=10),plt.xticks([]), plt.yticks([])
plt.subplot(2, 3, 4),plt.imshow(images[1][0])
plt.title(titles[1][0], fontsize=10),plt.xticks([]), plt.yticks([])
plt.subplot(2, 3, 5),plt.imshow(images[1][1])
plt.title(titles[1][1], fontsize=10),plt.xticks([]), plt.yticks([])
plt.subplot(2, 3, 6),plt.imshow(images[1][2])
plt.title(titles[1][2], fontsize=10),plt.xticks([]), plt.yticks([])
# plt.savefig('1_out.png', transparent=True, dpi=300, pad_inches = 0)
plt.show()
通过下采样减少像素点,计算mean_a & mean_b后进行上采样恢复到原有的尺寸大小。假设缩放比例为s,那么缩小后像素点的个数为 N s 2 \frac {N}{s^2} s2N ,那么时间复杂度变为 O ( N s 2 ) O(\frac {N}{s^2}) O(s2N) 。伪代码中:fmean代表均值平滑,fsubsample代表图像下采样即缩小图像,fupsample代表图片上采样即放大图像,s为缩小系数。参考:我跳
# -*- coding: utf-8 -*-
"""
@First_author: SongpingWangSongpingWangs
@Second_author: Dragon Liu
Operating environment: Python 3.7.1
lib: opencv-python
Date: 2020/3/16
"""
import cv2
import numpy as np
def guideFilter(I, p, winSize, eps, s):
# 输入图像的高、宽
h, w = I.shape[:2]
# 缩小图像
size = (int(round(w * s)), int(round(h * s)))
small_I = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)
small_p = cv2.resize(I, size, interpolation=cv2.INTER_CUBIC)
# 缩小滑动窗口
X = winSize[0]
small_winSize = (int(round(X * s)), int(round(X * s)))
# I的均值平滑 p的均值平滑
mean_small_I = cv2.blur(small_I, small_winSize)
mean_small_p = cv2.blur(small_p, small_winSize)
# I*I和I*p的均值平滑
mean_small_II = cv2.blur(small_I * small_I, small_winSize)
mean_small_Ip = cv2.blur(small_I * small_p, small_winSize)
# 方差、协方差
var_small_I = mean_small_II - mean_small_I * mean_small_I
cov_small_Ip = mean_small_Ip - mean_small_I * mean_small_p
small_a = cov_small_Ip / (var_small_I + eps)
small_b = mean_small_p - small_a * mean_small_I
# 对a、b进行均值平滑
mean_small_a = cv2.blur(small_a, small_winSize)
mean_small_b = cv2.blur(small_b, small_winSize)
# 放大
size1 = (w, h)
mean_a = cv2.resize(mean_small_a, size1, interpolation=cv2.INTER_LINEAR)
mean_b = cv2.resize(mean_small_b, size1, interpolation=cv2.INTER_LINEAR)
q = mean_a * I + mean_b
return q
if __name__ == '__main__':
eps = 0.01
winSize = (16,16) #类似卷积核(数字越大,磨皮效果越好)
image = cv2.imread(r'02.png', cv2.IMREAD_ANYCOLOR)
image = cv2.resize(image,None,fx=0.8,fy=0.8,interpolation=cv2.INTER_CUBIC)
I = image/255.0 #将图像归一化
p =I
s = 3 #步长
guideFilter_img = guideFilter(I, p, winSize, eps,s)
# 保存导向滤波结果
guideFilter_img = guideFilter_img * 255 #(0,1)->(0,255)
guideFilter_img[guideFilter_img > 255] = 255 #防止像素溢出
guideFilter_img = np.round(guideFilter_img )
guideFilter_img = guideFilter_img.astype(np.uint8)
cv2.imshow("image",image)
cv2.imshow("winSize_16", guideFilter_img )
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.Sobel()
, cv2.Schar()
, cv2.Laplacian()
Sobel, scharr其实是求一阶或者二阶导数。scharr是对Sobel的优化。 Laplacian是求二阶导数。cv2.Sobel() 是一种带有方向过滤器。参考:我跳# -*- coding: utf-8 -*-
"""
@First_author: SongpingWang
@Second_author: Dragon Liu
Operating environment: Python 3.7.1
lib: opencv-python
Date: 2020/3/16
"""
"""
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
src: 需要处理的图像;
ddepth: 图像的深度,-1表示采用的是与原图像相同的深度。
目标图像的深度必须大于等于原图像的深度;
dx和dy: 求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
dst 不用解释了;
ksize: Sobel算子的大小,必须为1、3、5、7。 ksize=-1时,会用3x3的Scharr滤波器,
它的效果要比3x3的Sobel滤波器要好
scale: 是缩放导数的比例常数,默认没有伸缩系数;
delta: 是一个可选的增量,将会加到最终的dst中, 默认情况下没有额外的值加到dst中
borderType: 是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
"""
import cv2
img=cv2.imread('02.png',cv2.IMREAD_COLOR)
x=cv2.Sobel(img,cv2.CV_16S,1,0)
y=cv2.Sobel(img,cv2.CV_16S,0,1)
absx=cv2.convertScaleAbs(x)
absy=cv2.convertScaleAbs(y)
dist=cv2.addWeighted(absx,0.5,absy,0.5,0)
cv2.imshow('original_img',img)
cv2.imshow('y',absy)
cv2.imshow('x',absx)
cv2.imshow('dsit',dist)
cv2.waitKey(0)
cv2.destroyAllWindows()
function result = gr(px, py, qx, qy, dr)
% 高斯空间核函数
result = exp( - ( (qx - px)^2 + (qy - py)^2 ) / (2 * dr^2) );
end
function result = gzeta(guide_img, div, px, py, qx, qy, dzeta)
% 高斯频域核函数
result = exp( - ( ( guide_img(px, py, div) - guide_img(qx, qy, div) )^2 ) / (2 * dzeta^2) );
end
function output = GS(image, r, dr, px, py, div)
% 求解高斯空间域滤波,返回指定像素点(p)的输出
Upsilon = 0;%τ,归一化系数
output = 0;
for i = -r : r % 以p为中心的窗口半径为2r+1的区域
for j = -r : r
Upsilon = Upsilon + gr(px, py, px + i, py + j, dr);
output = output + gr(px, py, px + i, py + j, dr) * image(px + i,py + j,div);
end
end
output = output / Upsilon ;
end
function output = WGGF(guide_img, source, r, dzeta, px, py, div, lambda)
% 窗口感知的高斯引导滤波
%求解WGGF在每个像素点p的输出并返回
Upsilon = 0;%τ,归一化系数
output = 0;
flag = 0;
for i = -r : r
for j = -r : r
temp = abs( guide_img(px + i, py + 1, div) - guide_img(px, py, div) );
if temp <= lambda
flag = flag + 1;
Upsilon = Upsilon + gzeta(guide_img, div, px, py, px+i, py+j, dzeta);
output = output + guide_img(px + i,py + j,div) * gzeta(guide_img, div, px, py, px+i, py+j, dzeta);
end
end
end
if flag == 1 %不满足窗口感知的要求,返回3*3窗口中的像素点中值
output = medfilt2( source( (px - 1):(px + 1), (py - 1):(py + 1), j), [3,3] );
else %满足条件
output = output / Upsilon ;
end
end
%% 读取图片
source = im2double( imread('01.jpg') );
guide_img = source;
%% 求解高斯引导滤波
[m ,n, div] = size(source);
r = 5; %窗口半径
dr = 0.5; %空域带宽
for k = 1 : div
for i = 1 : m
for j = 1 : n
if i <= r || i >= m - r || j <= r || j >= n - r %图片四周处理(原像素)
continue;
else
guide_img(i,j,k) = GS(source, r, dr, i, j, k); %空间域滤波
end
end
end
end
%% 求解WGGF
target = guide_img;
r = 5; %窗口半径
dzeta = 0.1; %频域带宽
lambda = 0.12; % λ为一选定的阈值
for k = 1 : div
for i = 1 : m
for j = 1 : n
if i <= r || i >= m - r || j <= r || j >= n - r%图片四周处理(引导像素)
continue;
else
target(i, j, k) = WGGF(guide_img, source, r, dzeta, i, j, k, lambda);
end
end
end
end
%% 显示图形
figure;
subplot(1,2,1), imshow(source), title('Source image');
subplot(1,2,2), imshow(target), title('WGGF image');
#encoding:utf-8
"""
@author: Dragon Liu
Operating environment: Python 3.7.1
lib: opencv-python
Date: 2020/3/22
BUG: 时间复杂度O(m*n*div*r*r),不可行,另外存在img[]访问问题
"""
#导入库
import math
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 高斯空间核函数
def gr(px, py, qx, qy, dr):
nut = math.exp( - ( pow((qx - px), 2) + pow((qy - py), 2) ) ) #分子
det = 2 * pow(dr, 2) #分母
result = nut / det
return result
# 高斯频域核函数
def gzeta(guide_img, div, px, py, qx, qy, dzeta):
guide_img = guide_img
nut = math.exp( - ( pow( ( guide_img[px, py, div] - guide_img[qx, qy, div] ), 2 ) ) ) #分子
det = 2 * pow(dzeta, 2)
result = nut / det
return result
# 求解高斯空间域滤波,返回指定像素点(p)的输出
def GS(image, r, dr, px, py, div):
Upsilon = 0 #τ,归一化系数
output = 0
for i in range(r, -(r+1), -1):# 以p为中心的窗口半径为2r+1的区域
for j in range(r, -(r+1), -1):
Upsilon = Upsilon + gr(px, py, px + i, py + j, dr)
output = output + gr(px, py, px + i, py + j, dr) * image[px + i,py + j,div]
output = output / Upsilon
return output
#求解指定窗口(3*3)的中值
def medbox(img, x, y, div, length, width):
nums = []
length = width = 3
for i in range(math.floor(length/2), -math.floor(length/2)-1, -1):
for j in range(math.floor(width/2), -math.floor(width/2)-1, -1):
nums.append( img[x+i, y+j, div])
return np.median(nums)
#窗口感知的高斯引导滤波
#求解WGGF在每个像素点p的输出并返回
def WGGF(guide_img,source,r,dzeta,px,py,div, lam):
guide_img = guide_img
source = source
Upsilon = 0 #τ,归一化系数
output = 0
flag = 0
for i in range(r, -(r+1), -1):# 以p为中心的窗口半径为2r+1的区域
for j in range(r, -(r+1), -1):
temp = abs( guide_img[px + i, py + 1, div] - guide_img[px, py, div] )
if temp <= lam:
flag = flag + 1
Upsilon = Upsilon + gzeta(guide_img, div, px, py, px+i, py+j, dzeta)
output = output + guide_img[px + i,py + j,div] * gzeta(guide_img, div, px, py, px+i, py+j, dzeta)
if flag == 1 or Upsilon == 0: #不满足窗口感知的要求,返回3*3窗口中的像素点中值
output = medbox( source, px, py, j, 3, 3 )
else: #满足条件
output = output / Upsilon
return output
# 主函数,测试
def main():
#读取图片
img = cv2.imread('02.png', 1)
source = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
source = source / 255.0
guide_img = source
print(1.666)
#求解高斯引导滤波
[m ,n, div] = np.shape(source)#查看矩阵或者数组的维数。
r = 5 #窗口半径
dr = 0.5 #空域带宽
# 高斯滤波
guide_img = cv2.GaussianBlur(source, (r,r), dr)
print(2.666)
#求解WGGF
target = guide_img
r = 5 #窗口半径
dzeta = 0.1 #频域带宽
lam = 0.12 #λ为一选定的阈值
num = 0
for k in range(div):
for i in range(m):
for j in range(n):
if i <= r or i >= m - r or j <= r or j >= n - r: #图片边界处理(引导像素)
continue
else:
target[i, j, k] = WGGF(guide_img, source, r, dzeta, i, j, k, lam)
num = num + 1
print(num)
print(3.666)
#显示图形
titles = ['Source Image', 'WGGF Image']
images = [source*255.0, target*255.0]
for i in range(2):
plt.subplot(1, 2, i+1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([]) #禁止输出坐标轴
plt.show()
if __name__ == '__main__':
main()