欢迎来到爱学习小可爱的“数字图像处理”入门编程小天地
手写卷积函数&改变图像边缘 编程目的通过编写卷积函数以及对图像边缘像素处理,实现输出分辨率大小不变但改变效果的图片的功能。
ps:
第一次写博客~
激动的心,颤抖的手,手误的地方宁请担待,慢慢改善排版哦吼~
编程核心代码基于算法,没有调用成品函数~ 如果感兴趣的话,就继续往下看吧~ 欢迎各位和我一起交流!如有引用,请标明来源哦!https://blog.csdn.net/qq_43836026/article/details/105470175
1. 卷积运算改变图片各点像素值
在图像处理中,数字图像是一个二维的离散信号,对数字图像做卷积操作是利用卷积核在图像上滑动,将图像点上的像素灰度值与对应的卷积核上的数值相乘,然后将所有相乘后的值相加作为卷积核右上角点对应的图像上像素的灰度值,并最终滑动完所有图像的过程,最终实现改变图像效果。
经观察得:
若输入图像分辨率为iw*ih, 卷积核大小为fw*fh,此计算方法会使得输出图像fw分辨率为(iw-fw+1)*(ih-fh+1),即分辨率变小,并且图像边缘像素点大小不真实,为使其输出图像分辨率大小不变,需将输入图像边缘进行填充。
2. 图像边缘填充处理
2.1 输出图像分辨率大小不变
不加填充时,输出图分辨率为(iw-fw+1)*(ih-fh+1),为使输出图像大小不变,需填充(fw-1)行和(fh-1)列。由于卷积操作是将卷积核右上角点对应图像上像素,所以将填充的行列至于左边缘和下边缘。如图示:
在左边缘填充了(fh-1)列,在下边缘填充了(fw-1)列,可实现输出的图像分辨率为iw*iw。
填充边缘后还需确定边缘像素的像素值,所以接下来我们考虑以下3种数字填充方法。
2.2 填充边缘的数字置0
2.3 图像沿边沿作镜像对称
2.4 按比例调整图像内部的滤波器的权重
如果觉得这里比较乱,可以跳过,代码里也有详细注释~
1.没心没肺必有我主函数~
if __name__ =='__main__':
#------读入图像和卷积核---------#
Img=cv.imread(file_in,0)
#Img = np.array([[10, 12, 3, 7], [4, 5, 8, 15], [9, 2, 6, 19],[10,7,20,8]])
# print('原始图像:\n',Img)
F = np.ones((3,3))*(1/9)
#F = np.ones((2, 2)) * (1 / 4)
iw,ih = Img.shape
fw,fh = F.shape
#---------卷积函数处理-----------#
Out_img1=Convolve0(Img,F,iw,ih,fw,fh)
Out_img2=Convolve_mirror(Img,F,iw,ih,fw,fh)
Out_img3=Convolve_F_value(Img,F,iw,ih,fw,fh)
# print('原图像大小\n',Img.shape)
# print('填充0后新图像大小\n',Out_img1.shape)
# print('镜像对称后新图像\n',Out_img2.shape)
# print('调整卷积核后新图像\n',Out_img3.shape)
#----------显示并保存图像---------#
cv.imshow('0',Out_img1)
cv.imshow('mirror', Out_img2)
cv.imshow('change F_value', Out_img3)
cv.imwrite(file_out1,Out_img1)
cv.imwrite(file_out2, Out_img2)
cv.imwrite(file_out3,Out_img3)
cv.waitKey(0)
cv.destroyAllWindows()
主函数中包含了测试代码~
2.边缘置0的卷积函数,流程较为简单,易上手,写完以后可以先测试一波~增强信心!
#------------边缘置0-------------#
def Convolve0(Img,F,iw,ih,fw,fh):
#---------创建新全0数组-------#
New_I = np.zeros((iw+fw-1,ih+fh-1)) .astype(np.float32)
#--------原图像像素值对应到新图像中----#
for i in range (iw):
for j in range(ih):
New_I[i,j+fh-1]=Img[i,j]
#print('填充0后:\n',New_I)
New_Img = np.zeros((iw,ih)).astype(np.float32)
#--------进行卷积运算----------#
for i in range (iw):
for j in range (ih):
Img_F = New_I[i:i+fw,j:j+fh]
temp = np.multiply(Img_F,F)
New_Img[i,j]=temp.sum()
#print(New_Img)
New_Img=New_Img.astype(np.uint8)
#print(New_Img)
return New_Img
3.镜像对称情况相对复杂一丢丢,在思考镜像对称,两列(行)对称时,他们的列(行)的关系!博主当时绞尽脑汁,废了77 41张草纸演算,终于想明白了!
#----------镜像对称-----------#
def Convolve_mirror(Img,F,iw,ih,fw,fh):
# ---------创建新全0数组-------#
New_I = np.zeros((iw + fw - 1, ih + fh - 1)).astype(np.float32)
# --------原图像像素值对应到新图像中----#
for i in range(iw):
for j in range(ih):
New_I[i, j + fh - 1] = Img[i, j]
#-------将新增的行做镜像对称--------#
for i in range (1,fw):
#New_I[-i,:]=New_I[-(2*fw-1)+i,:]
New_I[-i, :] = New_I[-(2 * fw ) + i, :]
# -------将新增的列做镜像对称--------#
for j in range(0,fh-1):
#New_I[:,j]=New_I[:,2*fh-3-j]
New_I[:, j] = New_I[:, 2 * fh - 2 - j]
#print('镜像对称后:\n',New_I)
# --------进行卷积运算----------#
New_Img = np.zeros((iw, ih)).astype(np.float32)
for i in range(iw):
for j in range(ih):
Img_F = New_I[i:i + fw, j:j + fh]
temp = np.multiply(Img_F, F)
New_Img[i, j] = temp.sum()
#print(New_Img)
New_Img = New_Img.astype(np.uint8)
#print(New_Img)
return New_Img
4.调整卷积核函数,这种情况最为复杂,在边缘的地方,改变卷积核的值,一方面要确定哪些变成0,另一方面需要确定非0的值。这里我分了两种情况,具体分类可见流程图!!当时码完这里,我对着我家门前的小鸟喊了一嗓子以表开心之情!
#-----------调整卷积核----------#
def Convolve_F_value(Img,F,iw,ih,fw,fh):
# ---------创建新全0数组-------#
New_I = np.zeros((iw + fw - 1, ih + fh - 1)).astype(np.float32)
# --------原图像像素值对应到新图像中----#
for i in range (iw):
for j in range(ih):
New_I[i,j+fh-1]=Img[i,j]
New_Img = np.zeros((iw, ih)).astype(np.float32)
#--------在原图像的位置时------#
for i in range(iw):
for j in range(ih):
Img_F = New_I[i:i + fw, j:j + fh]
temp = np.multiply(Img_F, F)
New_Img[i, j] = temp.sum()
#--------在补充的列时--------#
for i in range(0,iw-1):
for j in range (0,fh-1):
Img_F = New_I[i:i+fw,j:j+fh]
New_F1 = F_Value1(F,j,fw,fh)
temp = np.multiply(Img_F,New_F1)
New_Img[i,j]=temp.sum()
# --------在补充的列行时--------#
for i in range (iw-fw+1,iw):
for j in range(0,ih):
Img_F = New_I[i:i+fw,j:j+fh]
New_F2 = F_Value2(F,i,fw,fh)
temp = np.multiply(Img_F,New_F2)
New_Img[i,j] = temp.sum()
New_Img = New_Img.astype(np.uint8)
# print(New_Img)
return New_Img
这里就是根据不同情况具体修改卷积核的代码啦
#-----在左边缘时调整卷积核------#
def F_Value1(F,j,fw,fh):
for n in range (0,fh-j-1):
F[:,n]=0
Sum = F.sum()
for m in range (0,fw):
for k in range (1,j+2):
F[m,-k]=F[m,-k]/Sum
return F
#-----在下边缘时调整卷积核------#
def F_Value2(F,i,fw,fh):
for n in range (1,fw-(iw-i)+1):
F[-n,:]=0
Sum = F.sum()
for m in range (0,fh):
for k in range (0,fw):
F[k,m]=F[k,m]/Sum
return F
代码测试
最紧张最刺激的环节莫过于此了!!!!
数组带入测试特别有趣,也是最能直观反应代码成功与否的指标!
这么有意思的环节就不展示了,还是需要有一点神秘感,让你们亲自去体会“柳暗花明又一村”的激动!(博主当时错了改改了试完完全全就是这么个心态)
除了数组,少不了图片测试嘛
图片测试
大小
通过执行代码,可得到与输入图像分辨率大小一样,且改变效果的图像。将三种卷积函数对应的输出图像进行比较,可以得知:
1.该卷积核可使图像变得模糊。
2.边缘置0时,输出图像左边缘和下边缘有黑边,出现了失真的情况。
3.镜像对称和改变卷积核对应的输出图像效果较好。
手写卷积就结束了,回看思路和程序,还是改善之处的,比如对RGB图像进行卷积。
不过,做到这里让我们一起大喊 奥里给!!