【opencv】示例-distrans.cpp 距离变换

stuff.jpg



#include <opencv2/core/utility.hpp> // 包含OpenCV中的核心功能支持库
#include "opencv2/imgproc.hpp" // 包含OpenCV中的图像处理库
#include "opencv2/imgcodecs.hpp" // 包含OpenCV中的图像编解码库
#include "opencv2/highgui.hpp" // 包含OpenCV中的高级用户界面库#include <stdio.h> // 包含标准输入输出库using namespace std; // 使用标准命名空间
using namespace cv; // 使用OpenCV命名空间int maskSize0 = DIST_MASK_5; // 定义默认的掩膜大小为5x5
int voronoiType = -1; // 定义维诺图模式的初始类型,-1表示未激活维诺图模式
int edgeThresh = 100; // 边缘检测的阈值
int distType0 = DIST_L1; // 定义默认的距离变换类型为L1// 输出图像和临时图像
Mat gray;// 亮度阈值的回调函数
static void onTrackbar( int, void* )
{static const Scalar colors[] = // 预定义的颜色数组{Scalar(0,0,0),Scalar(255,0,0),Scalar(255,128,0),Scalar(255,255,0),Scalar(0,255,0),Scalar(0,128,255),Scalar(0,255,255),Scalar(0,0,255),Scalar(255,0,255)};int maskSize = voronoiType >= 0 ? DIST_MASK_5 : maskSize0; // 根据是否启用维诺图模式来选择掩膜大小int distType = voronoiType >= 0 ? DIST_L2 : distType0; // 根据是否启用维诺图模式来选择距离变换类型Mat edge = gray >= edgeThresh, dist, labels, dist8u; // 生成边缘图,距离图,标签图和8位显示图// 执行距离变换计算if( voronoiType < 0 )distanceTransform( edge, dist, distType, maskSize ); // 距离变换操作elsedistanceTransform( edge, dist, labels, distType, maskSize, voronoiType ); // 包含标签的距离变换// 如果没有激活维诺图模式,进行以下处理if( voronoiType < 0 ){// "绘画"距离变换结果的过程开始dist *= 5000;pow(dist, 0.5, dist); // 对距离变换结果取平方根以获得较好的显示效果Mat dist32s, dist8u1, dist8u2; // 用于转换数据类型的中间Mat变量dist.convertTo(dist32s, CV_32S, 1, 0.5); // 转换数据类型dist32s &= Scalar::all(255); // 将数值截断到[0, 255]范围内dist32s.convertTo(dist8u1, CV_8U, 1, 0); // 转换数据类型到8位无符号整型dist32s *= -1; // 取反dist32s += Scalar::all(255); // 增加255以避免负数值dist32s.convertTo(dist8u2, CV_8U); // 再次转换数据类型Mat planes[] = {dist8u1, dist8u2, dist8u2}; // 创建用于合并的平面数组merge(planes, 3, dist8u); // 合并三个平面成为一个3通道图像}// 如果激活了维诺图模式,进行以下处理else{dist8u.create(labels.size(), CV_8UC3); // 创建用于显示的8位3通道图像// 遍历图像中的所有像素for( int i = 0; i < labels.rows; i++ ){ //获取第i行的指针,并将其转换为指向int类型的指针。这样,ll就是指向labels图像第i行数据的指针,labels图像包含了沃罗诺伊图的标签信息。const int* ll = (const int*)labels.ptr(i);const float* dd = (const float*)dist.ptr(i);//获取dist图像第i行的指针,并将其转换为指向float类型的指针。dist图像包含了每个像素到最近的零像素点的距离uchar* d = (uchar*)dist8u.ptr(i);//获取输出图像(假设是dist8u)第i行的指针,并将其转换为指向uchar类型的指针。这里的dist8u是一个三通道的8位无符号整型图像,它将会被用来显示沃罗诺伊图及其颜色化的距离映射。for( int j = 0; j < labels.cols; j++ ){int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1; // 计算颜色索引float scale = 1.f/(1 + dd[j]*dd[j]*0.0004f); // 根据距离计算颜色缩放因子int b = cvRound(colors[idx][0]*scale); // 计算蓝色分量int g = cvRound(colors[idx][1]*scale); // 计算绿色分量int r = cvRound(colors[idx][2]*scale); // 计算红色分量d[j*3] = (uchar)b; // 设置蓝色分量d[j*3+1] = (uchar)g; // 设置绿色分量d[j*3+2] = (uchar)r; // 设置红色分量}}}imshow("Distance Map", dist8u ); // 显示距离图
}// 辅助输出函数,主要用于输出帮助信息
static void help(const char** argv)
{printf("\n本程序用于演示利用距离变换函数处理边缘图像之间的关系。\n""用法:\n""%s [image_name -- 默认图片为stuff.jpg]\n""\n快捷键:\n""\tESC - 退出程序\n""\tC - 使用C/Inf度量\n""\tL1 - 使用L1度量\n""\tL2 - 使用L2度量\n""\t3 - 使用3x3掩码\n""\t5 - 使用5x5掩码\n""\t0 - 使用精确距离变换\n""\tv - 切换到Voronoi图模式\n""\tp - 切换到基于像素的Voronoi图模式\n""\tSPACE - 遍历所有的模式\n\n", argv[0]);
}const char* keys =
{"{help h||}{@image |stuff.jpg|input image file}"
};int main( int argc, const char** argv )
{CommandLineParser parser(argc, argv, keys); // 使用命令行解析器来处理输入参数help(argv); // 显示帮助信息if (parser.has("help")) // 如果命令行包含帮助标志(例如-h或--help)return 0; // 返回0并退出,不执行接下来的代码string filename = parser.get<string>(0); // 获取命令行中的第一个参数,通常是输入图像的文件名gray = imread(samples::findFile(filename), 0); // 读取输入的图像,并转换为灰度图if(gray.empty()) // 判断读取的图像是否为空{printf("无法读取图像文件:%s\n", filename.c_str()); // 如果为空,打印错误信息help(argv); // 再次显示帮助信息return -1; // 返回-1表示错误退出}namedWindow("Distance Map", 1); // 创建一个名为"Distance Map"的窗口createTrackbar("Brightness Threshold", "Distance Map", &edgeThresh, 255, onTrackbar, 0); // 创建一个调整‘亮度阀值’的trackbarfor(;;) // 创建一个无限循环{onTrackbar(0, 0); // 调用回调函数,更新显示的视图char c = (char)waitKey(0); // 等待用户按键if( c == 27 ) // 如果按下ESC键(键码27)break; // 退出循环if( c == 'c' || c == 'C' || c == '1' || c == '2' || // 根据按键设置相关参数c == '3' || c == '5' || c == '0' )voronoiType = -1; // 重置voronoiTypeif( c == 'c' || c == 'C' )distType0 = DIST_C; // 设置距离变换为C类型else if( c == '1' )distType0 = DIST_L1; // 设置距离变换为L1类型else if( c == '2' )distType0 = DIST_L2; // 设置距离变换为L2类型else if( c == '3' )maskSize0 = DIST_MASK_3; // 设置掩码大小为3x3else if( c == '5' )maskSize0 = DIST_MASK_5; // 设置掩码大小为5x5else if( c == '0' )maskSize0 = DIST_MASK_PRECISE; // 设置掩码大小为精确模式else if( c == 'v' )voronoiType = 0; // 切换到Voronoi图模式else if( c == 'p' )voronoiType = 1; // 切换到基于像素的Voronoi图模式else if( c == ' ' ) // 当用户按下空格键时{if( voronoiType == 0 ) // 如果当前是Voronoi图模式(基于标签)voronoiType = 1; // 切换到pixel-based Voronoi diagram mode(像素级)else if( voronoiType == 1 ) // 如果当前是像素级的Voronoi图模式{voronoiType = -1; // 关闭Voronoi图模式maskSize0 = DIST_MASK_3; // 重置掩码大小为3x3distType0 = DIST_C; // 重置距离类型为C/Inf度量}else if( distType0 == DIST_C ) // 如果当前距离类型为C/Inf度量distType0 = DIST_L1; // 切换到L1度量else if( distType0 == DIST_L1 ) // 如果当前距离类型为L1度量distType0 = DIST_L2; // 切换到L2度量else if( maskSize0 == DIST_MASK_3 ) // 如果当前掩码大小为3x3maskSize0 = DIST_MASK_5; // 切换到5x5掩码大小else if( maskSize0 == DIST_MASK_5 ) // 如果当前掩码大小为5x5maskSize0 = DIST_MASK_PRECISE; // 切换到精确的距离变换else if( maskSize0 == DIST_MASK_PRECISE ) // 如果当前是精确的距离变换voronoiType = 0; // 开启Voronoi图模式(基于标签)}}return 0; // 程序正常退出
} 这段代码是一个使用OpenCV库函数,实现了基于距离变换的图像边缘检测,并由用户输入不同键值来调节距离度量方式、掩码大小及是否进入Voronoi图模式的C++程序示例。程序的主体会根据用户输入的图像文件,展示并允许用户通过交互式的方式(例如调节阈值的trackbar),来实时观察不同算法参数下的距离变换结果。程序还支持展示Voronoi图,用户可以通过键盘输入控制变换参数,探索对图像处理的影响。
distanceTransform( edge, dist, distType, maskSize ); 
distanceTransform( edge, dist, labels, distType, maskSize, voronoiType ); 

v

p
这段代码是一个OpenCV的示例程序,演示了如何使用距离变换函数(distance transform)在边缘图像之间的应用。
全局变量:
maskSize0: 用于调整掩码大小,初始设置为DIST_MASK_5。voronoiType: 用于切换绘制沃罗诺伊图,初始值为 -1,表示未激活该模式。edgeThresh: 边缘阈值,默认为100。distType0: 距离类型,默认是DIST_L1。gray: 一个Mat对象,用来存储灰度图像。
主要函数:
解析命令行参数,加载灰度图像。
创建一个显示距离映射的窗口和对应的滑动条。
进入一个无限循环,监听按键事件以改变距离变换的参数或是退出程序。
首先根据是否在沃罗诺伊模式下设置距离类型和掩码大小。
使用
distanceTransform函数计算边缘图像的距离变换。如果不是沃罗诺伊模式,则对结果进行渲染并显示在窗口中。
如果是沃罗诺伊模式,则根据距离和标签值对颜色进行缩放,以绘制沃罗诺伊图。
onTrackbar: 这个回调函数会响应滑动条变化,它计算边缘图像的距离变换,并将结果绘制在窗口中。help: 显示帮助信息,列出了程序的用法和键盘操作指南。main: 程序的主入口。
按键指南包括对距离计算方法(C/Inf、L1、L2)、掩码大小(3x3、5x5)、距离变换精确度以及绘制沃罗诺伊图模式的切换支持。输入图片名称可以通过命令行参数提供,如果未提供参数则默认使用 "stuff.jpg" 图片。
整体来说,这个程序可以让用户通过改变参数来探索不同的距离度量和掩码对距离变换效果的影响,以及如何生成沃罗诺伊图。
相关文章:
【opencv】示例-distrans.cpp 距离变换
stuff.jpg #include <opencv2/core/utility.hpp> // 包含OpenCV中的核心功能支持库 #include "opencv2/imgproc.hpp" // 包含OpenCV中的图像处理库 #include "opencv2/imgcodecs.hpp" // 包含OpenCV中的图像编解码库 #include "open…...
LVGL V8 代码细读——极致的链表使用
极致的链表的使用 序章碎碎念从redis源码里掏出来的adlist极致的精简的list.hlvgl对链表的巧思lv_ll尾记 序章碎碎念 对于链表,大家应该都不陌生。学过数据结构的,都知道它作为链式储存的基础,重要性不言而喻。 由于本人自动化专业ÿ…...
蓝桥杯第十二届c++大学B组详解
目录 1.空间 2.直线 3.路径 4.卡片 5.货物摆放 6.时间显示 7.砝码称重 8.杨辉三角 9.双向排序 10.括号序列 1.空间 题目解析:1Byte 8bit 1kb 1024B 1MB 1024kb; 先将256MB变成Byte 256 * 1024 * 1024; 再将32位 变成Byte就是 32 / 8 4;…...
Tubi 十岁啦!
Tubi 今年十岁了,这十年不可思议,充满奇迹! 从硅谷一个名不见经传的创业小作坊,转变成为四分之一美国电视家庭提供免费流媒体服务的北美领先的平台; 从费尽心力终于签下第一笔内容合作协议,到现在与 450 …...
Qt C++ 实现文件监视源码
以下是使用Qt C++实现文件监视的一个简单示例代码: #include <QCoreApplication> #include <QFileSystemWatcher> #include <QDebug>int main(int argc, char *argv[...
蓝桥杯第十一届c++大学B组详解
目录 1.字符串排序 2.门牌制作 3.即约分数 4.蛇型填数 5.跑步锻炼 6.七段码 7.成绩统计 8.回文日期 9.字串分值和 10.平面切分 1.字符串排序 题目解析:这个题目真没搞懂。有会的大佬教我一下谢谢。 2.门牌制作 题目解析:出过超级多这类题目&am…...
大模型日报2024-04-10
大模型日报 2024-04-10 大模型资讯 微软研究者提出通过可视化思维提升大型语言模型的空间推理能力 摘要: 微软研究者近日提出了一种新方法,旨在通过可视化思维来增强大型语言模型(LLMs)的空间推理能力。尽管LLMs在语言理解和推理任务方面表现…...
redis修改协议改了,有哪些替代品?
Redis 是一款广泛使用的开源内存数据结构存储,它支持多种数据结构,如字符串、哈希表、列表、集合、有序集合等。然而,由于 Redis 最近更改了其开源许可证,一些用户和开发者可能正在寻找替代品。以下是一些 Redis 的替代品…...
《QT实用小工具·十六》IP地址输入框控件
1、概述 源码放在文章末尾 该项目为IP地址输入框控件,主要包含如下功能: 可设置IP地址,自动填入框。 可清空IP地址。 支持按下小圆点自动切换。 支持退格键自动切换。 支持IP地址过滤。 可设置背景色、边框颜色、边框圆角角度。 下面…...
windows 系统下 mysql 数据库的下载与安装(包括升级安装)
windows 系统下 mysql 数据库的下载与安装(包括升级安装) 一、mysql 介绍: MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,属于 Oracle 旗下产品。 MySQL 是最流行的关系型数据库管理系统之一…...
Redis Stack十部曲之三:理解Redis Stack中的数据类型
文章目录 前言String字符串作为计数器限制 List限制列表阻塞列表自动创建和删除聚合类型键限制 Set限制 Hash限制 Sorted Set范围操作字典操作更新分数 JSON路径限制 BitMapBitfieldProbabilisticHyperLogLogBloom filterCuckoo filtert-digestTop-KCount-min sketchConfigurat…...
OneForAll安装使用
OneForAll简介 OneForAll是一款功能强大的子域收集工具 原项目地址:GitHub - shmilylty/OneForAll: OneForAll是一款功能强大的子域收集工具 gitee项目地址:OneForAll: OneForAll是一款功能强大的子域收集工具 # 安装Python Windows系统安装python参…...
【现代C++】线程支持库
现代C(C11及其之后的版本)引入了标准的线程支持库,使得多线程编程变得更加简单和可移植。这个库提供了线程管理、互斥量、条件变量和其他同步原语。 1. std::thread - 基本线程 std::thread允许创建执行特定任务的线程。 #include <ios…...
游戏引擎架构01__引擎架构图
根据游戏引擎架构预设的引擎架构来构建运行时引擎架构 ...
[Java、Android面试]_15_Android为什么使用Binder?
Android为什么使用Binder?用 Linux原有的IPC不行吗? 本人今年参加了很多面试,也有幸拿到了一些大厂的offer,整理了众多面试资料,后续还会分享众多面试资料。 整理成了面试系列,由于时间有限,每天…...
Python+Selenium+Unittest 之Unittest3(TestSuite()和TextTestRunner())
目录 1:addTest() 2、addTests() 3:discover() 上一篇说了Unittest的一个基本的执行顺序,那如果我们想要调整用例的执行先后顺序的话,可以用TestSuite()和TextTestRunner()了,可以这么理解,比如一个班级…...
3D桌面端可视化引擎HOOPS Visualize如何实现3D应用快速开发?
HOOPS Visualize是一个开发平台,可实现高性能、跨平台3D工程应用程序的快速开发。一些主要功能包括: 高性能、以工程为中心的可视化,使用高度优化的OpenGL或DirectX驱动程序来充分利用可用的图形硬件线程安全的C和C#接口,内部利用…...
Vue探索之Vue2.x源码分析(二)
一.Virtual Dom 虚拟DOM是一种轻量级的抽象,它允许我们在Javascript中创建、更新和删除DOM元素。它是React等现代Javascript框架的核心概念之一。 Vue的虚拟dom是一种抽象层的概念,它使得Vue可以高效地更新Dom。虚拟Dom是通过Javascript对象来表示DOM结…...
人工智能分类算法概述
文章目录 人工智能主要分类算法决策树随机森林逻辑回归K-均值 总结 人工智能主要分类算法 人工智能分类算法是用于将数据划分为不同类别的算法。这些算法通过学习数据的特征和模式,将输入数据映射到相应的类别。分类算法在人工智能中具有广泛的应用,如图…...
理解 Golang 变量在内存分配中的规则
为什么有些变量在堆中分配、有些却在栈中分配? 我们先看来栈和堆的特点: 简单总结就是: 栈:函数局部变量,小数据 堆:大的局部变量,函数内部产生逃逸的变量,动态分配的数据&#x…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
