如何将canvas imageData转换为嵌套象限

时间:2014-04-20 09:40:43

标签: javascript algorithm math canvas

示例:

假设我的画布分辨率为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"。用它作为起点是个好主意吗?

2 个答案:

答案 0 :(得分:1)

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

我们可以一点一点地写x,如下:

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

和y as:

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我们在顶部,如果y> 255,我们不是。测试x> 255是否与测试x&amp; 256 =&gt;测试最重要的位是否设置。
事实上,如果你仔细考虑,所有分辨率都会出现完全相同的方案:比如我们在象限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 - &gt;象限坐标函数是非常简单的位糖化:

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;
}

另一方面,象限坐标 - &gt; (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  

答案 1 :(得分:0)

如果x坐标是(big-endian)二进制中的abcdefghi且y坐标是二进制的jklmnopqr,那么base-4中表示的象限数是(达到一致)交织ajbkcldmenfogphqir的象限重新编号。这里有一些比特笨拙的C代码用于32位坐标(为了其他目的而编写)。

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;
}