博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于OctTree的快速最近颜色搜索
阅读量:3527 次
发布时间:2019-05-20

本文共 5933 字,大约阅读时间需要 19 分钟。

目录


介绍

查找调色板中与源图像中每个像素最近的颜色的Go-to方法是检查每个像素到每个调色板条目的距离,并使用距离最小的条目。这可以通过预先计算距离和缓存搜索结果等小技巧来加速,但最终结果仍然相当缓慢。您可以通过细分调色板颜色或仅检查最高n位来采取另一个步骤。虽然这两个选项都更快,但结果不太精确。细分将排除相邻空间中的颜色,并仅检查最高n位,本质上不太精确。对于本文,我选择了细分方法。但是为了尽可能精确而不慢,我们必须使最小的细分尽可能小——每个颜色通道一位。

背景

幸运的是,oct-tree已经存在很长一段时间了,它被设计为将颜色细分为每个颜色通道1位的空间。由于这种设计,它可以很快获得包含在其中的所有颜色,它们共享相同的第一个(最高)每个颜色通道的n位。例如,颜色255,240,249254,241,249共享相同的7个高位,这意味着它们将在相同的7级节点中找到。因此,假设255,240,249作为该节点的叶子存在,我们正在搜索最接近254,241,249的颜色。但是,我们搜索的颜色不是叶子。现在我们必须在所有叶子中搜索最近的颜色。幸运的是,这个节点可以拥有的最大叶数是8,我们知道我们的颜色不是其中之一,这意味着我们必须为我们的颜色进行的最大比较数是7。但是,如果我们要寻找一种不同的颜色,并且只有前4位匹配我们调色板中的任何一个呢?然后我们必须搜索该节点的子节点中包含的所有叶子。但是如果我们要搜索一个256色的调色板来寻找最接近的颜色,而我们的颜色显然不是其中之一(因为这棵树会引导我们找到它),那么我们只需要执行最多255次比较,而不是潜在的数千次比较。所以我们真正做的是相同的旧精确距离检查,但使用oct-tree尽可能地减少它们的数量(以及可能的邻居排除)。

使用代码

使用以下类非常简单。只需使用源颜色列表实例化类,然后开始搜索:

// Get a list of the nearest colors in sourceColors to those in imageColors.public Color[] GetNearestColors(Color[] sourceColors, Color[] imageColors) {   Color[] ret = new Color[imageColors.Length];   ColorFinder clfTmp = new ColorFinder(sourceColors);   for(int i = 0; i < imageColors.Length; i++) {      int iNearestColorIndex_i = clfTmp.GetNearestColorIndex(imageColors[i]);      ret[i] = sourceColors[iNearestColorIndex_i];   }   return ret;}

这是类本身:

public class ColorFinder {    // Declare a root node to contain all of the source colors.    private Node _nodRoot;    public ColorFinder(Color[] sourceColors) {        // Create the root node.        _nodRoot = new Node(0, sourceColors);        // Add all source colors to it.        for(int i = 0; i < sourceColors.Length; i++) {            _nodRoot.AddColor(i);        }    }    public int GetNearestColorIndex(Color color) {        int iTmp;        return _nodRoot.GetNearestColorIndex(color, out iTmp);    }    private class Node {        private int _iLevel;        private Color[] _aclSourceColors;        private Node[] _anodChildren = new Node[8];        private int _iColorIndex = -1;        // Cached distance calculations.        private static int[,] Distance = new int[256, 256];        // Cached bit masks.        private static int[] Mask = { 128, 64, 32, 16, 8, 4, 2, 1 };        static Node() {            // precalculate every possible distance            for(int i = 0; i < 256; i++) {                for(int ii = 0; ii < 256; ii++) {                    Distance[i, ii] = ((i - ii) * (i - ii));                }            }        }        public Node(int level, Color[] sourceColors) {            _iLevel = level;            _aclSourceColors = sourceColors;        }        public void AddColor(int colorIndex) {            if(_iLevel == 7) {                // LEAF MODE.                // The deepest level contains the color index and no children.                _iColorIndex = colorIndex;            } else {                // BRANCH MODE.                // Get the oct index for the specified source color at this level.                int iIndex = _GetOctIndex(_aclSourceColors[colorIndex], _iLevel);                // If the necessary child node doesn't exist, create it.                if(_anodChildren[iIndex] == null) {                    _anodChildren[iIndex] = new Node((_iLevel + 1), _aclSourceColors);                }                // Pass the color along to the proper child node.                _anodChildren[iIndex].AddColor(colorIndex);            }        }        public int GetNearestColorIndex(Color color, out int distance) {            int ret = -1;            if(_iLevel == 7) {                // LEAF MODE.                // Return our color index.                ret = _iColorIndex;                // Output the distance in case the caller is comparing distances.                distance = ( Distance[color.R, _aclSourceColors[ret].R] +                             Distance[color.G, _aclSourceColors[ret].G] +                             Distance[color.B, _aclSourceColors[ret].B] );            } else {                // BRANCH MODE.                // Get the oct index for the specified color at this level.                int iIndex = _GetOctIndex(color, _iLevel);                if(_anodChildren[iIndex] == null) {                    // NO DIRECT CHILD EXISTS.                    // Return the child containing the closeset color.                    int iMinDistance = int.MaxValue;                    int iMinColor = -1;                    foreach(Node nod in _anodChildren) {                        if(nod != null) {                            // Get the closeset color contained in the child node and its distance.                            int iDistance_nod;                            int iColor_nod = nod.GetNearestColorIndex(color, out iDistance_nod);                            // If the return color is the closest color found so far, remember it.                            if(iDistance_nod < iMinDistance) {                                iMinDistance = iDistance_nod;                                iMinColor = iColor_nod;                            }                        }                    }                    // Return the closest color index found and output its distance.                    ret = iMinColor;                    distance = iMinDistance;                } else {                    // DIRECT CHILD EXISTS.                    // Return its closest color and distance.                    ret = _anodChildren[iIndex].GetNearestColorIndex(color, out distance);                }            }            return ret;        }        private int _GetOctIndex(Color color, int level) {            // Take 1 bit from each color channel to return a 3-bit value ranging from 0 to 7.            // Level 0 uses the highest bit, level 1 uses the second-highest bit, etc.            int iShift = (7 - level);            return ( ((color.R & Mask[level]) >> iShift     ) |                     ((color.G & Mask[level]) << 1 >> iShift) |                     ((color.B & Mask[level]) << 2 >> iShift) );        }    }}

 

原文地址:

转载地址:http://iizhj.baihongyu.com/

你可能感兴趣的文章
hdu 4135 Co-prime(分解质因数+容斥定理)
查看>>
hdu 4407 Sum(分解质因数+容斥定理)
查看>>
HihoCoder - 1631 Cats and Fish(思维)
查看>>
HihoCoder - 1632 Secret Poems(规律题)
查看>>
zcmu 1900: Problem D: Dominos(单向并查集)
查看>>
zcmu 1059: 田忌赛马(贪心)
查看>>
zcmu 4944: 字符串处理
查看>>
浙江中医药大学2018级新生程序设计竞赛题解
查看>>
zcmu-新生宝贝们的第四次试水题解
查看>>
线段树详解(单点修改+区间修改和查询)
查看>>
线段树 单点修改+区间修改和查询 例题+代码
查看>>
zcmu-新生宝贝们的第五次试水题解
查看>>
fjut 1862 奇怪数列(判断一个数是否为2的整次方)
查看>>
C++ STL 之 set 与 multiset 的基本用法
查看>>
Powers of two(multiset的运用)
查看>>
并查集入门(普通并查集+带删除并查集+关系并查集)
查看>>
吉首大学第八届“新星杯”大学生程序设计大赛 A:组合数(递推组合+求因子数)
查看>>
吉首大学第八届“新星杯”大学生程序设计大赛 I: 夫子云游(简单搜索)
查看>>
吉首大学第八届“新星杯”大学生程序设计大赛 K: WaWa的难题(找规律)
查看>>
Codeforces Round #533 (Div. 2) C. Ayoub and Lost Array(dp)
查看>>