如何提取深度图像的边缘信息?

编程语言及工具

105人已加入

描述

不会吧?不会吧?不会吧?不会有人忘记我还会写图像处理的代码吧?别说了,我知道你忘了,没关系,我会在这篇文章写一些很简短的代码实现常见的图像处理工作。

如何提取深度图像的边缘信息?

Sobel算子:Sobel算子是一种基于图像梯度的边缘检测算法,可以在x方向和y方向上计算图像的梯度,然后将两个梯度值合并成一个边缘强度值。通常可以使用Sobel算子来检测深度图像中的水平和垂直边缘。 Scharr算子是一种改进的Sobel算子,它使用了更大的卷积核来平滑图像,并在计算梯度时使用更准确的权重。Scharr算子在处理低对比度图像时表现更好。 Laplacian算子:Laplacian算子是一种基于二阶微分的边缘检测算法,可以检测出深度图像中的较强的边缘。该算子计算图像的拉普拉斯变换,并寻找其中的极值点作为边缘点。 深度边缘检测算法:除了基于梯度或微分的算法,还有一些专门针对深度图像的边缘检测算法。这些算法通常利用深度图像的信息来检测物体表面的变化,例如深度跳变或斜率变化等。 Canny算子是一种广泛使用的边缘检测算法,它采用了多步骤的边缘检测过程。首先,使用高斯滤波器平滑图像,然后计算图像的梯度和梯度方向。接下来,应用非极大值抑制和双阈值处理来提取边缘。最后,通过连接具有强度边缘的像素来获得完整的边缘。Canny算子在抑制噪声和保留真实边缘方面表现良好,通常被认为是一种比Sobel算子更优秀的边缘检测算法。 如何使用Python实现一个抽帧算法? 为啥会有这种东西?原因就是因为图像帧太多又不需要都处理~

import cv2


def extract_frames(video_path, interval):
    # 打开视频文件
    cap = cv2.VideoCapture(video_path)
    # 计算视频总帧数和帧率
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    fps = cap.get(cv2.CAP_PROP_FPS)
    # 计算抽帧间隔
    interval_frames = int(interval * fps)
    # 初始化帧计数器和关键帧列表
    count = 0
    frames = []
    # 逐帧遍历视频
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        count += 1
        # 如果是关键帧,将其添加到关键帧列表中
        if count % interval_frames == 0:
            frames.append(frame)
    # 关闭视频文件
    cap.release()
    return frames
  照指定的时间间隔从视频中抽取关键帧 上述代码中,extract_frames()函数接受视频文件路径和抽帧间隔作为输入参数,返回一个包含关键帧的列表。在函数内部,首先使用cv2.VideoCapture()函数打开视频文件,并使用cv2.CAP_PROP_FRAME_COUNT和cv2.CAP_PROP_FPS获取视频总帧数和帧率。然后,根据指定的抽帧间隔计算需要保留的关键帧,在逐帧遍历视频时根据帧计数器来判断当前帧是否为关键帧,如果是,则将其添加到关键帧列表中。最后,使用cap.release()函数关闭视频文件。 可以使用以下代码调用extract_frames()函数来从视频文件中抽取关键帧:
frames = extract_frames('video.mp4', 1)  # 抽取间隔为1秒的关键帧
for frame in frames:
    cv2.imshow('frame', frame)
    cv2.waitKey(0)
cv2.destroyAllWindows()
  上述代码将抽取间隔设置为1秒,然后遍历返回的关键帧列表,使用cv2.imshow()函数显示每个关键帧,并在用户按下键盘后继续显示下一个关键帧。最后,使用cv2.destroyAllWindows()函数关闭所有显示窗口。 让我们使用一个算子来提取深度图像的边缘信息的函数: Sobel算子是一种常用的边缘检测算子,它利用图像的灰度值变化来检测边缘。
import cv2
import numpy as np


def extract_depth_edges(depth_img):
    # 计算Sobel算子的卷积核
    sobelx = cv2.Sobel(depth_img, cv2.CV_64F, 1, 0, ksize=3)
    sobely = cv2.Sobel(depth_img, cv2.CV_64F, 0, 1, ksize=3)
    # 计算梯度幅值和方向
    grad_mag = np.sqrt(sobelx ** 2 + sobely ** 2)
    grad_dir = np.arctan2(sobely, sobelx)
    # 将梯度幅值归一化到0-255之间
    grad_mag_norm = cv2.normalize(grad_mag, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
    # 将梯度方向转换为角度
    grad_dir_deg = (grad_dir * 180 / np.pi) % 180
    # 应用非极大值抑制
    grad_mag_nms = cv2.Canny(grad_mag_norm, 100, 200)
    return grad_mag_nms
  上述代码中,extract_depth_edges()函数接受深度图像作为输入参数,返回提取的边缘信息。在函数内部,首先使用cv2.Sobel()函数计算x和y方向上的Sobel算子的卷积核,然后计算梯度幅值和方向。接下来,将梯度幅值归一化到0-255之间,并将梯度方向转换为角度。最后,应用非极大值抑制(Canny边缘检测算法)来提取边缘信息,并返回结果。 可以使用以下代码调用extract_depth_edges()函数来提取深度图像的边缘信息:
depth_img = cv2.imread('depth_image.png', cv2.IMREAD_GRAYSCALE)
edges = extract_depth_edges(depth_img)
cv2.imshow('depth_edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()

  上述代码将读取深度图像并将其作为输入参数传递给extract_depth_edges()函数,然后显示提取的边缘信息。 有时候会有这样的需求,把提取的图像边缘保存在一个txt文件中: 假设我们已经提取了深度图像的边缘信息,存储在名为edge_img的NumPy数组中,边缘值的范围在0到255之间。
import numpy as np


# 假设我们已经提取了深度图像的边缘信息,存储在名为edge_img的NumPy数组中


# 将边缘值缩放到0到1之间
edge_img = edge_img / 255.0


# 将边缘信息转换为字符串格式
edge_str = np.array2string(edge_img, separator=',', formatter={'float_kind':lambda x: "%.5f" % x})


# 将字符串写入txt文件
with open('edge_info.txt', 'w') as f:
    f.write(edge_str)
在上面的代码中,我们将边缘值缩放到0到1之间,并将其转换为字符串格式。我们使用NumPy的array2string函数将数组转换为字符串,并使用逗号作为分隔符。我们还设置了formatter参数,将浮点数的小数位数限制为5位。最后,我们将字符串写入名为edge_info.txt的txt文件中。 请注意,在读取txt文件时,需要使用适当的代码将字符串转换回NumPy数组格式。 虽然一直写不了长代码,但是不妨碍我写在一起: 接下来把抽帧算法和保存边缘到txt的函数写在一起
import cv2
import numpy as np


def extract_edge(frame, threshold):
    # 使用高斯模糊平滑图像
    blurred = cv2.GaussianBlur(frame, (3, 3), 0)
    # 转换为灰度图像
    gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)
    # 使用Canny算法提取边缘
    edges = cv2.Canny(gray, threshold, threshold * 2)
    return edges


def save_edges_to_txt(edges, filename):
    # 将边缘值缩放到0到1之间
    edges = edges / 255.0
    # 将边缘信息转换为字符串格式
    edge_str = np.array2string(edges, separator=',', formatter={'float_kind':lambda x: "%.5f" % x})
    # 将字符串写入txt文件
    with open(filename, 'w') as f:
        f.write(edge_str)


# 读取深度图像
depth_img = cv2.imread('depth_img.png')
# 指定抽帧间隔
interval = 10
# 提取深度图像边缘
edges = extract_edge(depth_img, 50)
# 抽帧,保留每隔interval个像素
sampled_edges = edges[::interval, ::interval]
# 将边缘信息保存到txt文件中
save_edges_to_txt(sampled_edges, 'edge_info.txt')
在上面的代码中,我们定义了一个extract_edge函数来提取深度图像的边缘,该函数使用高斯模糊平滑图像并使用Canny算法提取边缘。我们还定义了一个save_edges_to_txt函数,将边缘信息保存到txt文件中。 在主函数中,我们首先读取深度图像,然后指定抽帧间隔。我们使用extract_edge函数提取深度图像边缘,并使用抽帧算法保留每隔interval个像素。最后,我们使用save_edges_to_txt函数将提取的边缘信息保存到txt文件中。 应该是可以直接运行的,如果运行不了你再改改? 上面鄙人已经教了你把图像转换成txt的文件,如何把保存在txt文件里面的边缘信息恢复成图像呢? 你会不?
1.从txt文件中读取边缘信息字符串,并将其转换为NumPy数组。可以使用numpy.loadtxt函数将文件中的数据加载到NumPy数组中。
2。根据边缘信息数组的大小创建一个全零的数组,然后将边缘信息数组的值复制到全零数组的对应位置上。可以使用numpy.zeros函数创建全零数组,并使用numpy.put函数将边缘信息数组的值复制到全零数组的对应位置上。 3.对全零数组进行插值操作,以生成与原始深度图像相同大小的边缘图像。可以使用cv2.resize函数对全零数组进行插值操作。 4.对插值后的边缘图像进行二值化处理,以生成二值图像。可以使用cv2.threshold函数对插值后的边缘图像进行二值化处理。
import cv2
import numpy as np


def load_edges_from_txt(filename, shape):
    # 从txt文件中读取边缘信息
    edge_str = np.loadtxt(filename, delimiter=',')
    # 创建全零数组
    edges = np.zeros(shape)
    # 将边缘信息复制到全零数组的对应位置上
    np.put(edges, np.arange(shape[0]*shape[1]), edge_str)
    # 对全零数组进行插值操作
    edges = cv2.resize(edges, (shape[1], shape[0]))
    # 对插值后的边缘图像进行二值化处理
    ret, edges = cv2.threshold(edges, 0, 255, cv2.THRESH_BINARY)
    return edges


# 读取深度图像
depth_img = cv2.imread('depth_img.png')
# 获取深度图像大小
height, width = depth_img.shape[:2]
# 从txt文件中加载边缘信息,并恢复成图像
edges = load_edges_from_txt('edge_info.txt', (height//10, width//10))
# 显示原始深度图像和恢复的边缘图像
cv2.imshow('depth_img', depth_img)
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
    在上面的代码中,我们定义了一个load_edges_from_txt函数,该函数从txt文件中加载边缘信息,并将其恢复成图像。该函数首先使用numpy.loadtxt函数从文件中加载数据,并将其转换为NumPy数组。然后,该函数根据指定的图像大小创建一个全零数组,并使用numpy.put函数将边缘信息数组的值复制到全零数组的对应位置上。接下来,该函数对全零数组进行插值操作,并使用cv2.threshold函数对插值后的边缘图像进行二值化处理,生成二值图像。 最后一个代码,把1000x1000的图像信息转换到10x10的图像里面,应该怎么做? 使用图像缩放操作。可以使用OpenCV中的cv2.resize函数对原始图像进行缩放操作。该函数的输入参数包括原始图像、目标图像大小和插值方法等。
import cv2


# 读取原始图像
img = cv2.imread('original_image.png')
# 缩放图像
new_img = cv2.resize(img, (10, 10), interpolation=cv2.INTER_AREA)
# 显示原始图像和缩放后的图像
cv2.imshow('original', img)
cv2.imshow('new', new_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上面的代码中,我们使用cv2.imread函数读取原始图像,然后使用cv2.resize函数对原始图像进行缩放操作,将其缩放为10x10的图像。在cv2.resize函数中,我们将目标图像大小设置为(10, 10),并将插值方法设置为cv2.INTER_AREA。最后,我们使用cv2.imshow函数显示原始图像和缩放后的图像。  
编辑:黄飞

 

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分