生活随笔
收集整理的這篇文章主要介紹了
OpenCV C++实现树结构可视化(画出一棵四叉树)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
這是之前那篇關(guān)于C++實(shí)現(xiàn)決策樹(shù)的子問(wèn)題。用不了Python的Matplotlib,只能用OpenCV手撕。
假定我們要實(shí)現(xiàn)這樣一個(gè)三層四叉樹(shù)的結(jié)構(gòu)。(畫(huà)圖軟件太費(fèi)時(shí)間了直接紙上畫(huà)了)需要的是畫(huà)圓,直線和中間標(biāo)的index寫(xiě)字。最主要的是求圓心坐標(biāo)。
背景圖片我是拿windows自帶的畫(huà)圖弄了個(gè)20000*20000的全空白jpg。
一、建立樹(shù)結(jié)構(gòu)
遍歷了一下,結(jié)果是這樣沒(méi)錯(cuò)。
二、計(jì)算坐標(biāo)
然后拿CV畫(huà)圖比較麻煩的一點(diǎn)就是坐標(biāo)的計(jì)算。
假定:最底層的是所有4的i次方個(gè)葉子節(jié)點(diǎn)的圓相切。每4個(gè)葉子節(jié)點(diǎn)圓上一層的根節(jié)點(diǎn)圓橫坐標(biāo)在第2、3個(gè)葉子節(jié)點(diǎn)的正中間位置。
如圖,這是一個(gè)三層的滿四叉樹(shù),以此為例。層數(shù)i取值為0-2。求出最大層數(shù)為max(此處為2)。設(shè)d為每個(gè)小圓的直徑,r為半徑,△H為每一層的高度。(d=2r)
1.每層開(kāi)始A->G->……->T->C坐標(biāo)總長(zhǎng)度Li的計(jì)算
可以看出,除了第0層是單個(gè)根節(jié)點(diǎn),最底層是所有4max 個(gè)圓相切,這兩層是特殊的,要單獨(dú)討論。其他中間層都是遵循規(guī)律的。
最底層長(zhǎng)度L2=16 d=42 d。
第二層,所有圓的長(zhǎng)度要減去最左和最右兩個(gè)圓的直徑,即L1=4maxd-4d。
該規(guī)律可通過(guò)四層滿四叉樹(shù)來(lái)泛化:
L1=4max d-16d
L2=4maxd-4d
L3=4max d
最后得到:
所以除了第一層和最底層,中間層的長(zhǎng)度Li=4max-4max-id。
最底層長(zhǎng)度L底=4max d。
2.每層的各個(gè)A->G->T->C坐標(biāo)單長(zhǎng)度L0的計(jì)算
同1,第0層和最底層是特殊的,單獨(dú)討論。
將Li的長(zhǎng)度細(xì)分為若干等長(zhǎng)L0,一個(gè)根節(jié)點(diǎn)對(duì)應(yīng)一個(gè)L0。
第1層總長(zhǎng)度為L(zhǎng)1,則L0=L1。
第2層總長(zhǎng)度為L(zhǎng)2,則L0=L2/4-d。因?yàn)橐蟮氖茿->G->T->C的長(zhǎng)度,最底層一開(kāi)始是統(tǒng)一計(jì)算一堆圓的直徑,所以多了最左和最右2個(gè)半徑。
為了泛化中間層規(guī)律,再次采用四層滿四叉樹(shù):
L01=L1
L02=3L2/15
L03=L3/16-d
五層滿四叉樹(shù):
L03=3L3/63
L04=L4/64-d
最后得到:
所以除了第一層和最底層,中間層的長(zhǎng)度L0i=3Li/(4i -1)。
最底層長(zhǎng)度L0底=L底/(4max-1)-d。
3.得到A,G,T,C的坐標(biāo)
假設(shè)某個(gè)根節(jié)點(diǎn)的坐標(biāo)為(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.算法實(shí)現(xiàn)
此處樹(shù)的結(jié)構(gòu)體里我加了個(gè)tag,來(lái)區(qū)分節(jié)點(diǎn)的類(lèi)型。以A點(diǎn)為例:
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.三層滿四叉樹(shù)
2.四層滿四叉樹(shù)
3.實(shí)現(xiàn)目標(biāo)樹(shù)結(jié)構(gòu)
字體和圓形大小比1、2中有放大。
結(jié)論:我在反思是不是應(yīng)該好好學(xué)一下Python,總這么手撕感覺(jué)不是個(gè)好辦法。
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;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;double yCircle
= 1000;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;
}
總結(jié)
以上是生活随笔為你收集整理的OpenCV C++实现树结构可视化(画出一棵四叉树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。