簡體   English   中英

C ++緩存設計建議

[英]C++ Cache Design Advice

我有一個c ++應用程序,有幾種圖像類型(RGB,灰色......),每種類型都有像旋轉或縮放等屬性。 每種圖像類型都是通過其他類型的計算生成的。 例如,通過旋轉GrayImage生成旋轉的GrayImage ,而GrayImage又通過“灰化” RGBImage生成。

我想設計一個緩存類,其方法GetX(...)緩存各種圖像(可能還有計算路徑中的所有圖像)。 如果不在緩存中,該類還將知道如何生成每個圖像。

該類必須滿足一些約束:

  1. 由於我們處理的是不同類型和表示的圖像(RGB,GrayScale等),因此緩存必須為調用代碼返回一個具體類,以便能夠在不使用某種類型的情況下使用它。 因此,緩存機制必須包含包含具體類型的不同緩存結構。 (如果我錯了,請修理我)

     map<...,RGBImage> map<...,GrayImage> 

    例如。

  2. 緩存必須靈活地適應圖像計算的變化。 代碼更改是可以接受的,只要它們不是太大。

我當前的版本為每個圖像類型附加了一個Key結構。 GrayKeyRGBKey等等。 各種鍵包含縮放和旋轉等屬性,並且可以具有特定於圖像的屬性(例如,用於GrayKey )。 緩存保存表單的地圖:

    map <XKey,XImage>

GetX(...)方法接收Key結構作為參數,例如請求Rotated GrayImage。 但是,此實現強制緩存應用大量邏輯來計算圖像。 必須檢查GrayKey是否請求旋轉圖像並采取相應措施。 我想以更優雅的方式“編碼”這個圖像計算關系,但似乎找不到。

有什么建議?

非常感謝。

也許你可以使用Boost.MultiIndex容器做些什么? 它允許您創建一個存儲圖像數據的類型,以及如何操作它的詳細信息,然后根據您想要的任何鍵組合查找值。 如果您之前沒有使用它,它可能看起來有點令人生畏,但我在下面附上了一個例子。

顯然,我的例子只處理緩存機制的存儲/檢索部分,如果你將它們粘在一起,如果查找失敗就可以生成圖像的東西,它應該做你想要的一切。 擴展它也很容易...需要查找額外的參數? 您只需要為ImageCache typedef添加另一個索引。

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/tag.hpp>

#include <boost/shared_array.hpp>

#include <algorithm>
#include <iostream>
#include <utility>

// A cache item, stores the image data, and any values we need to 
// index on.
struct ImageCacheItem
{
    enum RgbMode { RGB_MODE_COLOUR, RGB_MODE_GREYSCALE };

    // Im not sure how much copying goes on in the container,
    // so using a smart pointer to prevent copying large amounts
    // of data.
    boost::shared_array<char> imageBuffer;

    double  rotation;
    double  scale;
    RgbMode rgbMode;

    ImageCacheItem(double r, double s)
    : rotation(r), scale(s)
    {
    }
};

// These are "tag" structures, they are used as part of the 
// multi_index_container as a way to distinguish between indicies.
struct ByRotation {};
struct ByScale {};
struct ByRgb {};
struct ByRotationScale {};

// Typedef of the container itself.
typedef boost::multi_index_container<
    ImageCacheItem, // The data type for the container.  
                    // Note there is no "key" type, as the key values 
                    // are extracted from the data items theselves.
    boost::multi_index::indexed_by<

        // Define an index for the rotation value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByRotation>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation)
        >,

        // Define an index for the scale value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByScale>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
        >,

        // Define an index for the rgb value
        boost::multi_index::hashed_non_unique<
            boost::multi_index::tag<ByRgb>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, ImageCacheItem::RgbMode, rgbMode)
        >,

        // Define an index by rotation + scale
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<ByRotationScale>,
            boost::multi_index::composite_key<
                ImageCacheItem,
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation),
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
            >
        >

    >
> ImageCache;

// Utility typedefs, you'll want these to shorten the iterator
// data types when you're looking things up (see main).
typedef ImageCache::index<ByRotation>::type      ImageCacheByRotation;
typedef ImageCache::index<ByScale>::type         ImageCacheByScale;
typedef ImageCache::index<ByRgb>::type           ImageCacheByRgb;
typedef ImageCache::index<ByRotationScale>::type ImageCacheByRotationScale;

int main()
{
    // Create the cache and add time "images" to it.
    ImageCache cache;
    cache.insert(ImageCacheItem(10, 10));
    cache.insert(ImageCacheItem(10, 20));
    cache.insert(ImageCacheItem(20, 20));

    // look up the images with scale of 20.
    typedef ImageCacheByScale::iterator ScaleIter;

    std::pair<ScaleIter, ScaleIter> scaleResult = cache.get<ByScale>().equal_range(20);
    std::cout << "Found " << std::distance(scaleResult.first, scaleResult.second) << " Results" << std::endl;

    // look up the image with rotation = 10 && scale = 20.
    ImageCacheByRotationScale::iterator rsResult = cache.get<ByRotationScale>().find(boost::make_tuple(10, 20));
    std::cout << "Found " << (rsResult != cache.get<ByRotationScale>().end() ? 1 : 0) << " Results" << std::endl;

    return 0;
}

編輯:這是一個很大的...

我已經嘗試擴展上面的示例,以便在緩存中找到最接近您搜索內容的圖像,但是有偏差,所以如果您想要旋轉45,並且比例為10,如果沒有精確匹配則發現,它會傾向於一個屬性相同的結果,另一個屬性為0(即10的縮放,但是0旋轉,所以你需要做的就是旋轉)。

代碼被注釋以解釋它的作用,但基本上,它使用模板遞歸按順序搜索索引,一旦索引找到一些匹配,它就會嘗試按相關性排序它們,並返回最佳匹配。 要添加其他屬性,您需要執行以下操作:

  1. 將屬性添加到ImageCacheItem
  2. 將屬性的比較添加到ImageCacheSimilarity
  3. (可選)將另一個與其匹配的索引添加到ImageCache typedef

它可能不是最佳解決方案,但我認為它涵蓋了您在評論中提到的用例。

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/tag.hpp>

#include <boost/mpl/list.hpp>
#include <boost/optional.hpp>
#include <boost/ref.hpp>
#include <boost/shared_array.hpp>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <utility>
#include <vector>
#include <typeinfo>

// A cache item, stores the image data, and any values we need to 
// index on.
struct ImageCacheItem
{
    enum RgbMode { RGB_MODE_COLOUR, RGB_MODE_GREYSCALE };

    // Im not sure how much copying goes on in the container,
    // so using a smart pointer to prevent copying large amounts
    // of data.
    boost::shared_array<char> imageBuffer;

    double  rotation;
    double  scale;
    RgbMode rgbMode;

    ImageCacheItem(double r, double s)
    : rotation(r), scale(s)
    {
    }
};

// Calculates the similarity between two ImageCacheItem objects.
int ImageCacheSimilarity(const ImageCacheItem& item, const ImageCacheItem& target)
{
    const double EPSILON = 0.0000001;

    int score = 0;

    // 2 points for an exact match
    // 1 point if the value is 0 (e.g. not rotated, so can be used as a starting point)
    // -1 point otherwise
    score += (std::fabs(item.rotation - target.rotation) < EPSILON) 
        ? 2 
        : ((std::fabs(item.rotation) < EPSILON) ? 1 : -1);

    score += (std::fabs(item.scale - target.scale) < EPSILON) 
        ? 2 
        : ((std::fabs(item.scale) < EPSILON) ? 1 : -1);

    score += (item.rgbMode == target.rgbMode) ? 2 : 0;

    return score;
}

// Orders ImageCacheItem objects based on their similarity to a target value.
struct ImageCacheCmp
{
    const ImageCacheItem& target;

    ImageCacheCmp(const ImageCacheItem& t)
    : target(t)
    {
    }

    bool operator()(const ImageCacheItem& a, const ImageCacheItem& b)
    {
        return (ImageCacheSimilarity(a, target) > ImageCacheSimilarity(b, target));
    }
};

// These are "tag" structures, they are used as part of the 
// multi_index_container as a way to distinguish between indicies.
struct ByRotation {};
struct ByScale {};
struct ByRgb {};
struct ByRotationScale {};

// Typedef of the container itself.
typedef boost::multi_index_container<
    ImageCacheItem, // The data type for the container.  
                    // Note there is no "key" type, as the key values 
                    // are extracted from the data items theselves.
    boost::multi_index::indexed_by<

        // The order of indicies here will affect performance, put the 
        // ones that match against the most fields first.  Its not required
        // to make it work, but it will reduce the number of matches to 
        // compare against later on.

        // Define an index by rotation + scale
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<ByRotationScale>,
            boost::multi_index::composite_key<
                ImageCacheItem,
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation),
                BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
            >
        >,

        // Define an index for the rotation value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByRotation>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, rotation)
        >,

        // Define an index for the scale value
        boost::multi_index::ordered_non_unique<
            boost::multi_index::tag<ByScale>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, double, scale)
        >,

        // Define an index for the rgb value
        boost::multi_index::hashed_non_unique<
            boost::multi_index::tag<ByRgb>,
            BOOST_MULTI_INDEX_MEMBER(ImageCacheItem, ImageCacheItem::RgbMode, rgbMode)
        >
    >
> ImageCache;

// Type of the vector used when collecting index results.  It stores
// references to the values in the cache to minimise copying.
typedef std::vector<boost::reference_wrapper<const ImageCacheItem> > ImageCacheResults;

// Utility class for overload resolution
template <int I>
struct Int2Type
{
    enum { value = I };
};

void FindMatches(
    const ImageCacheItem& item, 
    const ImageCache& cache, 
    ImageCacheResults& results,
    const Int2Type<boost::mpl::size<ImageCache::index_type_list>::type::value>&)
{
    // End of template recursion
}

template <int I>
void FindMatches(
    const ImageCacheItem& item, 
    const ImageCache& cache, 
    ImageCacheResults& results,
    const Int2Type<I>&)
{
    // Get the index being searched
    typedef typename ImageCache::nth_index<I>::type Index;

    // This type knows how to extract the relevant bits of ImageCacheItem
    // for this particular index.
    typename Index::key_from_value keyExtractor;

    // Look for matches in the index.
    std::pair<typename Index::const_iterator, typename Index::const_iterator> iter = 
        cache.get<I>().equal_range(keyExtractor(item));

    // If we found any results, add them to 'results', otherwise
    // continue to the next index.
    if (iter.first != iter.second)
    {
        results.reserve(std::distance(iter.first, iter.second));

        for ( ; iter.first != iter.second; ++iter.first)
        {
            results.push_back(boost::cref(*iter.first));
        }
    }
    else
    {
        FindMatches(item, cache, results, Int2Type<I + 1>());
    }
}

boost::optional<ImageCacheItem> FindClosestImage(const ImageCacheItem& item, const ImageCache& cache)
{
    // Find exact/partial matches according to the indicies.
    ImageCacheResults results;
    FindMatches(item, cache, results, Int2Type<0>());

    // If no matches were found, return an empty value
    if (results.empty())
    {
        return boost::optional<ImageCacheItem>();
    }

    // We got this far, so we must have some candiates, the problem is
    // we dont know which is the best match, so here we sort the results
    // based on proximity to the "item".  However, we are only interested
    // in the best match, so do a partial_sort.
    std::partial_sort(results.begin(), results.begin() + 1, results.end(), ImageCacheCmp(item));

    return results.front().get();
}

int main()
{
    // Create the cache and add some "images" to it.
    ImageCache cache;
    cache.insert(ImageCacheItem(10, 20));
    cache.insert(ImageCacheItem(10, 10));
    cache.insert(ImageCacheItem(10, 2));
    cache.insert(ImageCacheItem(20, 20));
    cache.insert(ImageCacheItem(30, 20));
    cache.insert(ImageCacheItem(30, 0));

    // Look for an image similar to rotation = 30 && scale = 2.
    boost::optional<ImageCacheItem> result = FindClosestImage(ImageCacheItem(30, 2), cache);

    // Have to check if result is value before usage, it would be empty 
    // if not match is found.
    if (result)
    {
        std::cout << "Found (" << result->rotation 
                  << ", " << result->scale << ")" 
                  << std::endl;
    }
    else
    {
        std::cout << "No Results" << std::endl;
    }

    return 0;
}

您是否考慮過使用薄型存取器進行灰色和旋轉彩色圖像? Adobe的通用圖像庫(現在是boost的一部分)使用了一些聰明的迭代器

你考慮過使用STL容器嗎? 使用地圖或集來存儲對圖像的引用。 快速查找以查看您是否已創建圖像。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM