课程目标
了解和掌握图像分割的定义、像素间关系;掌握全阈值分割和自适应阈值分割技术。了解和掌握典型的边缘监测算法如梯度算子、拉普拉斯算子、坎尼算子等。了解霍夫变换及形状检测算法。
一、阈值分割
import cv2 as cv
img1 = cv.imread("D:\\DIP_Photo\\Feather.jpg", 0)
img2 = cv.imread("D:\\DIP_Photo\\Barcode.jpg", 0)
th1, OtsuImgFeather = cv.threshold(img1, 0, 255, cv.THRESH_OTSU)
th2, OtsuImgBarcode = cv.threshold(img2, 0, 255, cv.THRESH_OTSU)
cv.imshow("Feather", img1)
print(th1)
cv.imshow("OtsuImgFeather", OtsuImgFeather)
cv.imshow("Barcode", img2)
print(th2)
cv.imshow("OtsuImgBarcode", OtsuImgBarcode)
cv.waitKey()
cv.destroyAllWindows()
二、各类边缘检测算子
代码如下(示例):
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读入图像并灰度化
# image = cv2.imread("D:\\DIP_Photo\\BW_Art.jpg")
image = cv2.imread("D:\\DIP_Photo\\Cameraman.tif")
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 自定义卷积核
# Roberts边缘算子
kernel_Roberts_x = np.array([
[1, 0],
[0, -1]
])
kernel_Roberts_y = np.array([
[0, -1],
[1, 0]
])
# Sobel边缘算子
kernel_Sobel_x = np.array([
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
kernel_Sobel_y = np.array([
[1, 2, 1],
[0, 0, 0],
[-1, -2, -1]])
# Prewitt边缘算子
kernel_Prewitt_x = np.array([
[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]])
kernel_Prewitt_y = np.array([
[1, 1, 1],
[0, 0, 0],
[-1, -1, -1]])
# 拉普拉斯卷积核
kernel_Laplacian_1 = np.array([
[0, 1, 0],
[1, -4, 1],
[0, 1, 0]])
kernel_Laplacian_2 = np.array([
[1, 1, 1],
[1, -8, 1],
[1, 1, 1]])
# 下面两个卷积核不具有旋转不变性
kernel_Laplacian_3 = np.array([
[2, -1, 2],
[-1, -4, -1],
[2, 1, 2]])
kernel_Laplacian_4 = np.array([
[-1, 2, -1],
[2, -4, 2],
[-1, 2, -1]])
# 5*5 LOG卷积模板
kernel_LoG = np.array([
[0, 0, -1, 0, 0],
[0, -1, -2, -1, 0],
[-1, -2, 16, -2, -1],
[0, -1, -2, -1, 0],
[0, 0, -1, 0, 0]])
# Canny边缘检测 k为高斯核大小,t1,t2为阈值大小
def Canny(image, k, t1, t2):
img = cv2.GaussianBlur(image, (k, k), 0)
canny = cv2.Canny(img, t1, t2)
return canny
# 卷积
output_1 = cv2.filter2D(image, -1, kernel_Roberts_x)
output_2 = cv2.filter2D(image, -1, kernel_Sobel_x)
output_3 = cv2.filter2D(image, -1, kernel_Prewitt_x)
output_4 = cv2.filter2D(image, -1, kernel_Laplacian_1)
output_5 = cv2.filter2D(image, -1, kernel_LoG)
output_6 = Canny(image, 3, 50, 150)
# 显示处理后的图像
plt.figure("Original Image") # 图像窗口名称
plt.imshow(image, cmap='gray') # 显示灰度图要加cmap
plt.axis('off') # 关掉坐标轴为 off
plt.title('Original Image') # 图像题目
plt.show()
plt.figure("Multi Image") # 图像窗口名称
plt.suptitle('Multi_Image') # 图片名称
plt.subplot(2, 3, 1), plt.title('Roberts')
plt.imshow(output_1, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 2), plt.title('Sobel')
plt.imshow(output_2, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 3), plt.title('Prewitt')
plt.imshow(output_3, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 4), plt.title('Laplacian')
plt.imshow(output_4, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 5), plt.title('LOG')
plt.imshow(output_5, cmap='gray'), plt.axis('off')
plt.subplot(2, 3, 6), plt.title('Canny')
plt.imshow(output_6, cmap='gray'), plt.axis('off')
plt.show()
# 等待按键并销毁窗口
cv2.waitKey()
cv2.destroyAllWindows()
三、区域生长算法示例
代码如下(示例):
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 求两个点的差值
def getGrayDiff(image, currentPoint, tmpPoint):
return abs(int(image[currentPoint[0], currentPoint[1]]) - int(image[tmpPoint[0], tmpPoint[1]]))
# 区域生长算法
def regional_growth(gray, seeds, threshold=5):
# 每次区域生长的时候的像素之间的八个邻接点
connects = [(-1, -1), (0, -1), (1, -1), (1, 0), (1, 1),
(0, 1), (-1, 1), (-1, 0)]
threshold = threshold # 生长时候的相似性阈值,默认即灰度级不相差超过15以内的都算为相同
height, weight = gray.shape
seedMark = np.zeros(gray.shape)
seedList = []
for seed in seeds:
if (seed[0] < gray.shape[0] and seed[1] < gray.shape[1] and seed[0] > 0 and seed[1] > 0):
seedList.append(seed) # 将添加到的列表中
print(seedList)
label = 1 # 标记点的flag
while (len(seedList) > 0): # 如果列表里还存在点
currentPoint = seedList.pop(0) # 将最前面的那个抛出
seedMark[currentPoint[0], currentPoint[1]] = label # 将对应位置的点标志为1
for i in range(8): # 对这个点周围的8个点一次进行相似性判断
tmpX = currentPoint[0] + connects[i][0]
tmpY = currentPoint[1] + connects[i][1]
if tmpX < 0 or tmpY < 0 or tmpX >= height or tmpY >= weight: # 如果超出限定的阈值范围
continue # 跳过并继续
grayDiff = getGrayDiff(gray, currentPoint, (tmpX, tmpY)) # 计算此点与像素点的灰度级之差
if grayDiff < threshold and seedMark[tmpX, tmpY] == 0:
seedMark[tmpX, tmpY] = label
seedList.append((tmpX, tmpY))
return seedMark
# 初始种子选择
def originalSeed(gray):
ret, img1 = cv2.threshold(gray, 245, 255, cv2.THRESH_BINARY) # 二值图,种子区域(不同划分可获得不同种子)
retval, labels, stats, centroids = cv2.connectedComponentsWithStats(img1) # 进行连通域操作,取其质点
centroids = centroids.astype(int) # 转化为整数
return centroids
# img = cv2.imread("D:\\DIP_Photo\\multiple-regions.tif")
img = cv2.imread("D:\\DIP_Photo\\Bird.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
seed = originalSeed(img)
img = regional_growth(img, seed)
# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 图像显示
plt.figure(figsize=(10, 5)) # width * height
plt.subplot(111), plt.imshow(img, cmap='gray'), plt.title('区域生长'), plt.axis("off")
plt.show()
print("ok...")
四、霍夫直线检测示例
代码如下(示例):
import cv2
import numpy as np
img = cv2.imread('D:\\DIP_Photo\\BW_Art.jpg')
# img = cv2.imread('D:\\DIP_Photo\\Edge_Sample.bmp')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 彩色图片灰度化
edges = cv2.Canny(gray, 100, 200) # 执行边缘检测
cv2.imshow('edge', edges) # 显示原始结果
# 执行Hough直线检测
lines = cv2.HoughLines(edges, 1, np.pi / 180, 160)
lines1 = lines[:, 0, :]
for rho, theta in lines1:
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 1)
cv2.imshow('line', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 渐进概率式霍夫变换
img = cv2.imread('D:\\DIP_Photo\\BW_Art.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200)
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, minLineLength=200, maxLineGap=10)
lines = lines[:, 0, :]
for x1, y1, x2, y2 in lines:
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
五、霍夫圆检测示例
代码如下(示例):
import cv2
import numpy as np
src = cv2.imread("D:\\DIP_Photo\\twotone-circles.tif")
# src = cv2.imread("D:\\DIP_Photo\\balls.jpg")
src = cv2.resize(src, None, fx=0.8, fy=0.8, interpolation=cv2.INTER_CUBIC)
dst = cv2.blur(src, (5, 5))
dst = cv2.cvtColor(dst, cv2.COLOR_BGRA2GRAY)
cv2.imshow("adapt_image", dst)
circle = cv2.HoughCircles(dst, cv2.HOUGH_GRADIENT, 1, 200, param1=50, param2=30, minRadius=20, maxRadius=300)
if not circle is None:
circle = np.uint16(np.around(circle))
print(circle)
for i in circle[0, :]:
cv2.circle(src, (i[0], i[1]), i[2], (255, 0, 255), 3)
cv2.imshow("circle", src)
cv2.waitKey(0)
cv2.destroyAllWindows()
六、形状检测示例
代码如下(示例):
import cv2
# 读取彩色图片
img = cv2.imread('D:\\DIP_Photo\\Shape.bmp')
# 转换为灰度图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 进行二值化处理
[ret, binary] = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 寻找轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 绘制不同的轮廓
draw_img0 = cv2.drawContours(img.copy(), contours, 0, (0, 255, 255), 3)
draw_img1 = cv2.drawContours(img.copy(), contours, 1, (255, 0, 255), 3)
draw_img2 = cv2.drawContours(img.copy(), contours, 2, (255, 255, 0), 3)
draw_img3 = cv2.drawContours(img.copy(), contours, -1, (0, 0, 255), 3)
# 打印结果
print("contours:类型:", type(contours))
print("第0 个contours:", type(contours[0]))
print("contours 数量:", len(contours))
print("contours[0]点的个数:", len(contours[0]))
print("contours[1]点的个数:", len(contours[1]))
# 显示并保存结果
cv2.imshow("img", img)
cv2.imshow("draw_img0", draw_img0)
cv2.imshow("draw_img1", draw_img1)
cv2.imshow("draw_img2", draw_img2)
cv2.imshow("draw_img3", draw_img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
七、一个简单的车道检测
代码如下(示例):
import cv2
import numpy as np
class lane_detection():
def __init__(self, image):
self.image = image
def process(self):
# 滤波处理,去除噪声,平滑图像
blur = cv2.GaussianBlur(self.image, (5, 5), 1)
# 边缘检测,Canny算法
edge = cv2.Canny(blur, 180, 255)
return edge
def roi(self):
edge = self.process()
print(edge.shape[:2])
rows, cols = edge.shape[:2]
mask = np.zeros_like(edge)
# 梯形四点坐标
shape = np.array([[(0, rows), (int(cols / 3) + 100, int(rows * 2 / 3) - 30),
(int(2 * cols / 3) - 100, int(rows * 2 / 3) - 30), (cols, rows)]])
cv2.fillPoly(mask, shape, 255)
masked_img = cv2.bitwise_and(mask, edge)
return masked_img
def hough(self):
masked_img = self.roi()
left, right = [], []
rows, cols = masked_img.shape[:2]
# houghP算法,提取线段两端点坐标
lines = cv2.HoughLinesP(masked_img, 1, np.pi / 180, 50, minLineLength=50, maxLineGap=20)
print(len(lines))
# 提取左右两车道线段的集合,并分类
for line in lines:
for x1, y1, x2, y2 in line:
if (y2 - y1) / (x2 - x1) > 0:
left.append(line)
else:
right.append(line)
# 提取左右两车道的坐标,并最小二乘法拟合
left_points = [(x1, y1) for line in left for x1, y1, x2, y2 in line]
left_points = left_points + [(x2, y2) for line in left for x1, y1, x2, y2 in line]
right_points = [(x1, y1) for line in right for x1, y1, x2, y2 in line]
right_points = right_points + [(x2, y2) for line in right for x1, y1, x2, y2 in line]
print(len(left_points))
print(len(right_points))
left_x = [p[0] for p in left_points]
left_y = [p[1] for p in left_points]
right_x = [p[0] for p in right_points]
right_y = [p[1] for p in right_points]
fit_left = np.polyfit(left_y, left_x, 1)
fit_right = np.polyfit(right_y, right_x, 1)
left_fn = np.poly1d(fit_left)
right_fn = np.poly1d(fit_right)
print(left_fn)
print(right_fn)
left_x_min = int(left_fn(rows * 2 / 3))
left_x_max = int(left_fn(rows))
print(left_x_min)
print(left_x_max)
right_x_min = int(right_fn(rows * 2 / 3))
right_x_max = int(right_fn(rows))
print(right_x_min)
print(right_x_max)
lane = np.array([[(left_x_min, int(rows * 2 / 3)), (left_x_max, rows), (right_x_max, rows),
(right_x_min, int(rows * 2 / 3))]])
return lane
if __name__ == '__main__':
image = cv2.imread('D:\\DIP_Photo\\Road01.jpg', 0)
ld = lane_detection(image)
shape = ld.hough()
image = cv2.imread('D:\\DIP_Photo\\Road01.jpg', 1)
cv2.fillPoly(image, shape, (0, 255, 0))
cv2.imshow('lane', image)
cv2.waitKey(0)
代码示例仅供学生学习参考,如有引用未标注请提醒。