数字图像处理–卷积运算
1、主要内容
(1)自己编写一维卷积和二维卷积运算程序;
(2)用Python自带的一维卷积和二维卷积函数实现卷积运算;
(3)对比(1)(2)结果,对自己编写的运算程序进行修改和优化。
2、源代码
import cv2
import matplotlib.pyplot as plt
import scipy.signal
import torch
print('==========================一维卷积=========================')
#一维卷积
G = [1,2,3,4,5,6,7,8,9]
H = [-1,0,1]
F = []
F_optim = []
#自定义一维卷积函数
def conv1d(vector,kernel):
for i in range(len(vector)):
if i == 0:
x = kernel[-1]*vector[i]
F.append(x)
elif i == 1:
x = kernel[-1]*vector[i] + kernel[-2]*vector[i-1]
F.append(x)
elif 1<i<9:
x = kernel[-1]*vector[i] + kernel[-2]*vector[i-1] + kernel[-3]*vector[i-2]
F.append(x)
# elif i == 8:
# x = kernel[-1]*vector[i] + kernel[-2]*vector[i-1] + kernel[-3]*vector[i-2]
# F.append(x)
# # elif i == 10:
# x = kernel[-3]*vector[i-2]
# F.append(x)
return F
#修改原始自定义一维卷积
def optim_conv1d(vector,kernel):
for i in range(len(vector)+2):
if i == 0:
x = kernel[-1]*vector[i]
F_optim.append(x)
elif i == 1:
x = kernel[-1]*vector[i] + kernel[-2]*vector[i-1]
F_optim.append(x)
elif 1<i<9:
x = kernel[-1]*vector[i] + kernel[-2]*vector[i-1] + kernel[-3]*vector[i-2]
F_optim.append(x)
elif i == 9:
x = kernel[-2]*vector[i-1] + kernel[-3]*vector[i-2]
F_optim.append(x)
elif i == 10:
x = kernel[-3]*vector[i-2]
F_optim.append(x)
return F_optim
F = conv1d(G , H)
print(' conv1d-自定义')
print(F)
F_optim = optim_conv1d(G , H)
print(' optim_conv1d-自定义')
print(F_optim)
#调用一维卷积函数
print(' conv1d-库自带')
print(scipy.signal.convolve(G, H))
print('==========================二维卷积=========================')
#二维卷积
#频域卷积 = 空域相乘
#读取源图像像素
rose = cv2.imread('2.png',0)
print(' rose')
print(rose)
#定义卷积核
H_2d = [[1,1,1],[1,2,1],[1,1,1]]
#最大最小归一化
def maxmin_norm(array):
maxcols = array.max(axis = 0)
mincols = array.min(axis = 0)
data_shape = array.shape
data_rows, data_cols = data_shape
t = np.empty((data_rows, data_cols))
for i in range(data_cols):
t[:, i] = (array[:, i] - mincols[i]) / (maxcols[i] - mincols[i])
return t
#自定义二维卷积函数
def conv2d(x,kernel):
x = rose.shape
#填充
big_rose = np.zeros((x[0] + 2, x[1] + 2))
big_rose[1:big_rose.shape[0] - 1, 1:big_rose.shape[1] - 1] = rose
new_list = []
for i in range(len(kernel)):
for j in range(len(kernel)):
x = kernel[i][j] / 10
new_list.append(x)
new_list = np.matrix(new_list)
kernel = new_list.reshape(3, 3)
print(' kernel')
print(kernel)
for i in range(big_rose.shape[0] - 2):
for j in range(big_rose.shape[1] - 2):
sum = big_rose[i + 1][j + 1]*kernel[1,1] + big_rose[i + 1 + 1][j + 1]*kernel[2,1]+ \
big_rose[i + 1 - 1][j + 1]*kernel[0,1] + big_rose[i + 1][j + 1 + 1]*kernel[1,2] + \
big_rose[i + 1][j + 1 - 1] *kernel[1,0]+ big_rose[i + 1 - 1][j + 1 - 1]*kernel[0,0] + \
big_rose[i + 1 + 1][j + 1 + 1]*kernel[2,2] + big_rose[i + 1 - 1][j + 1 + 1]*kernel[0,2] + \
big_rose[i + 1 + 1][j + 1 - 1]*kernel[2,0]
big_rose[i + 1][j + 1] = sum
sum = 0
#print('After_big_rose:', big_rose)
After_rose = big_rose[1:big_rose.shape[0] - 1, 1:big_rose.shape[1] - 1]
#归一化
After_rose = maxmin_norm(After_rose)
return After_rose
#修改自定义二维卷积函数并加以优化
def Conv2d_Optim(image, mfilter):
mI, nI = np.shape(image)
[mF, nF] = np.shape(mfilter)
height = int(mF / 2)
width = int(nF / 2)
#源图像
convImage = np.zeros((mI, nI))
#填充
if mF % 2 == 0:
imData = np.pad(image,(width, width - 1),'constant')
else:
imData = np.pad(image,(width, height),'constant')
padmI, padnI = imData.shape
convHeight = padmI - mF + 1
convWidth = padnI - nF + 1
#开始卷积
for i in range(convHeight):
for j in range(convWidth):
localImage = imData[i:i + mF, j:j + nF]
convImage[i][j] = np.sum(localImage * mfilter)
#大于255 赋值为255
#小于0 赋值为0
convImage1 = convImage.clip(0, 255)
return convImage1
#库自带二维卷积函数
rose = torch.from_numpy(rose)
scharr=np.array([[-3-3j,0-10j,+3-3j],[-10+0j,0+0j,+10+0j],[-3+3j,0+10j,+3+3j]]) #设置一个特殊的卷积和
#scharr = np.array([[0,0,0],[-1,1,0],[0,0,0]])
rose_conv2d = scipy.signal.convolve2d(rose,scharr,boundary='symm',mode='same')
rose_conv2d = maxmin_norm(rose_conv2d)
print(' rose_conv2d')
print(rose_conv2d)
After_rose = conv2d(rose,H_2d)
print(' After_conv2d_rose')
print(After_rose)
filter1 = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]]
After_conv2d_Optim = Conv2d_Optim(rose,filter1)
print(' After_conv2d_Optim_rose')
print(After_conv2d_Optim)
plt.subplot(221),plt.imshow(rose,cmap = 'gray'),plt.title('Original')
plt.subplot(222),plt.imshow(After_rose,cmap = 'gray'),plt.title('Conv2d-Normalize')
plt.subplot(223),plt.imshow(rose_conv2d,cmap = 'gray'),plt.title('Conv2d-Function')
plt.subplot(224),plt.imshow(After_conv2d_Optim,cmap = 'gray'),plt.title('Conv2d-Optim')
plt.show()
3、实现结果
3.1 一维卷积
本实验中,针对一维卷积,自定义一维卷积函数所选取得到数据源是一个简单的Vector([1,2,3,4,5,6,7,8,9]),卷积核为([-1,0,1])。对数据源进行一维卷积结果如下所示。
得出结果后,调用了库函数scipy.signal.convolve()对该数据源进行卷积。
通过对库自带函数的分析可得,库自带一维卷积函数用的卷积核是([1,0,-1]),并对数据进行了填充,对边缘元素也进行了卷积运算。
因此,对自定义一维函数进行了边缘考虑。其修改后的一维卷积函数对数据源进行卷积,运行结果如下所示。
3.2 二维卷积
本实验中,针对二维卷积,读取了一幅尺寸为(1200*675)大小的灰度图像,并自定义二维卷积函数对该图像进行了边缘零填充,并进行了二维卷积运算,最后,用了最大最小归一化处理。其操作运算结果,如下图所示。
自定义二维卷积对图像主体有增强作用,起到了平滑作。接着,本实验调用了scripy.signal.convolve2d()函数,完成了对源数据图像的二维卷积,其卷积结果如下图所示。
从上述卷积结果图中,各个像素的灰度值都比较小,但是轮廓结果还是比较清晰的,起到了边缘检测的效果。因此,对自定义二维卷积函数进行了修改。首先是,将原来的卷积核([[1,1,1],[1,2,1],[1,1,1]])更改为了([[-1,-2,-1],[0,0,0],[1,2,1]]);其次,并且在卷积以后进行了限制灰度值在(0,255)之间的规范化。其修改结果如下图所示。
从上图可知,修改后的二维卷积函数也实现了边缘检测功能,对比先前起到平滑作用的卷积效果来说。卷积核如何设置决定了卷积后的效果。
小白记录!!!