Python图像处理之线路提取

#导入所需库和模块
import numpy as np
import math
import cv2
from sklearn.cluster import KMeans
from skimage.morphology import skeletonize
from scipy.signal import convolve2d
from simplification.cutil import simplify_coords
import webcolors
import matplotlib.pyplot as plt
%matplotlib inline

图像上传

img = cv2.imread('data/baby_yoda.jpeg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.xticks([])
plt.yticks([])
plt.show();

边缘探测(edges detection)

def make_white_background(image, mask):
    """
    auxiliary function to make white background for an image
    :param image: color image
    :param mask: mask of 0 (background) and 1 (detected edges)
    :return: masked color image
    """
    result_image = image.copy()
    for idx_row in range(image.shape[0]):
        for idx_col in range(image.shape[1]):
            if mask[idx_row, idx_col] == 0:
                result_image[idx_row][idx_col] = [255, 255, 255]
    result_image = result_image.astype('uint8')
    return result_image
def adaptive_thresholding_edge_detection(image):
    """
    function for image thresholding with median filter and adaptive threshold
    :param image: source image in RGB
    :return: image of the same size in RGB format with white background and detected color edges
    """
    imgray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    img = cv2.medianBlur(imgray, 5)
    thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)

    mask = (1 - (thresh / 255)).astype('uint8')
    result_image = make_white_background(image, mask)

    return result_image, mask
def simple_thresholding_edge_detection(image):
    """
    function for image thresholding with simple binary threshold
    :param image: source image in RGB
    :return: image of the same size in RGB format with white background and detected color edges
    """
    imgray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    ret, thresh = cv2.threshold(imgray, 127, 255, 0)

    mask = 1 - (thresh / 255).astype('uint8')
    result_image = make_white_background(image, mask)

    return result_image, mask

边缘检测算法

def canny_edge_detection(image):
    """
    function for canny edge detection
    :param image: source image in RGB
    :return: image of the same size in RGB format with white background and detected color edges
    """
    imgray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    img = cv2.medianBlur(imgray, 5)
    thresh = cv2.Canny(img, 75, 150)

    mask = (thresh / 255).astype('uint8')
    result_image = make_white_background(image, mask)

    return result_image, mask

简单的阈值处理

img_rgb_simple_thrsh, mask_simple_thrsh = simple_thresholding_edge_detection(img_rgb)

plt.imshow(img_rgb_simple_thrsh)
plt.xticks([])
plt.yticks([])
plt.plot();

自适应阈值化

img_rgb_adaptive_thrsh, mask_adaptive_thrsh = adaptive_thresholding_edge_detection(img_rgb)

plt.imshow(img_rgb_adaptive_thrsh)
plt.xticks([])
plt.yticks([])
plt.plot();

边缘检测

img_rgb_canny, mask_canny = canny_edge_detection(img_rgb)

plt.imshow(img_rgb_canny)
plt.xticks([])
plt.yticks([])
plt.plot();

 

矢量化(线选择)

支持功能

def distance(x1, y1, x2, y2):
    """
    function for calculating distance between two points
    :param x1: x coordinate of the first point
    :param y1: y coordinate of the first point
    :param x2: x coordinate of the second point
    :param y2: y coordinate of the second point
    :return: distance value
    """
    return math.sqrt(math.pow(x1 - x2, 2) + math.pow(y1 - y2, 2))
def line_length(line):
    """
    function for calculating length of a line
    :param line: as sequence of points
    :return: length of a line
    """
    line_len = 0
    for p in range(0, len(line) - 1):
        (x1, y1) = (line[p][1], line[p][0])
        (x2, y2) = (line[p + 1][1], line[p + 1][0])
        line_len = line_len + distance(x1, y1, x2, y2)
    return line_len
def find_neighbour_points(img, x, y, threshold=1):
    """
    function for finding neighbour points
    :param img: tested image
    :param x: x coordinate
    :param y: y coordinate
    :param threshold: thresholding value
    :return: detected lines
    """
    out_points = []

    if x - 1 >= 0 and y - 1 >= 0:
        if img[x - 1][y - 1] == threshold:
            out_points.append((x - 1, y - 1))

    if x - 1 >= 0:
        if img[x - 1][y] == threshold:
            out_points.append((x - 1, y))

    if x - 1 >= 0 and y + 1 < img.shape[1]:
        if img[x - 1][y + 1] == threshold:
            out_points.append((x - 1, y + 1))

    if y - 1 >= 0:
        if img[x][y - 1] == threshold:
            out_points.append((x, y - 1))

    if y + 1 < img.shape[1]:
        if img[x][y + 1] == threshold:
            out_points.append((x, y + 1))

    if x + 1 < img.shape[0] and y - 1 >= 0:
        if img[x + 1][y - 1] == threshold:
            out_points.append((x + 1, y - 1))

    if x + 1 < img.shape[0]:
        if img[x + 1][y] == threshold:
            out_points.append((x + 1, y))

    if x + 1 < img.shape[0] and y + 1 < img.shape[1]:
        if img[x + 1][y + 1] == threshold:
            out_points.append((x + 1, y + 1))

    return out_points
def find_lines(skeleton):
    """
    function for finding continuous sequence which may be treated as lines
    :param skeleton: result of skimage skeletonize
    :return: detected lines
    """
    lines = []
    for i in range(0, skeleton.shape[0]):
        for j in range(0, skeleton.shape[1]):
            if skeleton[i][j] == 1:
                line = []
                line.append((i, j))
                neb = find_neighbour_points(skeleton, i, j)
                skeleton[i][j] = 0
                while len(neb) != 0:
                    for n in neb:
                        skeleton[n[0], n[1]] = 0
                    line.append(neb[0])
                    nn = find_neighbour_points(skeleton, neb[0][0], neb[0][1])
                    neb.pop(0)
                    for n in neb:
                        nn.append(n)
                    neb = [n for n in nn]
                line = list(map(lambda point: (point[1], point[0]), line))
                lines.append(line)
    return lines

 

 

#线条骨架化
skeleton = skeletonize(mask_adaptive_thrsh)

#删除线的交叉点
neighbour_matrix = convolve2d(skeleton, np.ones((3, 3)), mode='same')
skeleton[neighbour_matrix > 3] = 0

#线路矢量化
lines = find_lines(skeleton)

#去除环路
new_lines = []
for line in lines:
    lenlen = []
    p = 0
    while p < len(line) - 1:
        if distance(line[p][0], line[p][1], line[p + 1][0], line[p + 1][1]) > 2:
            lenlen.append(p)
        p = p + 1
    if len(lenlen) == 1:
        i = lenlen[0]
        new_lines.append(line[i + 1: len(line)])
        new_lines.append(line[0: i + 1])
    else:
        new_lines.append(line)

#清除垃圾线
eps_line_len = 1
new_lines = [line for line in new_lines if len(line) > eps_line_len]
new_lines = [line for line in new_lines if line_length(line) > 5]

用Ramer-Douglas-Pecker算法简化线条

使用算法的示例

simplified = simplify_coords(new_lines[0], 1.0)

简化后的结果

print('Исходные координаты первой линии')
print(str(new_lines[0]))
 
print('Упрощенные координаты первой линии')
print(str(simplified))

按颜色分类的线条聚类

支持性功能

def get_colors_of_line(image, line):
    """
    function to get color of line
    :param image: original RGB image
    :param line: detected line as list of points
    :return: color
    """
    return [image[elem[1]][elem[0]] for elem in line]
def get_colors(image, lines):
    """
    function to get colors of lines
    :param image: original RGB image
    :param lines: detected lines as list of points
    :return: colors
    """
    rgb_lines = []
    for line in lines:
        t = get_colors_of_line(image, line)
        (r, g, b) = (0, 0, 0)
        for tt in t:
            r = r + tt[0]
            g = g + tt[1]
            b = b + tt[2]
        (r, g, b) = (int(r / len(t)), int(g / len(t)), int(b / len(t)))
        rgb_lines.append((r, g, b))
    return rgb_lines
number_of_clusters = 16
rgb_lines = get_colors(img_rgb, new_lines)
rgb_lines_array = np.array(rgb_lines, np.uint8)
lines_array = np.array(new_lines)
clusterer = KMeans(n_clusters=number_of_clusters)
clusterer.fit(rgb_lines_array)
labels = clusterer.labels_
centers = clusterer.cluster_centers_
lines_by_clusters = [list(lines_array[labels == i]) for i in range(number_of_clusters)]
cluster_color = list(map(lambda color: tuple(map(int, color)), centers))

绘制结果

支持性功能

def draw_lines_by_color(lines, debug_image, color, line_width=3):
    """
    function for drawing lines
    :param lines: detected lines as list of points
    :param debug_image: debug image
    :param color: color
    :param line_width: width of a line
    :return:
    """
    for line in lines:
        for p0, p1 in zip(line[:-1], line[1:]):
            x0, y0 = p0
            x1, y1 = p1
            cv2.line(debug_image, (int(x0), int(y0)), (int(x1), int(y1)), color, line_width)
def get_color_name(rgb_triplet):
    """
    function to get closest color name by RGB triplet
    :param rgb_triplet: (R, G, B)
    :return: identified color as str
    """
    min_colors = {}
    for name, hex_value in webcolors.CSS3_NAMES_TO_HEX.items():
        r_c, g_c, b_c = webcolors.hex_to_rgb(hex_value)
        rd = (r_c - rgb_triplet[0]) ** 2
        gd = (g_c - rgb_triplet[1]) ** 2
        bd = (b_c - rgb_triplet[2]) ** 2
        min_colors[(rd + gd + bd)] = name
    return min_colors[min(min_colors.keys())]
plt.figure(figsize=(15, 120))

for i, lines in enumerate(lines_by_clusters):
    plt.subplot(number_of_clusters, 2, 2 * i + 1)
    plt.imshow(img_rgb)
    plt.xticks([])
    plt.yticks([])
    
    plt.subplot(number_of_clusters, 2, 2 * i + 2)
    debug_image = (255 + np.zeros((img_rgb.shape[0], img_rgb.shape[1], 3))).astype('uint8')
    draw_lines_by_color(lines, debug_image, cluster_color[i], line_width=3)
    plt.imshow(debug_image.astype('uint8'))
    plt.title(get_color_name(cluster_color[i]))
    plt.xticks([])
    plt.yticks([])

plt.plot();

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ROS深度相机小车循迹是指使用ROS(机器人操作系统)结合深度相机技术来实现小车的循迹功能,并使用Python编程语言进行控制。具体步骤如下: 首先,需要搭建ROS环境。安装好ROS之后,我们可以使用ROS提供的各种工具和库来开发和控制我们的小车。 接下来,需要连接深度相机到小车上,并配置好相机的驱动程序。常用的深度相机有Kinect、RealSense等,可以通过官方提供的驱动程序或第三方库进行配置。 然后,需要使用ROS提供的视觉传感器包,例如OpenCV或PCL,读取深度相机的数据。可以通过ROS的图像传输工具将深度图像和彩色图像传输到ROS中。 在ROS中,使用Python编程语言创建一个节点,用于接收深度图像的数据。可以使用ROS提供的点云库对深度图像进行处理,提取出需要的信息,如障碍物的位置和形状。 根据深度图像的信息,可以设计一个算法来实现小车的循迹功能。例如,可以使用视觉巡线算法来检测道路的位置和方向,并根据检测结果调整小车的运动方向和速度。 最后,将控制指令发送给小车的驱动系统,控制小车按照设定的循迹算法运动。可以使用ROS提供的底层硬件驱动接口或者第三方库来实现与小车驱动系统的通信。 综上所述,ROS深度相机小车循迹Python是一种利用ROS和深度相机技术来实现小车循迹功能,并通过Python进行控制的方法。通过搭建ROS环境、配置深度相机驱动、读取深度图像数据、设计循迹算法和控制小车运动,可以实现小车在道路上的自动行驶。 ### 回答2: ROS (机器人操作系统) 是一个开源的机器人软件平台,能够帮助开发者轻松地创建机器人应用。ROS 提供了很多功能包和工具,包括与深度相机和小车循迹相关的功能。 深度相机是一种能够感知三维环境信息的摄像头,能够为机器人提供更精确的感知能力。在 ROS 中,可以使用深度相机的驱动程序和库进行数据的获取和处理。例如,可以使用 ROS 中的 OpenCV 和 PCL (点云库) 实现深度图像的处理和分析。通过深度相机,机器人可以感知环境的障碍物、物体位置等信息,以便进行导航和路径规划。 小车循迹是指小车按照预定的线路自动行驶的功能。在 ROS 中,可以使用小车底盘驱动程序来控制小车的运动。利用小车底盘的编码器和传感器信息,我们可以实现小车的定位和导航。结合深度相机的数据,可以进一步提高小车循迹的精确性和稳定性。 Python 是 ROS 中常用的编程语言之一,提供了丰富的库和工具。通过编写 Python 脚本,我们可以实现深度相机和小车循迹的控制。例如,可以使用 ROS 提供的 Python API (Application Programming Interface) 来订阅深度图像的话题,进行图像处理,并发送控制指令给小车底盘。另外,还可以使用一些第三方的 Python 库,如 PyTorch 和 TensorFlow,来进行深度学习和计算机视觉的任务。 总结来说,通过 ROS、深度相机和小车底盘的结合,我们可以实现使用 Python 控制小车进行循迹和感知环境的功能。这为机器人应用的开发提供了更强大的工具和平台。 ### 回答3: ROS是一个开源的机器人操作系统,可以帮助我们方便地开发和管理机器人的软硬件系统。深度相机是一种可以获取环境中物体距离和深度信息的相机设备。小车循迹是指小车能够根据特定的路径和线路进行自主行驶的能力。Python是一种流行的编程语言,它具有简洁易懂、易于学习和强大的库支持等特点。 在ROS中,可以使用ROS的Python库来实现小车循迹功能。首先,需要使用ROS提供的深度相机的驱动节点来获取深度图像和距离信息。然后,通过编写Python程序来处理获取到的深度信息,比如使用图像处理算法来识别出特定路径或线路的位置信息。 接下来,可以通过ROS提供的小车控制节点来控制小车的运动。通过Python程序将提取到的位置信息传递给小车控制节点,从而实现小车沿着设定的路径或线路行驶。 在具体实现时,可以使用Python图像处理库(如OpenCV)来处理深度图像,并使用计算机视觉算法来识别出路径或线路。通过与ROS相结合,可以利用ROS提供的通信机制将图像处理和小车控制部分进行集成。 总之,通过ROS的深度相机和Python图像处理能力,结合小车控制节点,可以实现小车循迹的功能。通过编写Python程序和与ROS进行通信,可以使小车根据深度相机的获取信息来自主行驶。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值