这是之前那篇关于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;
}