OpenCV C++实现树结构可视化(画出一棵四叉树)

本文介绍了如何使用C++和OpenCV手动实现决策树的可视化,特别是针对三层四叉树结构。通过计算圆心坐标、节点间的距离和层数,利用OpenCV进行画图。作者提到了Python的Matplotlib库在画图上的便利性,并反思了手动实现的局限性。代码示例展示了从创建树结构到绘制图形的完整过程。
摘要由CSDN通过智能技术生成

这是之前那篇关于C++实现决策树的子问题。用不了Python的Matplotlib,只能用OpenCV手撕。
假定我们要实现这样一个三层四叉树的结构。(画图软件太费时间了直接纸上画了)需要的是画圆,直线和中间标的index写字。最主要的是求圆心坐标。
在这里插入图片描述
背景图片我是拿windows自带的画图弄了个20000*20000的全空白jpg。
一、建立树结构
在这里插入图片描述

遍历了一下,结果是这样没错。
二、计算坐标
然后拿CV画图比较麻烦的一点就是坐标的计算。
假定:最底层的是所有4的i次方个叶子节点的圆相切。每4个叶子节点圆上一层的根节点圆横坐标在第2、3个叶子节点的正中间位置。在这里插入图片描述
如图,这是一个三层的满四叉树,以此为例。层数i取值为0-2。求出最大层数为max(此处为2)。设d为每个小圆的直径,r为半径,△H为每一层的高度。(d=2r)
1.每层开始A->G->……->T->C坐标总长度Li的计算
可以看出,除了第0层是单个根节点,最底层是所有4max 个圆相切,这两层是特殊的,要单独讨论。其他中间层都是遵循规律的。
最底层长度L2=16 d=42 d。
第二层,所有圆的长度要减去最左和最右两个圆的直径,即L1=4maxd-4d。
该规律可通过四层满四叉树来泛化:
L1=4max d-16d
L2=4maxd-4d
L3=4max d

最后得到:
所以除了第一层和最底层,中间层的长度Li=4max-4max-id。
最底层长度L底=4max d。
2.每层的各个A->G->T->C坐标单长度L0的计算
1,第0层和最底层是特殊的,单独讨论。
将Li的长度细分为若干等长L0,一个根节点对应一个L0。
第1层总长度为L1,则L0=L1。
第2层总长度为L2,则L0=L2/4-d。因为要求的是A->G->T->C的长度,最底层一开始是统一计算一堆圆的直径,所以多了最左和最右2个半径。
为了泛化中间层规律,再次采用四层满四叉树:
L01=L1
L02=3L2/15
L03=L3/16-d
五层满四叉树:
L03=3L3/63
L04=L4/64-d

最后得到:
所以除了第一层和最底层,中间层的长度L0i=3Li/(4i -1)。
最底层长度L0底=L底/(4max-1)-d。
3.得到A,G,T,C的坐标
假设某个根节点的坐标为(x0,y0)。那么:
A(x0-L0/2,y0+△H)
G(x0-L0/6,y0+△H)
T(x0+L0/6,y0+△H)
C(x0+L0/2,y0+△H)
4.算法实现
此处树的结构体里我加了个tag,来区分节点的类型。以A点为例:

if (t->tag == 'a')
        {
            double L = pow(4, maxLayer) * 2 * radius - pow(4, maxLayer - t->layer) * 2 * radius;
            double L0 = L * 3 / (pow(4, t->layer) - 1);
            if (t->aleaf == NULL && t->gleaf == NULL && t->tleaf == NULL && t->cleaf == NULL)
            {
                L = pow(4, maxLayer) * 2 * radius;
                L0 = L / pow(4, t->layer - 1) - 2 * radius;
            }
            pointX += -L0 / 2;
            pointY += 1000;
        }

三、做出图形
1.三层满四叉树
请添加图片描述
2.四层满四叉树
请添加图片描述
3.实现目标树结构
字体和圆形大小比1、2中有放大。
在这里插入图片描述

结论:我在反思是不是应该好好学一下Python,总这么手撕感觉不是个好办法。
Over.
代码

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
struct treeNode
{
    int layer;
    int index;
    char tag;
    treeNode* aleaf;
    treeNode* gleaf;
    treeNode* tleaf;
    treeNode* cleaf;
    treeNode() :index(0), layer(0), tag(' '), aleaf(NULL), gleaf(NULL), tleaf(NULL), cleaf(NULL) {}
};
treeNode* createtreeNode()
{
    treeNode* t = new treeNode();
    t->aleaf = new treeNode();
    t->gleaf = new treeNode();
    t->tleaf = new treeNode();
    t->cleaf = new treeNode();
    t->aleaf->layer = 1;
    t->gleaf->layer = 1;
    t->tleaf->layer = 1;
    t->cleaf->layer = 1;
    t->aleaf->index = 1;
    t->gleaf->index = 2;
    t->tleaf->index = 3;
    t->cleaf->index = 4;
    t->aleaf->tag = 'a';
    t->gleaf->tag = 'g';
    t->tleaf->tag = 't';
    t->cleaf->tag = 'c';
    t->aleaf->aleaf = new treeNode();
    t->aleaf->tleaf = new treeNode();
    t->cleaf->aleaf = new treeNode();
    t->cleaf->gleaf = new treeNode();
    t->cleaf->cleaf = new treeNode();
    t->aleaf->aleaf->layer = 2;
    t->aleaf->tleaf->layer = 2;
    t->cleaf->aleaf->layer = 2;
    t->cleaf->gleaf->layer = 2;
    t->cleaf->cleaf->layer = 2;
    t->aleaf->aleaf->index = 5;
    t->aleaf->tleaf->index = 6;
    t->cleaf->aleaf->index = 7;
    t->cleaf->gleaf->index = 8;
    t->cleaf->cleaf->index = 9;
    t->aleaf->aleaf->tag = 'a';
    t->aleaf->tleaf->tag = 't';
    t->cleaf->aleaf->tag = 'a';
    t->cleaf->gleaf->tag = 'g';
    t->cleaf->cleaf->tag = 'c';
    return t;
}
vector<int> countLayer;
void traverseTree(treeNode* t)
{
    if (t == NULL) return;
    else
    {
        countLayer.push_back(t->layer);
        cout << "index:" << t->index << endl;
        traverseTree(t->aleaf);
        traverseTree(t->gleaf);
        traverseTree(t->tleaf);
        traverseTree(t->cleaf);
    }
}
int findMaxLayer(vector<int> c)
{
    int size = c.size();
    int max = 0;
    for (int i = 0; i < size; i++)
    {
        if (c[i] > max)
            max = c[i];
    }
    return max;
}
Mat image = imread("untitled.jpg");
string intToChar(int n)
{
    char* num = new char[10];
    _itoa_s(n, num, sizeof(num), 10);
    string s = num;
    delete[] num;
    return s;
}
void drawTree(treeNode* t, double pointX, double pointY, string output)
{
    int radius = 200;//r;
    int maxLayer = findMaxLayer(countLayer);
    double previousX = pointX;
    double previousY = pointY;
    if (t == NULL) return;
    else
    {
        if (t->tag == 'a')
        {
            double L = pow(4, maxLayer) * 2 * radius - pow(4, maxLayer - t->layer) * 2 * radius;
            double L0 = L * 3 / (pow(4, t->layer) - 1);
            if (t->aleaf == NULL && t->gleaf == NULL && t->tleaf == NULL && t->cleaf == NULL)
            {
                L = pow(4, maxLayer) * 2 * radius;
                L0 = L / pow(4, t->layer - 1) - 2 * radius;
            }
            pointX += -L0 / 2;
            pointY += 1000;
        }
        else if (t->tag == 'g')
        {
            double L = pow(4, maxLayer) * 2 * radius - pow(4, maxLayer - t->layer) * 2 * radius;
            double L0 = L * 3 / (pow(4, t->layer) - 1);
            if (t->aleaf == NULL && t->gleaf == NULL && t->tleaf == NULL && t->cleaf == NULL)
            {
                L = pow(4, maxLayer) * 2 * radius;
                L0 = L / pow(4, t->layer - 1) - 2 * radius;
            }
            pointX += -L0 / 6;
            pointY += 1000;
        }
        else if (t->tag == 't')
        {
            double L = pow(4, maxLayer) * 2 * radius - pow(4, maxLayer - t->layer) * 2 * radius;
            double L0 = L * 3 / (pow(4, t->layer) - 1);
            if (t->aleaf == NULL && t->gleaf == NULL && t->tleaf == NULL && t->cleaf == NULL)
            {
                L = pow(4, maxLayer) * 2 * radius;
                L0 = L / pow(4, t->layer - 1) - 2 * radius;
            }
            pointX += L0 / 6;
            pointY += 1000;
        }
        else if (t->tag == 'c')
        {
            double L = pow(4, maxLayer) * 2 * radius - pow(4, maxLayer - t->layer) * 2 * radius;
            double L0 = L * 3 / (pow(4, t->layer) - 1);
            if (t->aleaf == NULL && t->gleaf == NULL && t->tleaf == NULL && t->cleaf == NULL)
            {
                L = pow(4, maxLayer) * 2 * radius;
                L0 = L / pow(4, t->layer - 1) - 2 * radius;
            }
            pointX += L0 / 2;
            pointY += 1000;
        }
        else if (t->tag == ' ')
        {
            pointX = 10000;
            pointY = 1000;
        }
        output = intToChar(t->index);
        line(image, Point(previousX, previousY), Point(pointX, pointY), Scalar(0, 0, 0), 20);
        circle(image, Point(previousX, previousY), radius, Scalar(0, 0, 0), 20);
        circle(image, Point(previousX, previousY), radius - 10, Scalar(255, 255, 255), -1);
        circle(image, Point(pointX, pointY), radius, Scalar(0, 0, 0), 20);
        circle(image, Point(pointX, pointY), radius - 10, Scalar(255, 255, 255), -1);
        drawTree(t->aleaf, pointX, pointY, output);
        drawTree(t->gleaf, pointX, pointY, output);
        drawTree(t->tleaf, pointX, pointY, output);
        drawTree(t->cleaf, pointX, pointY, output);
        putText(image, &output[0], Point(pointX - 100, pointY + 100), 0, 10, Scalar(0, 0, 0), 20);
    }
}
void drawTreeTotal(treeNode* t)
{
    double xCircle = 10000;//x0;
    double yCircle = 1000;//y0;
    namedWindow("tree", CV_WINDOW_NORMAL);
    imshow("tree", image);
    drawTree(t, xCircle, yCircle,"");
}
int main()
{
    treeNode* t = createtreeNode();
    traverseTree(t);
    drawTree(t, 10000, 1000, "");
    drawTreeTotal(t);
    waitKey(0);
    system("pause");
    return 0;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值