(算法版)基于二值图像数字矩阵的距离变换算法

Hi,大家好,我是半亩花海。本项目展示了欧氏距离、城市街区距离和棋盘距离变换的实现方法。通过定义一个距离变换类,对输入图像进行距离变换操作,并生成对应的距离矩阵。在示例中,展示了在一个480x480的全黑背景图像上设置三个前景像素点的距离变换结果。


文章目录

      • 一、距离的定义及分类
      • 二、导入必要库
      • 三、距离变换算法
      • 四、定义距离变换类
      • 五、显示原始图像
      • 六、计算并输出距离变换矩阵
      • 七、可视化距离变换结果
      • 八、完整代码


一、距离的定义及分类

距离是描述图像两点像素之间的远近关系的度量,常见的度量距离有欧式距离、城市街区距离、棋盘距离。以下以两坐标点 a = ( i , j ) a = (i, j) a=(i,j) b = ( k , l ) b = (k, l) b=(k,l) 的距离为例,来说明各种距离的定义方式:

(1)欧式距离 D e D_e De 欧式距离的定义源于经典的几何学,与我们数学中所学的简单几何的两点之间的距离一致,为两个像素点坐标值的平方根。欧式距离的优点在于其定义非常地直观,是显而易见的,但缺点在于平方根的计算是非常耗时的。

D e ( a , b ) = ( ( i − k ) 2 ) + ( j − l ) 2 D_e(a, b)=\sqrt{\left((i-k)^2\right)+(j-l)^2} De(a,b)=((ik)2)+(jl)2

(2)城市街区距离 D 4 D_4 D4 距离描述的是只允许像素坐标系平面中横向和纵向的移动距离,4表示在这种定义下,像素点是 4 邻接的,即每个点只与它的上、下、左、右相邻的 4 个点之间的距离为 1。

D 4 ( a , b ) = ∣ i − k ∣ + ∣ j − l ∣ D_4(a, b)=|i-k|+|j-l| D4(a,b)=ik+jl

(3)棋盘距离 D 8 D_8 D8 如果允许在图像坐标系中像素点的对角线方向的移动,就可以得到棋盘距离,8 表示在这种定义下,像素点是 8 邻接的,即每个点只与它的上、下、左、右、四个对角线方向相邻的 8 个点之间的距离为 1。

D 8 ( a , b ) = max ⁡ { ∣ i − k ∣ , ∣ j − l ∣ } D_8(a, b)=\max \{|i-k|,|j-l|\} D8(a,b)=max{ik,jl}


二、导入必要库

import numpy as np
import matplotlib.pyplot as plt# 设置字体样式以正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

三、距离变换算法

  • 距离变换是图像中像素点与某个区域块的距离。区域块中的像素点值为 0,临近区域块的像素点有较小的值,离它越远值越大。

以二值图像为例,其中区域块内部的像素值为 1,其他像素值为 0。距离变换给出每个像素点到最近的区域块边界的距离,区域块内部的距离变换结果为0。输入图像如图 1 所示, D 4 D_4 D4 距离的距离变换结果如图 2 所示。

  • 距离变换算法核心是利用两个小的局部掩膜对图像进行遍历。第一遍利用掩模1,左上角开始,从左往右,从上往下;第二遍利用第二个掩模,右下角开始,从右往左,从下往上。掩模形状如下图所示:

按照某种距离(如: D 4 D_4 D4 距离或 D 8 D_8 D8 距离)对大小为 M × N M×N M×N 的图像中的区域块作距离变换,算法过程如下:

(1) 建立一个大小为 M × N M×N M×N 的数组 F F F,作如下的初始化:将区域块中的元素设置为 0,其余元素设置为无穷;

(2) 利用掩模1(mask1),左上角开始,从左往右,从上往下遍历数组,将掩模中P点对应的元素的值作如下更新:

F ( P ) = min ⁡ q ∈ mask1 ⁡ { F ( P ) , D ( P , q ) + F ( q ) } F(P)=\min _{q \in \operatorname{mask1}}\{F(P), D(P, q)+F(q)\} F(P)=qmask1min{F(P),D(P,q)+F(q)}

(3) 利用掩模2(mask2),右下角开始,从右往左,从下往上遍历数组,将掩模中P点对应的元素的值作如下更新:

F ( P ) = min ⁡ q ∈ mask2 ⁡ { F ( P ) , D ( P , q ) + F ( q ) } F(P)=\min _{q \in \operatorname{mask2}}\{F(P), D(P, q)+F(q)\} F(P)=qmask2min{F(P),D(P,q)+F(q)}

最终得到的更新后的数组即为距离变换的结果。

因在边界处掩模不能全部覆盖图像,可以将掩模中没有对应元素的位置的值当作 0 来处理,以此对图像边界处做出调整,即maskSize=0


四、定义距离变换类

在距离变换类当中分别初始化距离变换类、定义欧氏距离和城市街区距离及棋盘距离的函数。

# 定义距离变换类
class DistanceTransform:# 初始化距离变换类def __init__(self, image):self.image = imageself.height, self.width = image.shape# 定义欧氏距离变换def Euclidean_distance_transform(self):distance_matrix = np.zeros_like(self.image, dtype=float)# 获取前景像素点的坐标yy, xx = np.argwhere(self.image == 1).Tfor y in range(self.height):for x in range(self.width):if self.image[y, x] == 1:distance_matrix[y, x] = 0else:# 计算当前像素到前景像素点的欧氏距离distances = np.sqrt((y - yy) ** 2 + (x - xx) ** 2)# 取最小值作为当前像素的距离值distance_matrix[y, x] = np.min(distances)return distance_matrix# 定义城市街区距离变换def D4_distance_transform(self):distance_matrix = np.zeros_like(self.image, dtype=float)yy, xx = np.argwhere(self.image == 1).Tfor y in range(self.height):for x in range(self.width):if self.image[y, x] == 1:distance_matrix[y, x] = 0else:# 计算当前像素到前景像素点的曼哈顿距离distances = np.abs(y - yy) + np.abs(x - xx)# 取最小值作为当前像素的距离值distance_matrix[y, x] = np.min(distances)return distance_matrix# 定义棋盘距离变换def D8_distance_transform(self):distance_matrix = np.zeros_like(self.image, dtype=float)yy, xx = np.argwhere(self.image == 1).Tfor y in range(self.height):for x in range(self.width):if self.image[y, x] == 1:distance_matrix[y, x] = 0else:# 计算当前像素到前景像素点的棋盘距离distances = np.maximum(np.abs(y - yy), np.abs(x - xx))# 取最小值作为当前像素的距离值distance_matrix[y, x] = np.min(distances)return distance_matrix

五、显示原始图像

# 初始化输入图像:480x480的全黑背景
image = np.zeros((480, 480), dtype=np.uint8)
# 取三个前景像素点
image[100, 200] = 1
image[200, 100] = 1
image[300, 300] = 1# 显示原始图像
plt.figure(figsize=(5, 5))
plt.scatter([100, 200, 300], [200, 100, 300], color='white', marker='o')
plt.imshow(image, cmap='gray')
plt.title('原始图像', fontsize=15)

六、计算并输出距离变换矩阵

# 计算距离变换矩阵
dt = DistanceTransform(image)
euclidean_distance_matrix = dt.Euclidean_distance_transform()
manhattan_distance_matrix = dt.D4_distance_transform()
chessboard_distance_matrix = dt.D8_distance_transform()# 输出欧氏、城区和棋盘的距离矩阵
print("欧氏距离的变换矩阵:\n", euclidean_distance_matrix)
print("城区距离的变换矩阵:\n", manhattan_distance_matrix)
print("棋盘距离的变换矩阵:\n", chessboard_distance_matrix)

七、可视化距离变换结果

# 可视化距离变换结果
plt.figure(figsize=(15, 5))# 欧氏距离变换
plt.subplot(1, 3, 1)
plt.imshow(euclidean_distance_matrix, cmap='gray')
plt.colorbar(shrink=0.8)
plt.title('欧氏距离', fontsize=15)
plt.axis('off')# 城区距离变换
plt.subplot(1, 3, 2)
plt.imshow(manhattan_distance_matrix, cmap='gray')
plt.colorbar(shrink=0.8)
plt.title('城区距离', fontsize=15)
plt.axis('off')# 棋盘距离变换
plt.subplot(1, 3, 3)
plt.imshow(chessboard_distance_matrix, cmap='gray')
plt.colorbar(shrink=0.8)
plt.title('棋盘距离', fontsize=15)
plt.axis('off')plt.tight_layout()
plt.show()

八、完整代码

import numpy as np
import matplotlib.pyplot as plt# 设置字体样式以正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 定义距离变换类
class DistanceTransform:# 初始化距离变换类def __init__(self, image):self.image = imageself.height, self.width = image.shape# 定义欧氏距离变换def Euclidean_distance_transform(self):distance_matrix = np.zeros_like(self.image, dtype=float)# 获取前景像素点的坐标yy, xx = np.argwhere(self.image == 1).Tfor y in range(self.height):for x in range(self.width):if self.image[y, x] == 1:distance_matrix[y, x] = 0else:# 计算当前像素到前景像素点的欧氏距离distances = np.sqrt((y - yy) ** 2 + (x - xx) ** 2)# 取最小值作为当前像素的距离值distance_matrix[y, x] = np.min(distances)return distance_matrix# 定义城市街区距离变换def D4_distance_transform(self):distance_matrix = np.zeros_like(self.image, dtype=float)yy, xx = np.argwhere(self.image == 1).Tfor y in range(self.height):for x in range(self.width):if self.image[y, x] == 1:distance_matrix[y, x] = 0else:# 计算当前像素到前景像素点的曼哈顿距离distances = np.abs(y - yy) + np.abs(x - xx)# 取最小值作为当前像素的距离值distance_matrix[y, x] = np.min(distances)return distance_matrix# 定义棋盘距离变换def D8_distance_transform(self):distance_matrix = np.zeros_like(self.image, dtype=float)yy, xx = np.argwhere(self.image == 1).Tfor y in range(self.height):for x in range(self.width):if self.image[y, x] == 1:distance_matrix[y, x] = 0else:# 计算当前像素到前景像素点的棋盘距离distances = np.maximum(np.abs(y - yy), np.abs(x - xx))# 取最小值作为当前像素的距离值distance_matrix[y, x] = np.min(distances)return distance_matrix# 初始化输入图像:480x480的全黑背景
image = np.zeros((480, 480), dtype=np.uint8)
# 取三个前景像素点
image[100, 200] = 1
image[200, 100] = 1
image[300, 300] = 1# 显示原始图像
plt.figure(figsize=(5, 5))
plt.scatter([100, 200, 300], [200, 100, 300], color='white', marker='o')
plt.imshow(image, cmap='gray')
plt.title('原始图像', fontsize=15)# 计算距离变换矩阵
dt = DistanceTransform(image)
euclidean_distance_matrix = dt.Euclidean_distance_transform()
manhattan_distance_matrix = dt.D4_distance_transform()
chessboard_distance_matrix = dt.D8_distance_transform()# 输出欧氏、城区和棋盘的距离矩阵
print("欧氏距离的变换矩阵:\n", euclidean_distance_matrix)
print("城区距离的变换矩阵:\n", manhattan_distance_matrix)
print("棋盘距离的变换矩阵:\n", chessboard_distance_matrix)# 可视化距离变换结果
plt.figure(figsize=(15, 5))# 欧氏距离变换
plt.subplot(1, 3, 1)
plt.imshow(euclidean_distance_matrix, cmap='gray')
plt.colorbar(shrink=0.8)
plt.title('欧氏距离', fontsize=15)
plt.axis('off')# 城区距离变换
plt.subplot(1, 3, 2)
plt.imshow(manhattan_distance_matrix, cmap='gray')
plt.colorbar(shrink=0.8)
plt.title('城区距离', fontsize=15)
plt.axis('off')# 棋盘距离变换
plt.subplot(1, 3, 3)
plt.imshow(chessboard_distance_matrix, cmap='gray')
plt.colorbar(shrink=0.8)
plt.title('棋盘距离', fontsize=15)
plt.axis('off')plt.tight_layout()
plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/823698.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

App Inventor 2 块拓展之:最大值、创建多项列表

什么是块拓展? App Inventor 2 引入了一项新功能,允许某些块扩展、收缩甚至更改其功能。 顶部具有蓝色框白色齿轮的代码块都是可拓展块。 块拓展用法 块扩展可以改变形状,通过单击蓝色图标,用户可以将较小的块拖到较大的块中&am…

雨伞-浅色脚本

渲染参考:明亮/干净/高级 静帧参考 解说 镜头时长 效果参考 中景画面展示3把竖着的浅色的伞 1s / 特写展示伞把手 1s 中景展示雨伞全貌 2s 微观镜头 缝线动画 3s 镜头旋转至伞面微观材质镜头,展现其多层结构 10s 微观镜头 水珠滑动在伞…

gpt4和chatgpt的区别

模型规模和性能:GPT-4比GPT-3.5更大、更强大。GPT-4拥有更多的参数和更大的训练数据集,因此在各种任务上表现更出色,如语言理解、问题解答和推理能力等。多模态能力:GPT-4支持处理图像等多模态信息,而GPT-3.5主要处理文…

服务器raid卡,守护数据安全,赋能新质生产力

RAID卡,全称为独立冗余磁盘阵列卡,在数据中心、服务器、网络存储等领域得到广泛应用,RAID卡通过不同的RAID级别实现数据容错和冗余。例如,RAID 0主要适用于需要高速数据传输但对数据安全要求不高的场景,如数据的缓存&a…

基于改进遗传算法的配电网故障定位(matlab代码)

1 主要内容 该程序复现文章《基于改进遗传算法的配电网故障定位》,将改进的遗传算法应用于配电网故障定位中, 并引入分级处理思想, 利用配电网呈辐射状的特点, 首先把整个配电网划分为主干支路和若干独立区域, 再利用该算法分别对各独立区域进行故障定位, 然后进行…

Node Version Manager(nvm):轻松管理 Node.js 版本的利器

文章目录 前言一、名词解释1、node.js是什么?2、nvm是什么? 二、安装1.在 Linux/macOS 上安装2.在 Windows 上安装 二、使用1.查看可安装的node版本2.安装node3. 查看已安装node4.切换node版本5.其它 总结 前言 Node.js 是现代 Web 开发中不可或缺的一部…

java的转换流,打印流,数据流

InputStreamReader(字符输入转换流) 解决不同编码,字符流读取文本内容乱码的问题 public InputStreamReader(InputStream in, String charsetName) throws UnsupportedEncodingException Creates an InputStreamReader that uses the named charset. 把原始的字节…

【华为笔试题汇总】2024-04-17-华为春招笔试题-三语言题解(Python/Java/Cpp)

🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为近期的春秋招笔试题汇总~ 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢&#x1f…

腾讯云优惠券介绍及领取教程详解

腾讯云是腾讯集团倾力打造的云计算品牌,提供全球领先的云计算、大数据、人工智能等技术产品与服务,以卓越的科技能力打造丰富的行业解决方案,构建开放共赢的云端生态,推动产业互联网建设,助力各行各业实现数字化升级。…

Python景区票务人脸识别系统

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

LeetCode236:二叉树的最近公共祖先

题目描述 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是…

YOLOv8 测试 5:Linux 中 Docker 部署 YOLOv8,Python 封装 API 接口,base64 图片处理

一、前言 记录时间 [2024-4-14] 系列文章简摘: Docker 学习笔记(二):在 Linux 中部署 Docker(Centos7 下安装 docker、环境配置,以及镜像简单使用) API 接口简单使用(二)…

Zabbix监控内容

目录 一、自定义监控内容 1、在客户端创建自定义key 1.1明确需要执行的linux命令 1.2创建zabbix监控项配置文件,用于自定义Key 1.3服务端验证测试 2、在Web界面创建自定义监控模板 2.1创建模板 2.2创建应用集(用于管理监控项) 2.3创建…

python-获取config.ini中的属性值

获取配置文件中的数据 import configparser class ReadConfig(object):def __init__(self,config_file_path):self.config configparser.ConfigParser()self.config.read(config_file_path,encodingutf-8)def get_config(self,section,option):config_valueself.config.get(s…

牛客NC197 跳跃游戏(一)【中等 动态规划 Java、Go、PHP】

题目 题目链接: https://www.nowcoder.com/practice/23407eccb76447038d7c0f568370c1bd 思路 答案说的merge区间就是每个A[i]的地方能跳到的最远坐标是A[i] [i], 有一个maxReach,遍历一遍A[i], 不断刷新MaxReach, 如果某个i 位置比maxReac…

进位制之间相互转换:二进制<=>八进制

示例&#xff1a; /*** brief how about carry-bin-otc? show you here.* author wenxuanpei* email 15873152445163.com(query for any question here)*/ #define _CRT_SECURE_NO_WARNINGS//support c-library in Microsoft-Visual-Studio #include <stdio.h> #inc…

Python可视化-matplotlib用法详解(三)

一、子图绘制 # 上节课复习 import pandas as pd import matplotlib.pyplot as plt s../../data/unrate.csvunrate pd.read_csv(s) unrate[DATE] pd.to_datetime(unrate[DATE]) first_twelve unrate[0:12] first_twelveDATEVALUE01948-01-013.411948-02-013.821948-03-014.…

【测试开发学习历程】python常用的模块(下)

目录 8、MySQL数据库的操作-pymysql 8.1 连接并操作数据库 9、ini文件的操作-configparser 9.1 模块-configparser 9.2 读取ini文件中的内容 9.3 获取指定建的值 10 json文件操作-json 10.1 json文件的格式或者json数据的格式 10.2 json.load/json.loads 10.3 json.du…

【八股】Redisson分布式锁

Redisson分布式锁 主要了解了Redisson分布式锁实现的三个功能&#xff1a; 1.可重入 -> 防止死锁 2.可重试&#xff08;i.e. 非阻塞获取锁&#xff09; 3.自动续约 1. 可重入 原理&#xff1a; 利用Redis的Hash结构&#xff0c;记录了使用当前锁的线程id和重用次数&#…

Linux系统——Elasticsearch企业级日志分析系统

目录 前言 一、ELK概述 1.ELK简介 2.ELK特点 3.为什么要使用ELK 4.完整日志系统基本特征 5.ELK工作原理 6.Elasticsearch介绍 6.1Elasticsearch概述 6.2Elasticsearch核心概念 7.Logstash介绍 7.1Logstash简介 7.2Logstash主要组件 8.Kibana介绍 8.1Kibana简介 …