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

news2024/11/25 16:24:19

f02abca910ffc3f94b0faa6a95826163.jpeg

stuff.jpg

006de25e1ba1b3b6f6ca809008149052.png

6513471157952e94cd5538403c8b60b8.gif

69547acc388be9200f8c0300ad6c81b5.png

#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 );   // 距离变换操作
    else
        distanceTransform( 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); // 创建一个调整‘亮度阀值’的trackbar


    for(;;) // 创建一个无限循环
    {
        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; // 重置voronoiType


        if( 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; // 设置掩码大小为3x3
        else if( c == '5' )
            maskSize0 = DIST_MASK_5; // 设置掩码大小为5x5
        else 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; // 重置掩码大小为3x3
                distType0 = 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 ) // 如果当前掩码大小为3x3
                maskSize0 = DIST_MASK_5; // 切换到5x5掩码大小
            else if( maskSize0 == DIST_MASK_5 ) // 如果当前掩码大小为5x5
                maskSize0 = DIST_MASK_PRECISE; // 切换到精确的距离变换
            else if( maskSize0 == DIST_MASK_PRECISE ) // 如果当前是精确的距离变换
                voronoiType = 0; // 开启Voronoi图模式(基于标签)
        }
    }
    return 0; // 程序正常退出
}

这段代码是一个使用OpenCV库函数,实现了基于距离变换的图像边缘检测,并由用户输入不同键值来调节距离度量方式、掩码大小及是否进入Voronoi图模式的C++程序示例。程序的主体会根据用户输入的图像文件,展示并允许用户通过交互式的方式(例如调节阈值的trackbar),来实时观察不同算法参数下的距离变换结果。程序还支持展示Voronoi图,用户可以通过键盘输入控制变换参数,探索对图像处理的影响。

distanceTransform( edge, dist, distType, maskSize );

2b6d82ecc5235f3ee496fb4ef3b24532.png

distanceTransform( edge, dist, labels, distType, maskSize, voronoiType );

774d3b324a7dcb36bf154310567abef7.png

5f8a476b598420621be1e7a0b1587ed5.png

v

5f483cc797ff0d0296fdefcffd2cce6e.png

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" 图片。

整体来说,这个程序可以让用户通过改变参数来探索不同的距离度量和掩码对距离变换效果的影响,以及如何生成沃罗诺伊图。

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

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

相关文章

微信小程序picker设置了系统年度,打开选择年份从1年开始显示

背景&#xff1a;开发微信小程序时&#xff0c;使用了picker组件&#xff0c;设置值为当前系统时间年份&#xff0c;可以正常回显年份。但是打开面板选择年份的时候&#xff0c;默认从一年开始显示的。如下图所示。 原因&#xff1a;因为绑定的年份字段为Number类型。 解决方案…

App Inventor 2 怎么判断两个颜色是否相等?

问&#xff1a;为什么这里不能判断这个背景颜色呢&#xff1f; 答&#xff1a;背景颜色不是 bool 型&#xff0c;不能直接插入判断积木。 本帖隐藏的内容 要使用 等于&#xff08;推荐数学块.等于&#xff0c;当然文本块.等于也可以&#xff09; 来判断才行。 经检验&…

java错误记录

文章目录 javaslf4j中log不存在 maven编译出现Non-resolvable import POM: Failure to find类找不到jdk版本不对 java slf4j中log不存在 解决方法&#xff1a;再idea中安装lombok插件。 离线下载地址 https://github.com/mplushnikov/lombok-intellij-plugin/releases&#x…

爬虫 selenium

爬虫 selenium 【一】介绍 【1】说明 Selenium是一款广泛应用于Web应用程序测试的自动化测试框架 它可以模拟用户再浏览器上的行为对Web应用进行自动化测试 主要作用&#xff1a; 浏览器控制&#xff1a;启动、切换、关闭不同浏览器元素定位于操作&#xff1a;通过CSS选择器…

突破编程_前端_SVG(概述)

1 什么是 SVG SVG&#xff0c;全称可缩放矢量图形&#xff08;Scalable Vector Graphics&#xff09;&#xff0c;是一种基于 XML&#xff08;可扩展标记语言&#xff09;的矢量图像格式。这种图像格式的主要特点是它描述的是矢量图形&#xff0c;而不是基于像素的位图图像。因…

计数排序解读

当我们提及排序算法时&#xff0c;通常会想到冒泡排序、选择排序、插入排序、归并排序和快速排序等经典算法。然而&#xff0c;今天我们要探讨的是一种非比较型整数排序算法——计数排序。计数排序在某些特定场景下表现出色&#xff0c;具有线性的时间复杂度。下面我们将深度剖…

如何看待现在的前端?必备技能和方向?

​ 目录 1. 技术生态丰富 2. 用户体验为中心 3. 跨平台和移动优先 4. 性能和安全性 5. 前端工程化和自动化 6. 服务端渲染和静态站点生成 7. 人工智能和机器学习的融合 总结 发展方向&#xff1a; 必备技能&#xff1a; 当前前端开发领域正在经历快速的发展和变革。…

Three飞线动画(运动轨迹)

效果图 1.初始化场景 onMounted(() > {line() })let index 0; //取索引值的点的位置 let num 20; //从曲线上获取的数量 let points1, newLine1, bufferGeometry1; let points2, newLine2, bufferGeometry2;function line() {} 2.场景中加入一条三维曲线 function line…

Flody算法求解多源最短路问题

Flody算法求解多源最短路问题 蓝桥公园 #include <bits/stdc.h> using namespace std; #define int long long const int N409; int n,m,q,d[N][N]; signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m>>q;memset(d,0x3f,sizeof…

Linux网卡与IP地址:通往网络世界的通行证

在探索Linux网卡和IP地址的关系之前&#xff0c;我们得先理解Linux网卡是怎么工作的。想象一下&#xff0c;每台计算机都是一个世界&#x1f30e;&#xff0c;而网卡就是连接这些世界的门户&#x1f6aa;。网卡的工作就是接收和发送数据包&#xff0c;就像邮差&#x1f4ec;递送…

在win10上虚拟一个LoongOS系统(类似虚拟机)作为开发环境

文章目录 1.安装1.1.下载这三个东西1.2.安装好qemu。1.3.创建一个启动脚本startup_mate.bat&#xff0c;然后把三部分东西放到一起1.4.然后双击startup.bat就可以启动了。 2.文件的传输2.1.使能虚拟机系统的ssh2.2.连接ssh 3.Qt相关安装Qt安装opencv 1.安装 注意&#xff0c;一…

揭秘操作系统:核心功能与Linux系统解析

1.引言 在先前探讨中&#xff0c;我们了解到计算机主机内部的硬件资源需要一种高效管控手段&#xff0c;由此催生了操作系统的诞生。操作系统&#xff08;Operating System&#xff0c;简称OS&#xff09;&#xff0c;是计算机生态系统中不可或缺的核心组件&#xff0c;以其复杂…

高颜值高性能的开源免费自托管照片和视频备份方案:Immich

Immich&#xff1a;安全存储您的珍贵记忆&#xff0c;高颜值且高性能的自托管照片与视频备份解决方案&#xff0c;让您随时随地无忧回顾美好时光。- 精选真开源&#xff0c;释放新价值。 概览 在数字化时代&#xff0c;我们的照片和视频越来越多&#xff0c;如何安全、有效地备…

DSP笔记12-PWM基础知识及EPWM

PWM pulse width modulation 脉冲宽度调制&#xff0c;宽度可调节的方波脉冲&#xff0c;驱动开关器件&#xff0c; 参数&#xff1a; 1.频率f 1kHz&#xff0c;2kHz开关损耗 2.周期T 3.幅值&#xff0c;高低电平之间电压 gpio输出3.3V&#xff0c;转换成5V高电平输出 4.占…

Vue项目中,使用高级表格vxe-table中的【vxe-grid】动态列之动态插槽

1、首先项目当中得安装了vxe-table // 没有安装的话&#xff0c;可以使用一下命令安装 npm install vxe-table 或 yarn add vxe-table使用示例&#xff1a; import Vue from vue import VXETable from vxe-table import vxe-table/lib/style.cssVue.use(VXETable)2、动态列中动…

苍穹外卖---文件上传-阿里OSS

一&#xff1a;开通阿里云对象存储服务oss,创建bucket&#xff0c;获得密钥 二&#xff1a;在程序中集成上传文件功能 1.连接阿里云OSS对象存储服务器 声明一个配置属性的文件用于传入连接的参数 package com.sky.properties;import lombok.Data; import org.springframewo…

电感在 DC/DC 变换器中的作用及选型指南

消费类应用是现代 DC/DC 变换器需求的主要驱动力。在这类应用中&#xff0c;功率电感主要被用于电池供电设备、嵌入式计算&#xff0c;以及高功率、高频率的 DC/DC 变换器。了解电感的电气特性对于设计紧凑型、经济型、高效率、并具备出色散热性能的系统至关重要。 电感是一种…

AI 对话完善【人工智能】

AI 对话【人工智能】 前言版权开源推荐AI 对话v0版本&#xff1a;基础v1版本&#xff1a;对话数据表tag.jsTagController v2版本&#xff1a;回复中textarea.jsChatController v3版本&#xff1a;流式输出chatLast.jsChatController v4版本&#xff1a;多轮对话QianfanUtilChat…

【分析 GClog 的吞吐量和停顿时间、heapdump 内存泄漏分析】

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容GClog分析以优化吞吐量和停顿时间步骤1: 收集GClog步骤2: 分析GClog步骤3: 优化建议步骤4: 实施优化 Heapdump内存泄漏分析步骤1: 获取Heapdump步骤2: 分析Heapdump步骤3: 定位泄漏对象步骤4: 分析泄漏原因步骤5: 修复泄漏…

linux服务使用./xxx.sh执行脚本命令

设置脚本文件为全权限 chmod 777 xxx.sh直接使用./xxxx.sh即可