DIP_UN_08


课程目标

了解和掌握图像分割的定义、像素间关系;掌握全阈值分割和自适应阈值分割技术。了解和掌握典型的边缘监测算法如梯度算子、拉普拉斯算子、坎尼算子等。了解霍夫变换及形状检测算法。


一、阈值分割

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)

代码示例仅供学生学习参考,如有引用未标注请提醒。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值