微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

调整quad_tree的大小

如何解决调整quad_tree的大小

将矩阵的大小更改为2 m ×2 m 。这样做是 如下。如果m≥n,则用2 m-n ×2 m-n 矩阵替换原始图像的每个像素 所有值都等于原始像素。如果m m ×2 m 子矩阵,每个子矩阵的大小为2 n-m ×2 n-m ,并用一个像素替换每个子矩阵 值在子矩阵中更经常出现。如果相等,则选择1。

如何用高度m调整高度n的区域四叉树的大小。 QUADTREE的定义如下:
图像被认为是2n×2n矩阵,其每个条目均为0(白色)或1(黑色)。每个条目称为一个像素。代替存储整个矩阵,使用不同的数据结构来减小大小。四叉树就是这样一种。 四叉树是一个有根树,其中每个节点都有0或4个子节点。树中的每个节点都对应于整个矩阵的某个子矩阵,对于0≤i≤n,大小为2i×2i。根节点是整个矩阵。如果子矩阵中与一个节点相对应的所有条目均相等,则该节点为叶节点,并且它将像素值存储在子矩阵中。如果子矩阵中有不同的条目,则将其分为4个大小为2i-1×2i-1的子矩阵,分别称为左上,右上,右下,左下,然后递归构造子对应于4个子矩阵的树。

解决方法

我实现了两个解决方案,第一个是针对QuadTree的情况,第二个是针对2D向量(数组)的情况的(我的第二个解决方案实际上是我的第一个,我是错误地实现了它,忘了注意到我们特别需要QuadTree结构,但是我仍然如果对别人有帮助,请留下第二个。)

第一个解决方案,使用QuadTree结构。

四叉树被实现为可以存储任何数据类型T的QuadTree模板结构,默认情况下,它以size_t类型(0/1,黑/白)存储二进制图像数据。有一些函数CreateQT用于创建和填充给定高度的四叉树,TraverseQT是一个遍历所有树节点并将给定回调应用于每个叶节点的函数,ResizeQT实际上可以解决给定任务-将四叉树的大小从当前高度n更改为新高度mDumpQT函数将四叉树转储为字符串,以便将其输出到控制台。

main()函数仅通过n调用将随机二进制数据填充到CreateQT中来创建高度为rand() % 2的输入树,然后通过{将原始图像输出到控制台{1}}调用,然后通过调用DumpQT从高度n调整为高度m,并使用ResizeQT将最终调整后的图像输出到控制台。

Try it online!

DumpQT

控制台输出:

#include <cstdlib>
#include <vector>
#include <utility>
#include <iostream>
#include <map>
#include <algorithm>
#include <array>
#include <memory>
#include <string>
#include <functional>
using namespace std;

template <typename T>
struct QuadTree {
    typedef T data_t;
    size_t height() const {
        return st[0] ? st[0]->height() + 1 : 0;
    }
    
    T data = T();
    // Sub-trees,in order Top-Left,Top-Right,Bottom-Left,Bottom-Right.
    array< shared_ptr<QuadTree>,4 > st = {};
};

template <typename T>
static shared_ptr< QuadTree<T> > CreateQT(size_t const height,function<T()> const & filler) {
    shared_ptr< QuadTree<T> > r(new QuadTree<T>());
    if (height <= 0)
        r->data = filler();
    else
        for (size_t i = 0; i < r->st.size(); ++i)
            r->st[i] = CreateQT(height - 1,filler);
    return r;
}

template <typename T>
static void TraverseQT(QuadTree<T> const & qt,function<void(T const &)> const & visitor) {
    if (qt.height() <= 0)
        visitor(qt.data);
    else
        for (size_t i = 0; i < qt.st.size(); ++i)
            TraverseQT<T>(*qt.st[i],visitor);
}

template <typename T>
static void ResizeQT(QuadTree<T> & qt,size_t const m) {
    size_t const n = qt.height();
    if (n == m)
        return;
    if (n > 0 && m > 0) {
        for (size_t i = 0; i < qt.st.size(); ++i)
            ResizeQT(*qt.st[i],m - 1);
    } else if (m > 0) {
        qt.st = CreateQT<T>(m,[&](){ return qt.data; })->st;
        qt.data = T();
    } else if (n > 0) {
        map<T,size_t> cnt;
        TraverseQT<T>(qt,[&](T const & v){ ++cnt[v]; });
        // Find max
        pair<T,size_t> maxv = {{},0};
        for (auto const & p: cnt)
            if (p.second > maxv.second)
                maxv = p;
        qt.data = maxv.first;
        for (size_t i = 0; i < qt.st.size(); ++i)
            qt.st[i].reset();
    }
    return;
}

string VecToStr(vector<string> const & a) {
    string r;
    for (size_t i = 0; i < a.size(); ++i) {
        r += a[i];
        if (i < a.size() - 1)
            r += "\n";
    }
    return r;
}

template <typename T>
static vector<string> DumpQT(QuadTree<T> const & qt) {
    if (qt.height() <= 0)
        return {to_string(qt.data)};
    auto JoinH = [](vector<string> const & a,vector<string> const & b) {
        vector<string> r;
        for (size_t i = 0; i < min(a.size(),b.size()); ++i)
            r.push_back(a[i] + " " + b[i]);
        return r;
    };
    auto JoinV = [](vector<string> const & a,vector<string> const & b) {
        vector<string> r = a;
        r.insert(r.end(),b.begin(),b.end());
        return r;
    };
    return JoinV(
        JoinH(DumpQT(*qt.st[0]),DumpQT(*qt.st[1])),JoinH(DumpQT(*qt.st[2]),DumpQT(*qt.st[3]))
    );
}

int main() {
    try {
        vector< pair<size_t,size_t> > const nm = {{2,3},{3,{4,3}};
        srand(0);
        typedef QuadTree<size_t> ImgQT;
        // Iterate through all "nm" tests
        for (size_t t = 0; t < nm.size(); ++t) {
            size_t n = nm[t].first,m = nm[t].second;
            cout << "n = " << n << ",m = " << m << endl;
            // Create/Fill input img of size 2^n with random values.
            ImgQT img = *CreateQT<ImgQT::data_t>(n,[]()->size_t{ return rand() % 2; });
            cout << "Original:" << endl << VecToStr(DumpQT(img)) << endl;
            // Solve task,resize to 2^m.
            ResizeQT(img,m);
            cout << "Resized:" << endl << VecToStr(DumpQT(img)) << endl;
        }
        return 0;
    } catch (exception const & ex) {
        cout << "Exception: " << ex.what() << endl;
        return -1;
    } catch (...) {
        cout << "Unknown Exception!" << endl;
        return -1;
    }
}

第二个解决方案,使用2D向量。

在代码的开头,使用所需的n = 2,m = 3 Original: 0 1 1 1 0 1 1 1 0 0 0 1 1 0 1 1 Resized: 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 1 n = 3,m = 3 Original: 1 1 0 1 0 1 1 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 1 0 1 0 0 0 1 1 0 1 0 0 1 1 0 0 0 0 1 0 0 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 1 0 Resized: 1 1 0 1 0 1 1 1 1 0 1 0 1 1 0 1 1 1 1 0 1 0 1 0 1 0 0 0 1 1 0 1 0 0 1 1 0 0 0 0 1 0 0 1 1 0 1 1 1 0 0 0 1 1 1 1 1 0 0 0 0 0 1 0 n = 4,m = 3 Original: 1 0 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1 0 0 1 1 0 1 0 0 0 1 0 0 0 1 0 1 1 0 0 1 1 0 0 1 1 1 0 0 0 1 1 1 1 1 1 0 1 1 0 1 1 1 1 0 0 0 1 1 1 0 0 1 1 0 0 0 1 0 1 1 1 0 1 1 1 0 0 1 0 0 1 1 0 1 1 0 0 1 1 0 1 0 0 1 0 0 1 0 1 1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 1 1 1 1 1 0 1 1 1 0 0 1 1 0 1 1 1 0 1 0 1 1 0 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 1 1 0 1 0 0 0 1 0 0 1 0 0 1 1 0 0 0 1 1 1 0 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1 1 0 0 1 1 1 1 1 1 1 0 1 0 1 1 0 1 1 0 1 1 0 1 1 0 0 0 1 1 1 1 0 0 1 0 1 0 0 0 1 Resized: 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 0 1 0 0 1 1 0 1 0 0 0 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 nm值向n数组添加额外的测试。输入图像预先填充了较小的随机整数值,您可以根据需要将其更改为读取某些输入。

每个图像像素都表示为一个固定大小的数组,其大小等于通道数(例如1表示灰度,3表示RGB)。在下一个代码中,为简单起见,每个像素都有1个通道,只有一个整数。频道数由m常数配置,将nchans更改为例如3用于测试RGB图像。

每个像素都填充有随机整数,随机整数的范围由代码nchans中的下一个表达式控制,修改模数rand() % (t <= 1 ? 10 : 3)之后的值以更改可能值的范围大小。

Try it online!

%

灰度图像(#include <cstdlib> #include <vector> #include <utility> #include <iostream> #include <map> #include <algorithm> #include <array> using namespace std; int main() { try { vector< pair<size_t,3}}; size_t const nchans = 1; // Number of channels (colors),e.g. 1 for Gray and 3 for RGB. typedef array<size_t,nchans> PixelT; srand(0); // Iterate through all "nm" tests for (size_t t = 0; t < nm.size(); ++t) { vector< vector<PixelT> > img; size_t n = nm[t].first,m = " << m << endl; cout << "Original:" << endl; // Create/Fill input img of size 2^n with random values. // (1 << n) is same as 2^n (power of 2). for (size_t i = 0; i < (1 << n); ++i) { img.resize(img.size() + 1); for (size_t j = 0; j < (1 << n); ++j) { PixelT p = {}; for (size_t k = 0; k < p.size(); ++k) { p[k] = rand() % (t <= 1 ? 10 : 3); cout << p[k]; if (k < p.size() - 1) cout << ","; } cout << " "; img[i].push_back(p); } cout << endl; } // Solve task,resize to 2^m. vector< vector<PixelT> > oimg; if (n <= m) { for (size_t i = 0; i < (1 << m); ++i) { oimg.resize(oimg.size() + 1); for (size_t j = 0; j < (1 << m); ++j) { oimg[i].push_back( img[i >> (m - n)][j >> (m - n)] ); } } } else { for (size_t i = 0; i < (1 << m); ++i) { oimg.resize(oimg.size() + 1); for (size_t j = 0; j < (1 << m); ++j) { // Count number of occurances map<PixelT,size_t> cnt; for (size_t k = (i << (n - m)); k < ((i << (n - m)) + (1 << (n - m))); ++k) for (size_t l = (j << (n - m)); l < ((j << (n - m)) + (1 << (n - m))); ++l) ++cnt[img[k][l]]; // Find max pair<PixelT,0}; for (auto const & p: cnt) if (p.second > maxv.second) maxv = p; oimg[i].push_back(maxv.first); } } } // Output results cout << "Resized:" << endl; for (size_t i = 0; i < oimg.size(); ++i) { for (size_t j = 0; j < oimg[i].size(); ++j) { auto const & p = oimg[i][j]; for (size_t k = 0; k < p.size(); ++k) { cout << p[k]; if (k < p.size() - 1) cout << ","; } cout << " "; } cout << endl; } } return 0; } catch (exception const & ex) { cout << "Exception: " << ex.what() << endl; return -1; } catch (...) { cout << "Unknown Exception!" << endl; return -1; } } )的示例输出:

nchans = 1

RGB图像(n = 2,m = 3 Original: 8 9 8 7 5 7 5 5 0 2 3 0 2 1 7 1 Resized: 8 8 9 9 8 8 7 7 8 8 9 9 8 8 7 7 5 5 7 7 5 5 5 5 5 5 7 7 5 5 5 5 0 0 2 2 3 3 0 0 0 0 2 2 3 3 0 0 2 2 1 1 7 7 1 1 2 2 1 1 7 7 1 1 n = 3,m = 3 Original: 5 5 7 0 6 1 5 6 7 3 1 0 5 8 6 0 0 7 7 7 1 7 6 7 3 8 3 7 7 4 2 1 8 6 9 4 9 5 8 9 9 6 1 4 4 6 8 2 2 4 7 6 8 2 7 3 3 3 0 2 7 5 1 4 Resized: 5 5 7 0 6 1 5 6 7 3 1 0 5 8 6 0 0 7 7 7 1 7 6 7 3 8 3 7 7 4 2 1 8 6 9 4 9 5 8 9 9 6 1 4 4 6 8 2 2 4 7 6 8 2 7 3 3 3 0 2 7 5 1 4 n = 4,m = 3 Original: 2 2 2 2 2 1 2 2 2 0 1 0 0 0 0 2 0 0 2 2 2 2 1 2 1 2 1 2 0 1 1 2 1 0 2 0 1 0 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 2 0 1 2 1 0 0 2 2 1 1 0 1 1 2 1 1 2 0 1 1 0 0 1 1 1 2 2 1 2 2 0 2 1 2 1 0 0 0 1 2 1 0 2 2 0 0 0 2 1 2 2 1 0 0 1 2 1 0 1 0 2 2 2 0 2 2 0 1 1 2 2 1 0 2 1 0 1 2 0 2 2 1 0 0 0 2 0 1 2 2 2 1 1 2 1 1 1 2 1 1 1 0 2 2 2 1 1 2 1 0 0 0 0 2 1 0 0 0 2 2 1 1 2 2 0 0 1 1 1 2 1 2 2 1 1 1 2 2 2 2 0 0 2 2 2 2 1 2 1 2 2 2 2 2 0 0 2 2 0 0 0 2 0 0 0 0 2 0 0 1 1 2 2 0 1 1 0 0 0 0 1 1 0 0 1 1 0 0 1 2 1 2 1 0 Resized: 0 2 2 2 2 1 0 2 0 0 0 1 1 1 1 1 1 0 1 1 1 2 1 2 1 0 1 0 2 0 0 2 0 2 1 2 1 1 1 1 1 0 2 1 2 0 0 2 1 1 1 2 0 0 0 2 0 0 0 1 0 2 1 0 )的示例输出:

nchans = 3

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。