《数据结构、算法与应用C++语言描述》-队列的应用-图元识别问题

news2025/1/12 12:08:46

《数据结构、算法与应用C++语言描述》-队列的应用-图元识别问题

图元识别

问题描述

数字化图像是一个 mxm 的像素矩阵。在单色图像中,每一个像素要么为0,要么为 1。值为0的像素表示图像的背景。值为1的像素表示图元上的一个点,称其为图元像素。两个像素是相邻的,是指它们左右相邻或上下相邻。两个相邻的图元像素是同一个图元的像素。图元识别的目的就是给图元像素做标记,使得两个像素标记相同,当且仅当它们是同一个图元的像素。

考察图 9-14a,它是一个7×7 图像。空白方格表示背景像素,标记为1 的方格表示图元像素。像素(1,3)和(2,3)是同一个图元的像素,因为它们是相邻的。像素(2,4)与(2,3)是相邻的,它们也属于同一图元。因此,三个像素(1,3)、(2,3)和(2,4)属于同一个图元。由于没有其他的像素与这三个像素相邻,因此这三个像素定义了一个图元。图 9-14a 的图像有 4 个图元。第一个图元是像素集合{(1,3),(2,3),(2,4)};第二个是{(3,5),(4,4),(4,5),(5,5)};第三个是{(5,2),(6,1),(6,2),(6,3),(7,1),(7,2),(7,3)};第四个是{(5,7),(6,7),(7,6),(7,7))。在图9-14b中,图元像素都做了标记,两个像素标记相同,当且仅当它们属于同一个图元。我们用数字 2,3,4,…作为图元标记。这里我们没有用数字1 做图元标记,是因为我们用1表示未做标记的图元像素。
在这里插入图片描述

求解策略

通过扫描像素来识别图元。扫描的方式是逐行扫描,每一行逐列扫描。当扫描到一个未标记的图元像素时,给它一个图元标记。然后把这个图元像素作为一个新图元的种子,通过识别和标记所有与该种子相邻的图元像素,来寻找新图元剩余的像素。与种子相邻的图元像素称为1-间距像素。然后,识别和标记与1-间距像素相邻的所有未标记的图元像素,这些像素被称为2-间距像素。接下来识别和标记与2-间距像素相邻的未标记的图元像素。这个过程一直持续到没有新的、未标记的、相邻的图元像素为止。

代码

#include <iostream>
#include <queue>
using namespace std;

/*用于存储迷宫地址的结构体*/
struct position
{
    int row,  //行
    col;  //列
    position() {}
    position(int prow, int pcol):row(prow),col(pcol){}
    operator int() const { return row; }
    friend ostream& operator<<(ostream& out, const position x)
    {
        out << "(" << x.row << "," << x.col << ")";
        return out;
    }
};
/*创建二维数组*/
template <class T>
bool make2dArray(T**& x, int numberOfRows, int numberOfColumns)
{
    try {
        //行指针
        x = new T * [numberOfRows];
        //为每一行分配内存
        for (int i = 0; i < numberOfRows; i++)
            x[i] = new int[numberOfColumns];
        return true;
    }
    catch (bad_alloc) { return false; }
}

/*遍历二维数组*/
template<class T>
void traverse2dArray(T**& x, int numberOfRows, int numberOfColumns)
{
    for (int i = 0; i < numberOfRows; i++)
    {
        for (int j = 0; j < numberOfColumns; j++)
        {
            cout.width(4);
            cout << x[i][j] << "  ";
        }
        cout << endl;
    }
}

/*图元识别问题全局变量*/
int** pixel;//二维方阵
int pixelSize;//方阵大小

/*图元识别*/
/*方格元素为1表示为有像素,方格元素为0表示无像素*/
/*标记为n(n>1)表示为第n个图元*/
void inputPixelQueue()//输入像素矩阵
{
    cout << "Please enter the size of pixel-Matrix:";
    while (!(cin >> pixelSize))
    {
        cin.clear();//清空标志位
        while (cin.get() != '\n')//删除无效的输入
            continue;
        cout << "Please enter the size of pixel-Matrix:";
    }
    //+2的原因是为了避免在处理内部位置和边界位置时存在差别
    make2dArray<int>(pixel, pixelSize + 2, pixelSize + 2);
    //初始化边界位置的数值
    for (int i = 0; i <= pixelSize + 1; i++)
    {
        pixel[i][0] = 0;
        pixel[0][i] = 0;
        pixel[i][pixelSize + 1] = 0;
        pixel[pixelSize + 1][i] = 0;
    }
    //初始化像素
    for (int i = 1; i <= pixelSize; i++)
        for (int j = 1; j <= pixelSize; j++)
        {
            int positionij;
            cout << "Please enter pixel[" << i << "," << j << "]:";
            while (!(cin >> positionij))
            {
                cin.clear();//清空标志位
                while (cin.get() != '\n')//删除无效的输入
                    continue;
                cout << "Please enter pixel[" << i << "," << j << "]:";
            }
            pixel[i][j] = positionij;
        }
    cout << "The pixel = " << endl;
    traverse2dArray<int>(pixel, pixelSize + 2, pixelSize + 2);
}
void labelComponents()
{
    inputPixelQueue();//输入迷宫,Grid二维数组和数组大小GridSize和电路布线共享
    //初始化偏移量
    position offset[4];
    offset[0].row = 0; offset[0].col = 1;//右
    offset[1].row = 1; offset[1].col = 0;//下
    offset[2].row = 0; offset[2].col = -1;//左
    offset[3].row = -1; offset[3].col = 0;//上
    int numberOfNbrs = 4;//一个像素的相邻位置数
    //扫描所有像素,标记图元
    queue<position> q;
    int id = 1;
    position here, nbr;
    for(int i = 1;i <= pixelSize;i++)
        for (int j = 1; j <= pixelSize; j++)
        {
            if (pixel[i][j] == 1)//新图元
            {
                pixel[i][j] = ++id;
                here.row = i;
                here.col = j;

                while (true)
                {
                    for (int k = 0; k < numberOfNbrs; k++)
                    {
                        nbr.row = here.row + offset[k].row;
                        nbr.col = here.col + offset[k].col;
                        if (pixel[nbr.row][nbr.col] == 1)
                        {
                            pixel[nbr.row][nbr.col] = id;
                            q.push(nbr);
                        }
                    }
                    //图元中无未考察的像素
                    if (q.empty()) break;
                    here = q.front();
                    q.pop();
                }
            }
        }
    cout << "The pixel = " << endl;
    traverse2dArray<int>(pixel, pixelSize+1, pixelSize+2);
}

int main()
{
    cout << "图元识别问题********************" << endl;
    labelComponents();

    return 0;
}

运行结果

C:\Users\15495\Documents\Jasmine\Work\coding\cmake-build-debug\coding.exe
鍥惧厓璇嗗埆闂********************
Please enter the size of pixel-Matrix:7
Please enter pixel[1,1]:0
Please enter pixel[1,2]:0
Please enter pixel[1,3]:1
Please enter pixel[1,4]:0
Please enter pixel[1,5]:0
Please enter pixel[1,6]:0
Please enter pixel[1,7]:0
Please enter pixel[2,1]:0
Please enter pixel[2,2]:0
Please enter pixel[2,3]:1
Please enter pixel[2,4]:1
Please enter pixel[2,5]:0
Please enter pixel[2,6]:0
Please enter pixel[2,7]:0
Please enter pixel[3,1]:0
Please enter pixel[3,2]:0
Please enter pixel[3,3]:0
Please enter pixel[3,4]:0
Please enter pixel[3,5]:1
Please enter pixel[3,6]:0
Please enter pixel[3,7]:0
Please enter pixel[4,1]:0
Please enter pixel[4,2]:0
Please enter pixel[4,3]:0
Please enter pixel[4,4]:1
Please enter pixel[4,5]:1
Please enter pixel[4,6]:0
Please enter pixel[4,7]:0
Please enter pixel[5,1]:0
Please enter pixel[5,2]:1
Please enter pixel[5,3]:0
Please enter pixel[5,4]:0
Please enter pixel[5,5]:1
Please enter pixel[5,6]:0
Please enter pixel[5,7]:1
Please enter pixel[6,1]:1
Please enter pixel[6,2]:1
Please enter pixel[6,3]:1
Please enter pixel[6,4]:0
Please enter pixel[6,5]:0
Please enter pixel[6,6]:0
Please enter pixel[6,7]:1
Please enter pixel[7,1]:1
Please enter pixel[7,2]:1
Please enter pixel[7,3]:1
Please enter pixel[7,4]:0
Please enter pixel[7,5]:0
Please enter pixel[7,6]:1
Please enter pixel[7,7]:1
The pixel =
   0     0     0     0     0     0     0     0     0
   0     0     0     1     0     0     0     0     0
   0     0     0     1     1     0     0     0     0
   0     0     0     0     0     1     0     0     0
   0     0     0     0     1     1     0     0     0
   0     0     1     0     0     1     0     1     0
   0     1     1     1     0     0     0     1     0
   0     1     1     1     0     0     1     1     0
   0     0     0     0     0     0     0     0     0  
The pixel =
   0     0     0     0     0     0     0     0     0
   0     0     0     2     0     0     0     0     0
   0     0     0     2     2     0     0     0     0
   0     0     0     0     0     3     0     0     0
   0     0     0     0     3     3     0     0     0
   0     0     4     0     0     3     0     5     0
   0     4     4     4     0     0     0     5     0
   0     4     4     4     0     0     5     5     0

Process finished with exit code 0

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

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

相关文章

A_搜索(A Star)算法

A*搜索(A Star) 不同于盲目搜索&#xff0c;A算法是一种启发式算法(Heuristic Algorithm)。 上文提到&#xff0c;盲目搜索对于所有要搜索的状态结点都是一视同仁的&#xff0c;因此在每次搜索一个状态时&#xff0c;盲目搜索并不会考虑这个状态到底是有利于趋向目标的&#x…

STM32使用WWDG窗口看门狗

1 WWDG 介绍 1.1 WWDG 简介 窗口看门狗 WWDG 其实和独立看门狗类似&#xff0c;它是一个 7 位递减计数器不断的往下递减计数&#xff0c; 当减到一个固定值 0X40 时还不喂狗的话&#xff0c;产生一个 MCU 复位&#xff0c;这个值叫窗口的下限&#xff0c;是固定的值&#xf…

Android 开发技巧:音乐播放器的后台处理【Service、Handler、MediaPlayer】

给定部分完成的MusicPlayer项目&#xff0c;实现其中未完成的service部分&#xff1a; 1、创建MusicService类&#xff0c;通过service组件实现后台播放音乐的功能&#xff1b; 2、在MainActivity中通过ServiceConnection连接MusicService&#xff0c;实现对音乐播放的控制&…

Android端自定义铃声

随着移动应用竞争进入红海时代&#xff0c;如何在APP推送中别出心裁显得尤为重要。例如对自己的APP推送赋予独特的推送铃声&#xff0c;能够给用户更加理想的使用体验。 1、个性化提醒铃声有助于当收到特定类型的消息时&#xff0c;用户能够立刻识别出来。 2、不同的推送铃声…

xxl-job任务调度2.0.2升级到2.3.0版本,执行器改造过程中经验总结

xxl-job任务调度2.0.2升级到2.3.0版本 一、背景二、开始改造1、修改pom.xml2、修改Handler3、启动服务并验证4、解决异常5、再次启动服务并验证 一、背景 现在要对一批老项目中的执行器进行升级&#xff0c;原来老项目中的执行器&#xff0c;依赖的任务调度中心xxl-job版本是2…

金和OA SQL注入漏洞

一、漏洞描述 金和OA协同办公管理系统C6软件&#xff0c;为北京金和网络股份有限公司 开发系统&#xff0c;贴合企事业单位的实际需求&#xff0c;实行通用化、标准化、智能化、人性化的产品设计&#xff0c;充分体现企事业单位规范管理、提高办公效率的核心思想&#xff0c;为…

Go包介绍与初始化:搞清Go程序的执行次序

Go包介绍与初始化&#xff1a;搞清Go程序的执行次序 文章目录 Go包介绍与初始化&#xff1a;搞清Go程序的执行次序一、main.main 函数&#xff1a;Go 应用的入口函数1.1 main.main 函数1.2 main.main 函数特点 二、包介绍2.1 包介绍与声明2.2 非 main包的 main 函数2.3 包的命名…

剑指Offer || 050.路径总和|||

题目 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节…

DETR原理与代码超详细解读

文章目录 前言一、DETR论文原理1、DETR整体介绍2、DETR论文贡献3、DETR模型框架4、DETR基于二分图匹配的LOSS 二、DETR环境安装1、安装基础环境2、pycocotools安装3、其它环境安装4、环境验证5、训练与推理效果显示 三、数据准备1、coco 数据格式2、修改数据 四、DETR加载数据代…

Git的安装

前置 知道自己电脑上跑的是什么系统 查看电脑位数 省事的一种办法 Windows 在cmd中输入如下命令 wmic os get osarchitecture看命令结果即可 省事的一种办法 Linux 直接在终端中输入如下命令 uname -m若结果是x86_64就是64位的&#xff0c;反之32位 图形化的办法 Wind…

Peter算法小课堂—正整数拆分

大家可能会想&#xff1a;正整数拆分谁不会啊&#xff0c;2年级就会了&#xff0c;为啥要学啊 例题 正整数拆分有好几种&#xff0c;这里我们列举两种讲。 关系 我们看着第一幅图&#xff0c;头向左转90&#xff0c;记住你看到的图&#xff0c;再来看第二幅图&#xff0c;你…

lnmp架构部署Discuz论坛并配置重定向转发

lnmp架构部署Discuz论坛并配置重定向转发 文章目录 lnmp架构部署Discuz论坛并配置重定向转发环境说明部署Discuz论坛系统下载Discuz论坛系统代码包&#xff0c;官网地址如下&#xff1a;部署Discuz论坛系统步骤&#xff1a;解压安装Discuz源码包配置虚拟主机进入Discuz安装界面…

pytest利用request fixture实现个性化测试需求详解

这篇文章主要为大家详细介绍了pytest如何利用request fixture实现个性化测试需求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下− 前言 在深入理解 pytest-repeat 插件的工作原理这篇文章中&#xff0c;我们看到pytest_repeat源码中有这样一段 import pyt…

YOLOv5算法改进(14)— 如何去更换主干网络(3)(包括代码+添加步骤+网络结构图)

前言:Hello大家好,我是小哥谈。为了给后面YOLOv5算法的进阶改进奠定基础,本篇文章就继续通过案例的方式给大家讲解如何在YOLOv5算法中更换主干网络,本篇文章的特色就是比较浅显易懂,附加了很多的网络结构图,通过结构图的形式向大家娓娓道来,希望大家学习之后能够有所收获…

msvcr120.dll缺失怎么修复,快速修复msvcr120.dll丢失的三个有效方法

随着计算机技术的不断发展&#xff0c;我们在使用软件或游戏时经常会遇到各种错误提示&#xff0c;其中找不到msvcr120.dll就是一种常见的错误。那么&#xff0c;msvcr120.dll是什么&#xff1f;它的作用是什么&#xff1f;如何修复这一错误呢&#xff1f;本文将为您详细介绍几…

Python学习基础笔记七十九——Socket编程2

应用消息格式&#xff1a; 为什么要定义消息格式&#xff1f; 我们发送的消息就是要传递的内容&#xff0c;比如字符串。 我们在企业中开发的程序通讯&#xff0c;消息往往是有格式定义的。消息格式的定义可以归入OSI网络模型的表示层。 比如&#xff1a;定义的消息包括消息…

电子技术基础(三)__第7章 时序逻辑电路_第7篇之解题方法与步骤

我们必须牢记这样一句&#xff1a; 先列出输入逻辑式&#xff0c;即驱动方程&#xff0c; 然后将驱动方程代入触发器的特征方程&#xff0c; 得到状态方程(也称 次态方程)&#xff0c; 最后写出输出方程。 二 看例题 2022.4 真题 第38题 分析: 此题乍一看&#xff0c;可能有点…

jvm 各个版本支持的参数 容器化部署

知道一些 jvm 调优参数&#xff0c;但是没有找到官网对应的文档&#xff0c;在网上的一些文章偶然发现&#xff0c;记录一下。 https://docs.oracle.com/en/java/javase/ 包含各个版本 jdk 8 分为 windows 和 unix 系统 https://docs.oracle.com/javase/8/docs/technotes/too…

Volatile 可以保证什么特性?有什么作用?

Volatile 可以保证什么特性&#xff1f;有什么作用&#xff1f; 可以保证可见性&#xff0c;有序性&#xff0c;禁止指令重排序。但是不能保证原子性。线程上下文切换的时候&#xff0c;还是有可能出现线程安全问题。 cpu 都是把数据从内存拉取到自己的缓存中进行运算&#xff…

在Espressif-IDE中使用Wokwi仿真ESP32

陈拓 2023/10/17-2023/10/19 1. 概述 在Espressif-IDE v2.9.0版本之后可直接在IDE中使用Wokwi模拟器。 1.1 什么是 Wokwi 模拟器&#xff1f; Wokwi 是一款在线电子模拟器&#xff0c;支持模拟各种开发板、元器件和传感器&#xff0c;例如乐鑫产品 ESP32。 Wokwi 提供基于浏…