Возможно, вы могли бы что-то сделать, используя контейнер 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, поэтому все, что вам нужно сделать, это повернуть).
Кодпрокомментировал, чтобы объяснить, что он делает, но в основном он использует рекурсию шаблона для поиска по индексам по порядку, как только индекс находит некоторые совпадения, он пытается отсортировать их в порядке релевантности и возвращает наилучшее совпадение.Чтобы добавить другое свойство, вам необходимо сделать следующее:
- Добавить свойство к
ImageCacheItem
- Добавить сравнение для свойства к
ImageCacheSimilarity
- (необязательно) Добавьте еще один индекс, соответствующий ему, в
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;
}