一步一步写算法(之图的保存)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】


前面的几篇博客,我们对图进行基本定义,同时介绍了图的创建、图的添加和删除等。今天,我们聊一聊图是怎么在存储在外设中的。这些外接设备可以是各种类型的,比如说,可以是硬盘、sd卡、网络硬盘等等。本质上说,我们今天讨论的主题就是怎么把图的数据永久地保留在本地。并且,如果需要加载这些数据,也可以快速恢复图原来的面貌。对图数据结构已经记得不太清楚的朋友可以复习一下面的代码,回想一下我们之前的定义方法。

typedef struct _LINE { int end; int weight; struct _LINE* next; }LINE; typedef struct _VECTEX { int start; int number; LINE* neighbor; struct _VECTEX* next; }VECTEX; typedef struct _GRAPH { int count; VECTEX* head; }GRAPH; 数据结构中有好多的指针。那么在外存中应该怎么保存呢?因为对于外存来说,指针是没有什么意义的。大家稍微思考其实就明白了。其实我们可以把这些指针全部看成是偏移值。GRAPH是有许多的点构成的,点的结构中有很多的边连接,那么我们就可以按照下面的顺序保存数据。

/* * --------------------------------------------------------------------------- * | GRAPH | vectex1 | vectex2 | ...... | vectex n | LINE1 |......| LINE n | * --------------------------------------------------------------------------- */ 那么偏移值怎么安排呢?

a)GRAPH结构

head为第一个vectex的偏移地址。


b)VECTEX结构

neighbour记录了第一条边的偏移位置,next记录了下一个节点的偏移值。


c)LINE结构

next为下一条边的偏移值。


但是,如果我们做一些优化的话,那么保存的数据还要少一些。比如说,第一个vectex的节点就在GRAPH的后面,那么head实际上不需要保存;同时在vectex结构中,因为我们需要知道LINE的偏移值,所以neighbour的偏移是需要知道的,但是next就不再需要了,因为vectex数据本身就是并列在一起的;最后同样因为我们需要把所有属于同一个vectex的边放在一起,那么LINE结构中的next数据其实也可以省略了。所以修改后保存的数据结构大体应该是这样的:

typedef struct _LINE { int end; int weight; }LINE; typedef struct _VECTEX { int start; int number; LINE* neighbor; }VECTEX; typedef struct _GRAPH { int count; }GRAPH;
有了上面的数据结构,那么从外层加载数据就是一个逆向操作而已,不再复杂了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。 首先,分水岭算法(watershed algorithm)是一种像分割算法,可以将像分割成不同的区域,每个区域表示一个不同的物体或区域。在这个问题中,我们需要将扑克牌分割成不同的区域,每个区域代表一张牌。 下面是用C++实现分水岭算法分割扑克牌的大致步骤: 1. 读取扑克牌的像,并将其转换为灰度像。 ```c++ cv::Mat src = cv::imread("poker.png"); cv::Mat gray; cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); ``` 2. 对灰度像进行二值化处理,得到二值像。 ```c++ cv::Mat binary; cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU); ``` 3. 对二值像进行形态学操作,消除噪声和不规则边界。 ```c++ cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); cv::Mat morph; cv::morphologyEx(binary, morph, cv::MORPH_OPEN, kernel); ``` 4. 对形态学操作后的像进行距离变换,得到距离像。 ```c++ cv::Mat dist; cv::distanceTransform(morph, dist, cv::DIST_L2, cv::DIST_MASK_3); ``` 5. 对距离像进行阈值处理,得到分水岭的初始标记像。 ```c++ cv::Mat markers; cv::threshold(dist, markers, 0.5 * cv::mean(dist), 255, cv::THRESH_BINARY); ``` 6. 对标记像进行分水岭变换,得到分割结果。 ```c++ cv::Mat labels; cv::watershed(src, markers); ``` 7. 将分割结果可视化,并保存到本地。 ```c++ for (int i = 0; i < markers.rows; i++) { for (int j = 0; j < markers.cols; j++) { if (markers.at<int>(i, j) == -1) { src.at<cv::Vec3b>(i, j)[0] = 0; src.at<cv::Vec3b>(i, j)[1] = 0; src.at<cv::Vec3b>(i, j)[2] = 255; } } } cv::imwrite("result.png", src); ``` 完整的代码如下: ```c++ #include <iostream> #include <opencv2/opencv.hpp> int main(int argc, char** argv) { cv::Mat src = cv::imread("poker.png"); cv::Mat gray; cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); cv::Mat binary; cv::threshold(gray, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU); cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); cv::Mat morph; cv::morphologyEx(binary, morph, cv::MORPH_OPEN, kernel); cv::Mat dist; cv::distanceTransform(morph, dist, cv::DIST_L2, cv::DIST_MASK_3); cv::Mat markers; cv::threshold(dist, markers, 0.5 * cv::mean(dist), 255, cv::THRESH_BINARY); cv::watershed(src, markers); for (int i = 0; i < markers.rows; i++) { for (int j = 0; j < markers.cols; j++) { if (markers.at<int>(i, j) == -1) { src.at<cv::Vec3b>(i, j)[0] = 0; src.at<cv::Vec3b>(i, j)[1] = 0; src.at<cv::Vec3b>(i, j)[2] = 255; } } } cv::imwrite("result.png", src); return 0; } ``` 注意:上述代码中的文件路径需要根据实际情况进行修改。此外,本文未进行完整测试,实际使用时可能需要根据具体情况进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值