Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyibadou authored May 8, 2024
1 parent 7257121 commit c30fab5
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 0 deletions.
155 changes: 155 additions & 0 deletions 226+陈易+武汉/11.canny_detail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import numpy as np
import matplotlib.pyplot as plt
import math

if __name__ == "__main__":
pic_path = "lenna.png"
img = plt.imread(pic_path)
print("样本集img\n",img)
if pic_path[-4:] == ".png": # [-4:] 切片,截取倒数第4位至最后一位
# .png图片在这里的存储格式是0到1的浮点数,所以要扩展到255再计算
img = img * 255 # 还是浮点数类型
img = img.mean(axis = -1) # 取均值的方法进行灰度化
print("样本集img灰度化\n", img)

# 1.高斯平滑
# sigma = 1.52 高斯平滑时的高斯核参数,标准差,可调
sigma = 0.5
dim = 5 # 高斯核尺寸
Gaussion_filter = np.zeros([dim,dim]) # 储存高斯核,这是数组,不是列表
tmp = [i - dim//2 for i in range(dim)] # 生成一个序列
print("tmp:",tmp)
# 计算高斯核,公式:n1为e左侧数据,n2为e的指数数据。math.pi:圆周率π
n1 = 1/(2 * math.pi * sigma**2)
n2 = -1/(2 * sigma**2)
for i in range(dim):
for j in range(dim): # math.exp:e的幂次方
Gaussion_filter[i,j] = n1 * math.exp(n2*(tmp[i]**2 + tmp[j]*22))
# 1)归一化后加快了梯度下降求最优解的速度;2)归一化有可能提高精度(如KNN)
Gaussion_filter = Gaussion_filter / Gaussion_filter.sum() # 归一化

dx,dy = img.shape # 获取原图的行列数
print("dx:",dx,"\ndy:",dy)
img_new = np.zeros(img.shape) # 储存平滑后的图像,zeros函数得到的是浮点型数据
""" np.pad()图像边缘填充技术,
即在图像四周边缘填充0,使得卷积运算后图像大小不会缩小,同时也不会丢失边缘和角落的信息
在卷积神经网络中,通常采用constant填充方式"""
r = dim//2 # 高斯核半径为2
img_pad = np.pad(img,((r,r),(r,r)),"constant")
for i in range(dx):
for j in range(dy):
img_new[i,j] = np.sum(img_pad[i:i+dim,j:j+dim] * Gaussion_filter)
plt.figure(1)
plt.imshow(img_new.astype(np.uint8),cmap="gray") # 此时的img_new是255的浮点型数据,强制类型转换才可以,gray灰阶
plt.axis("off")
# plt.show()

# 2、求梯度。以下两个是滤波用的sobel矩阵(检测图像中的水平、垂直和对角边缘)
sobel_kernel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
sobel_kernel_y = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]])
img_tidu_x = np.zeros(img_new.shape)
img_tidu_y = np.zeros([dx,dy])
img_tidu = np.zeros(img_new.shape)
img_pad = np.pad(img_new,((1,1),(1,1)),"constant")
for i in range(dx):
for j in range(dy):
img_tidu_x[i,j] = np.sum(img_pad[i:i+3,j:j+3]*sobel_kernel_x) # X方向
img_tidu_y[i,j] = np.sum(img_pad[i:i+3,j:j+3]*sobel_kernel_y) # Y方向
img_tidu[i,j] = np.sqrt(img_tidu_x[i,j]**2 + img_tidu_y[i,j]**2)
img_tidu_x[img_tidu_x == 0] = 0.000000001
tan = img_tidu_y/img_tidu_x
print("tan:\n",tan)
plt.figure(2)
plt.imshow(img_tidu.astype(np.uint8),cmap="gray")
plt.axis("off")
# plt.show()

# 3、非极大值抑制
img_yizhi = np.zeros(img_tidu.shape)
print("img_yizhi:\n",img_yizhi)
for i in range(1,dx - 1): # 没有做np.pad 所以边缘像素点要去掉
for j in range(1,dy - 1): # 没有做np.pad 所以边缘像素点要去掉
flag = True # 在8个邻域内是否要抹去做个标记
temp = img_tidu[i-1:i+2, j-1:j+2] # 梯度幅值的8邻域矩阵
if tan[i,j] <= -1:
num_1 = (temp[0,1] - temp[0,0])/tan[i,j] + temp[0,1]
num_2 = (temp[2,1] - temp[2,2])/tan[i,j] + temp[2,1]
if not (img_tidu[i,j] > num_1 and img_tidu[i, j] > num_2):
flag = False
elif tan[i,j] >= 1:
num_1 = (temp[0,2] - temp[0,1])/tan[i,j] + temp[0,1]
num_2 = (temp[2,0] - temp[2,1])/tan[i,j] + temp[2,1]
if not (img_tidu[i, j] > num_1 and img_tidu[i, j] > num_2):
flag = False
elif tan[i,j] > 0:
num_1 = (temp[0,2] - temp[1,2])/tan[i,j] + temp[1,2]
num_2 = (temp[2,0] - temp[1,0])/tan[i,j] + temp[1,0]
if not (img_tidu[i, j] > num_1 and img_tidu[i, j] > num_2):
flag = False
elif tan[i,j]:
num_1 = (temp[1,0] - temp[0,0])/tan[i,j] + temp[1,0]
num_2 = (temp[1,2] - temp[2,2])/tan[i,j] + temp[1,2]
if not (img_tidu[i, j] > num_1 and img_tidu[i, j] > num_2):
flag = False
if flag:
img_yizhi[i,j] = img_tidu[i,j]
print("img_yizhi后:\n", img_yizhi)
plt.figure(3)
plt.imshow(img_yizhi.astype(np.uint8),cmap="gray")
plt.axis("off")
# plt.show()

# 4、双阈值检测,链接边缘。遍历所有一定是边的点,查看8邻域是否存在可能是边的点
lower_boundary = img_tidu.mean() * 0.5
high_boundary = lower_boundary * 3
zhan = []
for i in range(1,img_yizhi.shape[0]-1): # 外圈不考虑了
for j in range(1,img_yizhi.shape[1]-1):
if img_yizhi[i,j] >= high_boundary: # 大于高阈值为强边缘,留
img_yizhi[i,j] = 255
zhan.append([i,j])
elif img_yizhi[i,j] <= lower_boundary: # 小于低阈值不是边缘
img_yizhi[i,j] = 0

while not len(zhan) == 0:
temp_1,temp_2 = zhan.pop()
a = img_yizhi[temp_1-1:temp_1+2, temp_2-1:temp_2+2]
print("a:\n",a)
"""
小于高阈值并且大于低阈值为弱边缘,弱化边缘周围8邻域有强边缘,则保留为真是边缘,
逆向思考,强边缘的8邻域周围有弱边缘,则保留该弱边缘,记录为强边缘
"""
if (a[0, 0] < high_boundary) and (a[0, 0] > lower_boundary):
img_yizhi[temp_1 - 1, temp_2 - 1] = 255 # 这个像素点标记为边缘
zhan.append([temp_1 - 1, temp_2 - 1]) # 进栈
if (a[0, 1] < high_boundary) and (a[0, 1] > lower_boundary):
img_yizhi[temp_1 - 1, temp_2] = 255
zhan.append([temp_1 - 1, temp_2])
if (a[0, 2] < high_boundary) and (a[0, 2] > lower_boundary):
img_yizhi[temp_1 - 1, temp_2 + 1] = 255
zhan.append([temp_1 - 1, temp_2 + 1])
if (a[1, 0] < high_boundary) and (a[1, 0] > lower_boundary):
img_yizhi[temp_1, temp_2 - 1] = 255
zhan.append([temp_1, temp_2 - 1])
if (a[1, 2] < high_boundary) and (a[1, 2] > lower_boundary):
img_yizhi[temp_1, temp_2 + 1] = 255
zhan.append([temp_1, temp_2 + 1])
if (a[2, 0] < high_boundary) and (a[2, 0] > lower_boundary):
img_yizhi[temp_1 + 1, temp_2 - 1] = 255
zhan.append([temp_1 + 1, temp_2 - 1])
if (a[2, 1] < high_boundary) and (a[2, 1] > lower_boundary):
img_yizhi[temp_1 + 1, temp_2] = 255
zhan.append([temp_1 + 1, temp_2])
if (a[2, 2] < high_boundary) and (a[2, 2] > lower_boundary):
img_yizhi[temp_1 + 1, temp_2 + 1] = 255
zhan.append([temp_1 + 1, temp_2 + 1])

# 经过强边缘检测完毕后,要么为0,要么为255。还有不在强边缘周边的点,均定义为非边缘。
for i in range(img_yizhi.shape[0]):
for j in range(img_yizhi.shape[1]):
if img_yizhi[i,j] != 0 and img_yizhi[i,j] != 255:
img_yizhi[i,j] = 0
plt.figure(4)
plt.imshow(img_yizhi.astype(np.uint8),cmap='gray')
plt.axis('off')
plt.show()
18 changes: 18 additions & 0 deletions 226+陈易+武汉/12.canny.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# encoding = UTF-8

import cv2
import numpy as np

"""
cv2.Canny(image, threshold1, threshold2,[,edges[,aperureSize[,L2gradient ]]])
必要参数:
第一个参数是需要处理的原图像,该图像必须为单通道的灰度图;
第二个参数是阈值1;
第三个参数是阈值2。
"""

img = cv2.imread("lenna.png",1) # 1是彩色图 bgr # 0是灰度图
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow("canny",cv2.Canny(gray,50,150))
cv2.waitKey()
cv2.destroyAllWindows()
48 changes: 48 additions & 0 deletions 226+陈易+武汉/13.canny_track.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# encoding = UTF-8

'''
Canny边缘检测:优化的程序
'''

import cv2
import numpy as np

def CannyThreshold(lowThreshold):
# detected_edges = cv2.GaussianBlur(gray,(3,3),0) # 高斯滤波
detected_edges = cv2.Canny(gray,
lowThreshold,
lowThreshold * ratio,
apertureSize = kernel_size) # 边缘检测,apertureSize默认是5
# 用原始颜色添加到检测的边缘上
# 按位“与”操作。对每个像素,将两幅输入图像相应位置的像素值分别进行按位“与”运算,输出的结果图像的对应项数值即为这两幅输入图像对应像素值按位 与 结果
# src1和src2表示要进行按位“与”操作的两幅输入图像;
# mask 是可选参数,如果指定了掩膜,则只对掩膜对应位置的像素进行按位“与”操作,函数的返回值表示按位“与”运算的结果
dst = cv2.bitwise_and(img,img,mask= detected_edges)
cv2.imshow('canny result',dst)
cv2.waitKey()

lowThreshold = 0 # 低阈值
max_lowThreshold = 100 # max低阈值
ratio = 3
kernel_size = 3 # kernel大小为:3*3

img = cv2.imread("lenna.png") # 读图
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 转灰度

cv2.namedWindow('canny result') # cv2.namedWindow创建一个窗口

# 设置调节杆
"""
下面是第二个函数,cv2.createTrackbar()
共有5个参数,其实这五个参数看变量名就大概能知道是什么意思
第一个参数,是这个trackbar对象的名字
第二个参数,是这个trackbar对象所在面板的名字
第三个参数,是这个trackbar的默认值,也是调节的对象
第四个参数,是这个trackbar上调节的范围(0~count)
第五个参数,是调节trackbar时调佣的回调函数名
"""
cv2.createTrackbar('min threshold','canny result',lowThreshold,max_lowThreshold,CannyThreshold)

CannyThreshold(50) # 初始化
if cv2.waitKey(0) == 5: # wait for ESC key to exit cv2
cv2.destroyAllWindows()
42 changes: 42 additions & 0 deletions 226+陈易+武汉/14.sobel_laplace_canny.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# encoding = UTF-8
"""
#!/usr/bin/env python 目的就是指出,你要用哪个python解释器去运行它
"""

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread("lenna.png",1)
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
'''
Sobel算子
Sobel算子函数原型如下:
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
前四个是必须的参数:
第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
其后是可选的参数:
dst是目标图像;
ksize是Sobel算子的大小,必须为1、3、5、7。
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
'''

img_sobel_x = cv2.Sobel(img_gray,cv2.CV_64F,1,0,ksize=3) # 对x求导
img_sobel_y = cv2.Sobel(img_gray,cv2.CV_64F,0,1,ksize=3) # 对y求导

# Laplace 算子
img_laplace = cv2.Laplacian(img_gray,cv2.CV_64F,ksize=3)

# canny 算子
img_canny = cv2.Canny(img_gray,50,150)

plt.subplot(231),plt.imshow(img_gray,"gray"),plt.title("正常")
plt.subplot(232),plt.imshow(img_sobel_x,"gray"),plt.title("img_sobel_x")
plt.subplot(233),plt.imshow(img_sobel_y,"gray"),plt.title("img_sobel_y")
plt.subplot(234),plt.imshow(img_laplace,"gray"),plt.title("laplace")
plt.subplot(235),plt.imshow(img_canny,"gray"),plt.title("img_canny")
plt.show()
33 changes: 33 additions & 0 deletions 226+陈易+武汉/15.透视变化.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import cv2
import numpy as np

img = cv2.imread("photo1.jpg") # 读图
result3 = img.copy() # 复制原图

"""
注意这里src和dst的输入不是图像,而是图像对应的顶点坐标
"""
src = np.float32([[207, 151], [517, 285], [17, 601], [343, 731]])
dst = np.float32([[0, 0], [337, 0], [0, 488], [337, 488]])
print(img.shape)

# 生成透视变换矩阵warpMatrix,进行透视变换,参数1:原图上的点 参数2:目标图上的点
m = cv2.getPerspectiveTransform(src,dst) # 获取逆透视变换矩阵函数warpMatrix的各参数(a11~a33)
print("warpMatrix:\n",m)

"""
warpPerspective函数,使指定的矩阵变化源图像.
cv.warpPerspective (InputArray src, OutputArray dst, dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar &borderValue=Scalar())
参数说明如下:
InputArray src:输入图像
OutputArray dst:输出大小为dsize
dsize:目标图像的大小,以元组形式表示,例如(width, height)
***以下为默认值***
flags: 插值方法的标志,用于指定插值方法,默认为cv2.INTER_LINEAR
borderMode: 边界模式,用于指定超出边界的像素处理方式,默认为cv2.BORDER_CONSTANT
borderValue: 当边界模式为cv2.BORDER_CONSTANT时,用于指定边界像素的值,默认为0。
"""
result = cv2.warpPerspective(result3,m,(337,488))
cv2.imshow("src",img)
cv2.imshow("result",result)
cv2.waitKey(0)

0 comments on commit c30fab5

Please sign in to comment.