【问题标题】:How to convert canvas imageData to nested quadrants如何将画布 imageData 转换为嵌套象限
【发布时间】:2014-06-04 12:43:55
【问题描述】:

示例:

假设我有一个 512x512 分辨率的画布。我试图得到它的坐标如下:

第一步:将每个画布分成笛卡尔坐标象限

_____ _____ | | | | 2 | 1 | |_____|_____| | | | | 3 | 4 | |_____|_____|

第二步:将每个象限划分为另外四个象限,并在旧象限之后添加新的象限ID,如下所示:

_____ _____ _____ _____ | | | | | | 22 | 21 | 12 | 11 | |_____|____|____|____| | | | | | | 23 | 24 | 13 | 14 | |_____|____|____|____| | | | | | | 32 | 31 | 42 | 41 | |_____|____|____|____| | | | | | | 33 | 34 | 43 | 44 | |_____|____|____|____|

等等……

_____ _____ _____ _____ _____ _____ _____ _____ | | | | | | | | | | 222 | 221 | 212 | 211 | 122 | 121 | 112 | 111 | |_____|____|_____|____|____|____|____|_____| | | | | | | | | | | 223 | 224 | 213 | 214 | 123 | 124 | 113 | 114 | |_____|____|_____|____|____|____|____|_____| | | | | | | | | | | 232 | 231 | 242 | 241 | 132 | 131 | 142 | 141 | |_____|____|_____|____|____|____|____|_____| | | | | | | | | | | 233 | 234 | 243 | 244 | 133 | 134 | 143 | 144 | |_____|____|_____|____|____|____|____|_____| | | | | | | | | | | 322 | 321 | 312 | 311 | 422 | 421 | 412 | 411 | |_____|____|_____|____|____|____|____|_____| | | | | | | | | | | 323 | 324 | 313 | 314 | 423 | 424 | 413 | 414 | |_____|____|_____|____|____|____|____|_____| | | | | | | | | | | 332 | 331 | 342 | 341 |第432章第431章第442章第441章 |_____|____|_____|____|____|____|____|_____| | | | | | | | | | | 333 |第334章第343章第344章第433章第434章第443章第444章 |_____|____|_____|____|____|____|____|_____|

直到象限数等于像素数

我想在这里总结一下如何实现这个功能。 首先,我想到了一个函数,它将获得一个 imageData 索引并返回它的象限 id 。但是这样每次调用函数时我都必须进行一些繁重的(?)计算。
或者从imageData 生成一个新数组,并在需要时通过索引访问它的元素。

我确信有几种方法可以解决这个问题。递归方法很有趣,是否可以在更大的画布上使用?

我的朋友向我指出了以下一段代码,它做了非常相似的事情,但我很难理解这里发生的事情:

for (var y = 0; y < 512; y++)
    for (var x = 0; x < 512; x++){
            var s = "";
        for (var b = 1; b <= 256; b *= 2){
                var yb = y & b;
                var xb = x & b;
                s = String.fromCharCode(49 + (xb != yb) + yb / b * 2) + s;
        }
    }

我没有得到二进制数学或魔法49 数字?这是 "1" 的字符串。以它为起点是个好主意吗?

【问题讨论】:

  • JavaScript 中的位运算符快速参考:developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
  • 我建议不要使用该循环,它会循环约 4194304 次并导致我的 chrome 控制台停止响应。
  • 我们可以假设 1) 宽度和高度是 2 的幂和/或 2) 宽度 == 高度? (取决于此,这是一个非常简单的解决方案)
  • @GameAlchemist 你是对的!

标签: javascript algorithm math canvas


【解决方案1】:

如果 x 坐标是 (big-endian) 二进制中的 abcdefghi 并且 y 坐标是二进制中的 jklmnopqr,那么以 base-4 表示的象限编号是(直到象限的一致重新编号)交错ajbkcldmenfogphqir。这是一些用于 32 位坐标的 C 代码(为其他目的而编写)。

uint64_t expand(int32_t x) {
  uint64_t n = (uint32_t)((int64_t)x - INT32_MIN);
  n = (n | (n << 16)) & UINT64_C(0x0000ffff0000ffff);
  n = (n | (n << 8)) & UINT64_C(0x00ff00ff00ff00ff);
  n = (n | (n << 4)) & UINT64_C(0x0f0f0f0f0f0f0f0f);
  n = (n | (n << 2)) & UINT64_C(0x3333333333333333);
  return (n | (n << 1)) & UINT64_C(0x5555555555555555);
}

int32_t unexpand(uint64_t n) {
  n &= UINT64_C(0x5555555555555555);
  n = (n | (n >> 1)) & UINT64_C(0x3333333333333333);
  n = (n | (n >> 2)) & UINT64_C(0x0f0f0f0f0f0f0f0f);
  n = (n | (n >> 4)) & UINT64_C(0x00ff00ff00ff00ff);
  n = (n | (n >> 8)) & UINT64_C(0x0000ffff0000ffff);
  return (int32_t)((int64_t)(uint32_t)(n | (n >> 16)) + INT32_MIN);
}

uint64_t z_rank(struct Point p) {
  return expand(p.x) | (expand(p.y) << 1);
}

struct Point z_unrank(uint64_t n) {
  return (struct Point){unexpand(n), unexpand(n >> 1)};
}

如果出于某种原因需要字符串,则一次剥掉两个低位,类似这样。

var s = "";
while (n > 0) {
    s = (n & 3) + s;
    n >>= 2;
}

【讨论】:

  • 您可能应该将示例翻译成 JavaScript,因为这是 OP 所要求的,而且当今大多数(主流)计算机都是小端的,所以大端的示例可能没有那么有用?跨度>
  • @Cryptoburner (1) 对于这样的代码,C -> Javascript 的音译并不难。 (2) 代码是字节序无关的。
【解决方案2】:

假设您的图像具有 2^p 宽度 == 高度。
像素的每个 (x,y) 坐标都有一个 x 和 y,它们在 p 位上编码。
现在很好的是,象限坐标只是 x 和 y 坐标的交错:

我们可以把 x 一点一点地写成:

x = x(p-1) x(p-2)  ... x2 x1 x0

和 y 为:

x = y(p-1) y(p-2)  ... y2 y1 y0

那么 q 是 x 和 y 的交错:

q = x(p-1)y(p-1) x(p-2)y(p-2)  ... x2y2 x1y1 x0y0 

q 是您要搜索的象限坐标,但它的构建方式如下:

 _____ _____
|     |     |
|  0  |  2  |
|_____|_____|
|     |     |
|  1  |  3  |
|_____|_____|

也许这样的方案更清晰:

 x = 0   x = 1
 _____________
|      |      |
|  00  |  10  |  y = 0
|______|______|
|      |      |
|  01  |  11  |  y = 1    (figures inside are in binary form)
|______|______|

实际上在上面的方案中,x 由第一位编码,y 由第二位编码。

更一般地说,一个点在哪个最高象限中仅取决于 x 的高位和 y 的高位。
你可以很快想象,如果 x > 255 我们在右边,否则我们在左边。 y 也是如此:如果 y 255 我们不在。测试 x>255 是否与测试 x & 256 相同 => 测试是否设置了最重要的位。
事实上,如果你仔细考虑,完全相同的方案将出现在所有分辨率上:假设我们在 00 象限。现在看看我们是在这个象限的左边还是右边,我们将 x 与 127 进行比较。y 相同.所以实际上我们正在测试 x 和 y 的第二位。

所以你可以看到,两个接两个,(x,y) 点的交错位描述点象限 [xp-1yp-1], [xp-2yp-2], ..., [ x2y2],[x1y1],[x0y0]

现在你可以在这里找到代码:http://jsbin.com/cavifito/1/edit?js,console

x,y -> 象限坐标函数非常简单:

var widthLog=10;  // 2^10 = 1024 X 1024 picture

function getQuadrant(x,y) {
    var q=0;
    var mask = 1 << (widthLog-1) ; 
    for (var i=0; i<widthLog; i++) {
        q<<=1;
        q |= ((x & mask ) == mask);
        q<<=1;
        q |= ((y & mask) == mask);
         x<<=1; y<<=1;      
    }
    return q;
}

另一方面,象限坐标 -> (x,y) 函数是:

function getCoords(q, pt) {
  var x=0, y=0;
    var mask = 1 << (2*(widthLog)-1) ; 
    for (var i=0; i<widthLog; i++) { 
      x<<=1;
      x |= ((q & mask)==mask);
      q<<=1;
      y<<=1;
      y |= ((q & mask)==mask);
      q<<=1;    
    }  
  pt.x = x;
  pt.y = y;
}

这是一个方便的函数,可将象限更改为人类可读的数字(每个数字代表一个象限)。

function quadrantToNum ( q ) {
     var res = 0;
     var bitIndex = 2*widthLog ;
     var mask = 3 << (bitIndex);
     while ( mask ) {
       var qi = (q & mask) >> bitIndex ;
       bitIndex -=2 ;
       mask >>= 2;
       res = 10*res + qi ;
     }
  return res;
}

widthLog = 2 / width = 4 的结果:

00  02  20  22 
01  03  21  23 
10  12  30  32 
11  13  31  33 

widthLog = 3 / width = 8 的结果:

000  002  020  022  200  202  220  222  
001  003  021  023  201  203  221  223  
010  012  030  032  210  212  230  232  
011  013  031  033  211  213  231  233 
100  102  120  122  300  302  320  322  
101  103  121  123  301  303  321  323  
110  112  130  132  310  312  330  332  
111  113  131  133  311  313  331  333  

【讨论】:

  • 你能解释一下你是如何得到这个解决方案的吗?
  • @Alexander:我澄清并说明了我的帖子。
猜你喜欢
  • 1970-01-01
  • 2017-01-29
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
  • 2019-09-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
相关资源
最近更新 更多