计算机视觉 | 基于二值图像数字矩阵的距离变换算法

Hi,大家好,我是半亩花海。本实验基于 OpenCV 实现了二值图像数字矩阵的距离变换算法。首先生成一个 480x480 的黑色背景图像(定义黑色为0,白色为1),在其中随机选择了三个白色像素点作为距离变换的原点,利用 OpenCV 中 distanceTransform 等相关函数计算并输出这些原点到其他像素点的欧氏距离、D4 距离和 D8 距离及其相应的距离矩阵,并将距离变换结果可视化

文章目录

  • 一、导入必要库
  • 二、初始化输入图像和变换结果图像
  • 三、根据二值图计算并输出距离矩阵
  • 四、将距离矩阵转换为可视化图片

一、导入必要库

导入必要的库(cv2、numpy、matplotlib.pyplot),为后续的图像处理任务做准备。

#!/usr/bin/env python
# coding: utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 用来设置字体样式(黑体)以正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

二、初始化输入图像和变换结果图像

自定义 480x480 二值图,随机生成图案,初始值都是 0(黑色),并显示原始图像。

  • 图像数字化:
    通过传感器获得的图像是平面坐标 ( x , y ) (x,y) (x,y) 的连续函数 f ( x , y ) f(x,y) f(x,y),它的值图像对应位置的亮度。为了能够让计算机来处理,需要对图像进行采样,并且对亮度值进行量化。

    • 采样: 对连续函数 f ( x , y ) f(x,y) f(x,y) 进行采样,就是分别对 x x x 轴和 y y y 轴,按照固定间隔取值,得到平面坐标上的 M × N M×N M×N 个点,将其函数值作为元素生成 M M M N N N 列的矩阵。

    • 量化亮度值。 f ( x , y ) f(x,y) f(x,y) 的值转化为等价的整数值的过程称为量化,量化的级别越高,图像越细致。通常将亮度值表示为 0~255 之间的整数。

# 创建一个大小为 480x480 的全黑图像(确保数据类型为 8 位无符号整数)
mat = np.zeros((480, 480), dtype=np.uint8)
# 给输入图像指定三个像素点设置为白色像素,作为距离变换原点(区域块)
mat[100, 200] = 1
mat[200, 100] = 1
mat[300, 300] = 1

# 显示原始图像和距离变换结果
plt.figure(figsize=(15, 5))
plt.scatter([100, 200, 300], [200, 100, 300], color='white', marker='o')  # 添加三个白点表示出三个像素点的坐标
plt.imshow(mat, cmap='gray')
plt.title('原始图像', fontsize=16)
# 将输入图像中 1(白色)和 0(黑色)调换,使得原点距离为 0
mat = 1 - mat

三、根据二值图计算并输出距离矩阵

  • 距离: 距离是描述图像两点像素之间的远近关系的度量,常见的度量距离有欧式距离(Euchildean distance)、城市街区距离(City block distance)、棋盘距离(Chessboard distance)。以下以两坐标点 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}

  • 距离变换

距离变换也叫作距离函数或者斜切算法。它是距离概念的一个应用,图像处理的一些算法以距离变换为基础。距离变换描述的是图像中像素点与某个区域块的距离,区域块中的像素点值为 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

在 OpenCV 中,distanceTransform 函数是用于计算二进制图像中每个非零像素到最近零像素的距离的函数。这个函数通常用于图像处理中的形态学操作和特征提取。下面是 distanceTransform 函数的一般形式:

dist_transform = cv2.distanceTransform(src, distanceType, maskSize)

  • src: 是输入的二进制图像(该图像应该是一个 8 位单通道图像)。

  • distanceType: 是指定距离度量的类型。

  • maskSize: 是指定计算距离时使用的卷积核的大小。

# 分别利用欧式距离、D4 距离和 D8 距离作距离变换
transMatE = cv2.distanceTransform(mat, distanceType=cv2.DIST_L2, maskSize=0)  # 计算欧氏距离变换
transMatD4 = cv2.distanceTransform(mat, distanceType=cv2.DIST_L1, maskSize=0)  # 计算 D4 距离变换
transMatD8 = cv2.distanceTransform(mat, distanceType=cv2.DIST_C, maskSize=0)  # 计算 D8 距离变换
# 输出欧式、D4 和 D8 的距离矩阵
print("欧氏距离的变换矩阵:\n", transMatE)
print("城区距离-D4的变换矩阵:\n", transMatD4)
print("棋盘距离-D8的变换矩阵:\n", transMatD8)

四、将距离矩阵转换为可视化图片

因为经过距离矩阵变换之后,变换结果的数据类型为 float32(32 位浮点数),而在 OpenCV 中,采用 imshow 函数显示图像时需要使用 uint8 数据类型(8 位无符号整数),使得像素值的范围是从 0~255,可以表示灰度图像中的所有可能像素值。而 Matplotlib 可以直接处理 float32 类型的图像数据,因此并不需要将图像数据类型转换为 uint8 类型。

plt.figure(figsize=(15, 5))

plt.subplot(1, 3, 1)
plt.imshow(transMatE, cmap='gray')
plt.title('欧氏距离', fontsize=16)
plt.colorbar(shrink=0.8)

plt.subplot(1, 3, 2)
plt.imshow(transMatD4, cmap='gray')
plt.title('城区距离-D4', fontsize=16)
plt.colorbar(shrink=0.8)

plt.subplot(1, 3, 3)
plt.imshow(transMatD8, cmap='gray')
plt.title('棋盘距离-D8', fontsize=16)
plt.colorbar(shrink=0.8)

plt.tight_layout()
plt.show()

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RTSP/Onvif安防视频EasyNVR平台 vs.多协议接入视频汇聚EasyCVR平台:设备分组的区别

EasyNVR安防视频云平台是旭帆科技TSINGSEE青犀旗下支持RTSP/Onvif协议接入的安防监控流媒体视频云平台。平台具备视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力,能对接入的视频流进行处理与多端分发,包括RTSP、RTMP、HTTP-FLV、W…

HWOD:投票统计

一、知识点 1、单词 候选人的英文是Candidate 投票的英文是vote 投票人的英文是voter 2、for循环 如果在for循环内将i置为n,结束该层循环后,for循环会先给i加1,然后再去判读i是否小于n,所以for循环结束后,i的值为n1 3、字符…

LeetCode 239. 滑动窗口最大值

滑动窗口最大值 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1: 输入:nums [1,3,-1,-3,…

用html实现一个动态的文字框

<!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>一个动态的文字框动画</title><link rel"stylesheet" href"./style.css"></head> <body> <link rel…

Centos7下docker的jenkins下载并配置jdk与maven【图文教程】

个人记录 进入目录 cd /usr/local/JDK下载与配置 OpenJDK官网 下载安装 wget https://download.java.net/openjdk/jdk18/ri/openjdk-1836_linux-x64_bin.tar.gz解压 tar -zxvf openjdk-1836_linux-x64_bin.tar.gz ls ls jdk-18/编辑配置文件 vim /etc/profile配置环境变…

[C++]让C++的opencv库支持写出h264格式视频

当我们写下面测试代码时候&#xff1a; #include <opencv2/opencv.hpp>int main() {cv::VideoCapture cap("E:\\car.mp4"); // 打开默认摄像头if (!cap.isOpened()) {std::cout << "读取完毕!" << std::endl;return -1;}double fps ca…

上线数日暴涨600%市值直逼节点猴,Runestone符石为何成第二大比特币NFT?

NodeMonkes&#xff08;节点猴&#xff09;市值超越BAYC成为第二大NFT之际&#xff0c;凭借着不断上涨的市场热度和人气&#xff0c;符文项目Runestone在空投数日后也成功跻身为比特币生态市值第二大NFT。Runestone高共识背后的动因有哪些&#xff1f;又有哪些策略具有借鉴意义…

Dubbo的使用和相关概念

参考官网 大致流程图 1. 初始化项目 参考官网进行项目的初始化即可。 2. 相关配置 主要参考官网&#xff1a;这里仅给出提示 application.yml dubbo:application:name: dubbo-springboot-demo-consumerprotocol:name: dubboport: -1registry:address: zookeeper://${zo…

考研数学|武忠祥各阶段用书搭配及分享

看到有人问武忠祥老师&#xff0c;不请自来 武忠祥老师&#xff0c;绝对的宝藏老师&#xff0c;我在考研强化阶段的时候听过他的强化课程&#xff0c;听完之后&#xff0c;很多问题都想通了&#xff0c;所以&#xff0c;如果有人想问武忠祥老师行不行&#xff0c;那我就一个字…

基于FPGA的以太网相关文章导航

首先需要了解以太网的一些接口协议标准&#xff0c;常见的MII、GMII、RGMII时序&#xff0c;便于后续开发。 【必读】从MII到RGMII&#xff0c;一文了解以太网PHY芯片不同传输接口信号时序&#xff01; 介绍一款比较老的以太网PHY芯片88E1518&#xff0c;具有RGMII接口&#xf…

代码学习记录40---动态规划

随想录日记part40 t i m e &#xff1a; time&#xff1a; time&#xff1a; 2024.04.10 主要内容&#xff1a;今天开始要学习动态规划的相关知识了&#xff0c;今天的内容主要涉及&#xff1a; 买卖股票的最佳时机加强版。 123.买卖股票的最佳时机III 188.买卖股票的最佳时机…

李廉洋:4.11黄金原油早盘#行情走势#分析及策略。

美国通胀数据超出预期&#xff0c;抑制了对美联储降息的押注。Coex Partners有限公司宏观经济学家Henrik Gullberg表示&#xff1a;“对新兴市场和风险资产来说&#xff0c;(通胀)高企持续时间更长是个坏消息&#xff0c;还因为它增加了美国和全球经济更明显下滑的风险。CPI数据…

代码随想录--数组--二分查找

数组理论基础 数组是存放在连续内存空间上的相同类型数据的集合。 数组可以方便的通过下标索引的方式获取到下标下对应的数据。 举一个字符数组的例子&#xff0c;如图所示&#xff1a; 需要两点注意的是 数组下标都是从0开始的。 数组内存空间的地址是连续的。 正是因为数…

lv逻辑卷(虚拟磁盘)及配额实操

、LVM 1.LVM概念 LVM逻辑卷管理&#xff08;Logical Volume Manager&#xff09;&#xff1a;LVM 适合于管理大存储设备&#xff0c;并允许用户动态调整磁盘容量大小&#xff0c;提高磁盘管理的灵活性。LVM的快照功能可以帮助我们快速备份数据。 2.LVM对比磁盘分区的优点 1…

IP查询在追踪网络攻击源头中的应用

随着网络攻击事件的不断增加&#xff0c;追踪攻击源头成为网络安全领域的重要任务之一。IP查询技术通过分析网络流量中的IP地址&#xff0c;可以帮助确定攻击的来源。本文将探讨IP查询在追踪网络攻击源头中的应用&#xff0c;包括其原理、方法以及实际案例分析。 IP地址查询&a…

git学习 1

打开自己想要存放git仓库的文件夹&#xff0c;右键打开git bush&#xff0c;用git init命令建立仓库 用 ls -a(表示全都要看&#xff0c;包括隐藏的)可以看到git仓库 也可以用 git clone 接github链接&#xff08;点code选项里面会给链接&#xff0c;结尾是git的那个&#xf…

LeetCode - 1702. 修改后的最大二进制字符串

文章目录 解析AC CODE 题目链接&#xff1a;LeetCode - 1702. 修改后的最大二进制字符串 解析 详细题解&#xff1a;贪心&#xff0c;简洁写法&#xff08;Python/Java/C/Go/JS/Rust&#xff09; 思路很牛b。 简单来说我们需要想办法将0配对&#xff0c;将其变为10&#xff0…

AI日报:GPT-4-Turbo正式版自带读图能力;Gemini1.5Pro开放API;SD3将于4月中旬发布;抖音宫崎骏AI特效爆火

欢迎来到【AI日报】栏目!这里是你每天探索人工智能世界的指南&#xff0c;每天我们为你呈现AI领域的热点内容&#xff0c;聚焦开发者&#xff0c;助你洞悉技术趋势、了解创新AI产品应用。 新鲜AI产品点击了解&#xff1a;AIbase - 智能匹配最适合您的AI产品和网站 &#x1f4f…

机器人路径规划:基于Q-learning算法的移动机器人路径规划(可以更改地图,起点,终点),MATLAB代码

一、Q-learning算法 Q-learning算法是强化学习算法中的一种&#xff0c;该算法主要包含&#xff1a;Agent、状态、动作、环境、回报和惩罚。Q-learning算法通过机器人与环境不断地交换信息&#xff0c;来实现自我学习。Q-learning算法中的Q表是机器人与环境交互后的结果&#…

Redis中的集群(五)

集群 在集群中执行命令 MOVED错误。 当节点发现键所在的槽并非由自己负责处理的时候&#xff0c;节点就会向客户端返回一个MOVED错误&#xff0c;指引客户端转向至正在负责槽的节点&#xff0c;MOVED错误的格式为: MOVED <slot> <ip>:<port>其中slot为键…