【问题标题】:How to make a checkerboard in numpy?如何在 numpy 中制作棋盘格?
【发布时间】:2011-01-11 06:52:26
【问题描述】:

我正在使用 numpy 将像素数组初始化为灰色棋盘格(“无像素”或透明的经典表示)。似乎应该有一种奇妙的方法来使用 numpy 惊人的数组分配/切片/切块操作,但这是我想出的最好的方法:

w, h = 600, 800
sq = 15    # width of each checker-square
self.pix = numpy.zeros((w, h, 3), dtype=numpy.uint8)
# Make a checkerboard
row = [[(0x99,0x99,0x99),(0xAA,0xAA,0xAA)][(i//sq)%2] for i in range(w)]
self.pix[[i for i in range(h) if (i//sq)%2 == 0]] = row
row = [[(0xAA,0xAA,0xAA),(0x99,0x99,0x99)][(i//sq)%2] for i in range(w)]
self.pix[[i for i in range(h) if (i//sq)%2 == 1]] = row

它有效,但我希望有更简单的东西。

【问题讨论】:

  • 我想你的意思是numpy.zeros((h, w, 3), ...)(翻转wh)。
  • 我找到了这个解决方案:np.tile( np.array([[0,1],[1,0]]), (h, w))

标签: python numpy


【解决方案1】:

你不能使用 hstack 和 vstack 吗?见here。 像这样:

>>> import numpy as np
>>> b = np.array([0]*4)
>>> b.shape = (2,2)
>>> w = b + 0xAA
>>> r1 = np.hstack((b,w,b,w,b,w,b))
>>> r2 = np.hstack((w,b,w,b,w,b,w))
>>> board = np.vstack((r1,r2,r1,r2,r1,r2,r1))

【讨论】:

  • 我在这里没有得到尊重,但这是正确的。 telliott99.blogspot.com/2010/01/…
  • 这不会生成正确大小的数组,尽管看起来您在博客文章中扩展了您的答案。但我们不能投票赞成这篇博文! :) 哎呀!
【解决方案2】:

应该这样做

您想要的任何尺寸的棋盘格(只需传入宽度和高度,如 w、h);我也将单元格高度/宽度硬编码为 1,当然这也可以参数化,以便传入任意值:

>>> import numpy as NP

>>> def build_checkerboard(w, h) :
      re = NP.r_[ w*[0,1] ]              # even-numbered rows
      ro = NP.r_[ w*[1,0] ]              # odd-numbered rows
      return NP.row_stack(h*(re, ro))


>>> checkerboard = build_checkerboard(5, 5)

>>> checkerboard
 Out[3]: array([[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0]])

使用这个二维数组,渲染棋盘的图像很简单,如下所示:

>>> import matplotlib.pyplot as PLT

>>> fig, ax = PLT.subplots()
>>> ax.imshow(checkerboard, cmap=PLT.cm.gray, interpolation='nearest')
>>> PLT.show()

【讨论】:

  • 这很接近,尽管您必须注意一些事情:我希望检查的宽度超过 1 个像素(我将它们设置为 15),并且您不能假设检查将均匀地适合所需棋盘的宽度和高度。
  • 不错! ro 可以简单地写成 re^1。 (只是 XORing re 与 1)
  • 这适用于均匀和非均匀宽度/高度:import numpydef checkerboard(w, h, a=0, b=1):row0 = numpy.r_[ int(w/2.0) * [a,b] + (w % 2) * [a] ]row1 = row0^1return numpy.row_stack( int(h/2.0) * (row0, row1) + (h % 2) * (row0,) )
  • 应编辑答案以允许奇数宽度/高度。
【解决方案3】:

我不确定这是否比我拥有的更好:

c = numpy.fromfunction(lambda x,y: ((x//sq) + (y//sq)) % 2, (w,h))
self.chex = numpy.array((w,h,3))
self.chex[c == 0] = (0xAA, 0xAA, 0xAA)
self.chex[c == 1] = (0x99, 0x99, 0x99)

【讨论】:

    【解决方案4】:

    这是另一种使用ogrid 的方法,它更快一点:

    import numpy as np
    import Image
    
    w, h = 600, 800
    sq = 15
    color1 = (0xFF, 0x80, 0x00)
    color2 = (0x80, 0xFF, 0x00)
    
    def use_ogrid():
        coords = np.ogrid[0:w, 0:h]
        idx = (coords[0] // sq + coords[1] // sq) % 2
        vals = np.array([color1, color2], dtype=np.uint8)
        img = vals[idx]
        return img
    
    def use_fromfunction():
        img = np.zeros((w, h, 3), dtype=np.uint8)
        c = np.fromfunction(lambda x, y: ((x // sq) + (y // sq)) % 2, (w, h))
        img[c == 0] = color1
        img[c == 1] = color2
        return img
    
    if __name__ == '__main__':
        for f in (use_ogrid, use_fromfunction):
            img = f()
            pilImage = Image.fromarray(img, 'RGB')
            pilImage.save('{0}.png'.format(f.func_name))
    

    这是timeit的结果:

    % python -mtimeit -s"import test" "test.use_fromfunction()"
    10 loops, best of 3: 307 msec per loop
    % python -mtimeit -s"import test" "test.use_ogrid()"
    10 loops, best of 3: 129 msec per loop
    

    【讨论】:

    • 如果我的像素颜色不是纯灰色,您能否调整它以使其正常工作?假设我希望这两种颜色是 (0xFF,0x80,0x00) 和 (0x80,0xFF,0x00)
    • 当然。我认为颜色必须是灰色的,这是一个糟糕的设计选择......
    【解决方案5】:

    晚了,但为了后代:

    def check(w, h, c0, c1, blocksize):
      tile = np.array([[c0,c1],[c1,c0]]).repeat(blocksize, axis=0).repeat(blocksize, axis=1)
      grid = np.tile(tile, ( h/(2*blocksize)+1, w/(2*blocksize)+1, 1))
      return grid[:h,:w]
    

    【讨论】:

      【解决方案6】:

      我最近想要同样的功能,我修改了doug的答案如下:

      def gen_checkerboard(grid_num, grid_size):
          row_even = grid_num/2 * [0,1]
          row_odd = grid_num/2 * [1,0]
          checkerboard = numpy.row_stack(grid_num/2*(row_even, row_odd))
          return checkerboard.repeat(grid_size, axis = 0).repeat(grid_size, axis = 1)
      

      【讨论】:

        【解决方案7】:

        我将hass的回答修改如下。

        import math
        import numpy as np
        
        def checkerboard(w, h, c0, c1, blocksize):
                tile = np.array([[c0,c1],[c1,c0]]).repeat(blocksize, axis=0).repeat(blocksize, axis=1)
                grid = np.tile(tile,(int(math.ceil((h+0.0)/(2*blocksize))),int(math.ceil((w+0.0)/(2*blocksize)))))
                return grid[:h,:w]
        

        【讨论】:

        • 理想情况下,您应该指出这个答案比另一个答案有什么优势,而不仅仅是告诉我们您已经修改了它。
        【解决方案8】:

        我会使用Kronecker product kron

        np.kron([[1, 0] * 4, [0, 1] * 4] * 4, np.ones((10, 10)))
        

        本例中的棋盘格在每个方向上有 2*4=8 个大小为 10x10 的字段。

        【讨论】:

        • 优雅的代数答案!一个可能的改进(与大多数其他答案一样)是使用 OP 的原始灰度来说明一般性。
        【解决方案9】:

        您可以使用start:stop:stepstepslicing 方法水平和垂直更新矩阵: 这里x[1::2, ::2] 从该行的第一个元素开始,每隔一个矩阵的第二行挑选一个其他元素。

        import numpy as np
        print("Checkerboard pattern:")
        x = np.zeros((8,8),dtype=int)
        # (odd_rows, even_columns)
        x[1::2,::2] = 1
        # (even_rows, odd_columns)
        x[::2,1::2] = 1
        print(x)
        

        【讨论】:

        • 我觉得这是的答案,其余的真的很复杂......
        【解决方案10】:
        import numpy as np
        
        a=np.array(([1,0]*4+[0,1]*4)*4).reshape((8,8))
        print(a)
        
        
        [[1 0 1 0 1 0 1 0]
         [0 1 0 1 0 1 0 1]
         [1 0 1 0 1 0 1 0]
         [0 1 0 1 0 1 0 1]
         [1 0 1 0 1 0 1 0]
         [0 1 0 1 0 1 0 1]
         [1 0 1 0 1 0 1 0]
         [0 1 0 1 0 1 0 1]]
        

        【讨论】:

          【解决方案11】:
          def checkerboard(shape):
              return np.indices(shape).sum(axis=0) % 2
          

          最紧凑,可能是最快的,也是发布的唯一推广到 n 维的解决方案。

          【讨论】:

          • 非常聪明的实现!
          • 有人能解释一下这个解决方案吗?
          • @HazimAhmed np.indices(shape) 创建两个不同的数组,一个在每行中具有升序整数,另一个在每列中具有升序整数。一旦你对它们求和,你就会得到一个在行和列中都有升序整数的矩阵(例如,第一行来自 [0,...,9] 第二行来自 [1,...,10] 等。 )。一旦你进行模运算,你就会在行和列中得到交替的余数——这正是一个棋盘。确实是聪明的实现。
          • 这会进行计算(summod),并且比其他建议的解决方案要慢得多。
          • 它在任何意义上肯定不是计算最优的;尽管在 numpy-practice 中,sum 或 mods 无关紧要;它的三个操作,每个操作都会遍历整个数组一次;内存访问模式是主要瓶颈;任何将其拆分为更多数组操作的解决方案,或者不使用数组操作但某种形式的 python 迭代的解决方案,例如第二个最受好评的示例(不使用任何总和或 mods),肯定会慢得多。
          【解决方案12】:

          相同的最简单实现。

          import numpy as np
          
          n = int(input())
          checkerboard = np.tile(np.array([[0,1],[1,0]]), (n//2, n//2))
          print(checkerboard)
          

          【讨论】:

          • @demokritos 你错过了上下文。
          【解决方案13】:
          n = int(input())
          import numpy as np
          m=int(n/2)
          a=np.array(([0,1]*m+[1,0]*m)*m).reshape((n,n))
          
          print (a)
          

          因此,如果输入为 n = 4,则输出将如下所示:

          [[0 1 0 1]
           [1 0 1 0]
           [0 1 0 1]
           [1 0 1 0]]
          

          【讨论】:

            【解决方案14】:

            使用平铺功能:

            import numpy as np
            n = int(input())
            x = np.tile(arr,(n,n//2))
            x[1::2, 0::2] = 1
            x[0::2, 1::2] = 1
            print(x)
            

            【讨论】:

              【解决方案15】:

              这是一个 numpy 解决方案,通过一些检查确保宽度和高度可以被正方形大小整除。

              def make_checkerboard(w, h, sq, fore_color, back_color):
                  """
                  Creates a checkerboard pattern image
                  :param w: The width of the image desired
                  :param h: The height of the image desired
                  :param sq: The size of the square for the checker pattern
                  :param fore_color: The foreground color
                  :param back_color: The background color
                  :return:
                  """
                  w_rem = np.mod(w, sq)
                  h_rem = np.mod(w, sq)
                  if w_rem != 0 or h_rem != 0:
                      raise ValueError('Width or height is not evenly divisible by square '
                                       'size.')
                  img = np.zeros((h, w, 3), dtype='uint8')
                  x_divs = w // sq
                  y_divs = h // sq
                  fore_tile = np.ones((sq, sq, 3), dtype='uint8')
                  fore_tile *= np.array([[fore_color]], dtype='uint8')
                  back_tile = np.ones((sq, sq, 3), dtype='uint8')
                  back_tile *= np.array([[back_color]], dtype='uint8')
                  for y in np.arange(y_divs):
                      if np.mod(y, 2):
                          b = back_tile
                          f = fore_tile
                      else:
                          b = fore_tile
                          f = back_tile
                      for x in np.arange(x_divs):
                          if np.mod(x, 2) == 0:
                              img[y * sq:y * sq + sq, x * sq:x * sq + sq] = f
                          else:
                              img[y * sq:y * sq + sq, x * sq:x * sq + sq] = b
                  return img
              

              【讨论】:

                【解决方案16】:

                您可以使用 Numpy 的 tile 函数来获取大小为 n*m 的棋盘数组,其中 n 和 m 应该是偶数以获得正确的结果...

                def CreateCheckboard(n,m):
                    list_0_1 = np.array([ [ 0, 1], [ 1, 0] ])
                    checkerboard = np.tile(list_0_1, ( n//2, m//2)) 
                    print(checkerboard.shape)
                    return checkerboard
                CreateCheckboard(4,6)
                

                给出输出:

                (4, 6)
                array([[0, 1, 0, 1, 0, 1],
                       [1, 0, 1, 0, 1, 0],
                       [0, 1, 0, 1, 0, 1],
                       [1, 0, 1, 0, 1, 0]])
                
                

                【讨论】:

                • 欢迎来到 StackOverflow! SO 社区试图收集精选的高质量答案,与所有人分享。在回答这些老问题时,你应该确保你的答案解决了原始问题,格式正确,并提供了新的价值。您共享但不直接改进任何当前答案的代码;也许尝试将您的想法浓缩成评论?
                【解决方案17】:

                使用 tile() 编写棋盘矩阵的最简单方法

                array = np.tile([0,1],n//2)
                array1 = np.tile([1,0],n//2)
                finalArray = np.array([array, array1], np.int32)
                finalArray = np.tile(finalArray,(n//2,1))
                

                【讨论】:

                  【解决方案18】:

                  假设我们需要一个长度和宽度(偶数)为l,b的模式。

                  base_matrix = np.array([[0,1],[1,0]])

                  由于这个将用作图块的基本矩阵已经具有 2 X 2 的长度和宽度,因此我们需要除以 2。

                  print np.tile(base_matrix, (l / 2, b / 2))

                  print (np.tile(base,(4/2,6/2)))
                  [[0 1 0 1 0 1]
                   [1 0 1 0 1 0]
                   [0 1 0 1 0 1]
                   [1 0 1 0 1 0]]
                  

                  【讨论】:

                    【解决方案19】:
                    n = int(input())
                    import numpy as np
                    a = np.array([0])
                    x = np.tile(a,(n,n))
                    x[1::2, ::2] = 1
                    x[::2, 1::2] = 1
                    print(x)
                    

                    我猜这使用 numpy.tile( ) 函数效果很好。

                    【讨论】:

                      【解决方案20】:

                      非常非常晚了,但我需要一个解决方案,允许在任意大小的棋盘格上使用非单位棋盘格大小。这是一个简单快速的解决方案:

                      import numpy as np
                      
                      def checkerboard(shape, dw):
                          """Create checkerboard pattern, each square having width ``dw``.
                      
                          Returns a numpy boolean array.
                          """
                          # Create individual block
                          block = np.zeros((dw * 2, dw * 2), dtype=bool)
                          block[dw:, :dw] = 1
                          block[:dw, dw:] = 1
                      
                          # Tile until we exceed the size of the mask, then trim
                          repeat = (np.array(shape) + dw * 2) // np.array(block.shape)
                          trim = tuple(slice(None, s) for s in shape)
                          checkers = np.tile(block, repeat)[trim]
                      
                          assert checkers.shape == shape
                          return checkers
                      

                      要将棋盘格转换为颜色,您可以这样做:

                      checkers = checkerboard(shape, dw)
                      img = np.empty_like(checkers, dtype=np.uint8)
                      img[checkers] = 0xAA
                      img[~checkers] = 0x99
                      

                      【讨论】:

                        【解决方案21】:

                        这里是在numpy中使用tile函数的解决方案。

                        import numpy as np
                        
                        x = np.array([[0, 1], [1, 0]])
                        check = np.tile(x, (n//2, n//2))
                        # Print the created matrix
                        print(check)
                        
                        1. 对于输入 2,输出为
                             [[0 1]
                             [1 0]]
                        
                        1. 对于输入 4,输出为
                             [[0 1 0 1] 
                             [1 0 1 0]
                             [0 1 0 1]
                             [1 0 1 0]]
                        

                        【讨论】:

                          【解决方案22】:
                          import numpy as np
                          n = int(input())
                          arr = ([0, 1], [1,0])
                          print(np.tile(arr, (n//2,n//2)))
                          

                          对于输入 6,输出:

                             [[0 1 0 1 0 1]
                              [1 0 1 0 1 0]
                              [0 1 0 1 0 1]
                              [1 0 1 0 1 0]
                              [0 1 0 1 0 1]
                              [1 0 1 0 1 0]]
                          

                          【讨论】:

                            【解决方案23】:

                            对于那些想要任意大小的正方形/矩形的人:

                            import numpy as np
                            # if you want X squares per axis, do squaresize=[i//X for i in boardsize]
                            def checkerboard(boardsize, squaresize):
                                return np.fromfunction(lambda i, j: (i//squaresize[0])%2 != (j//squaresize[1])%2, boardsize).astype(int)
                            
                            print(checkerboard((10,15), (2,3)))
                            [[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
                             [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
                             [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
                             [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
                             [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
                             [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
                             [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
                             [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
                             [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
                             [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]]
                            

                            【讨论】:

                              【解决方案24】:

                              n换成偶数,你就会得到答案。

                              import numpy as np
                              b = np.array([[0,1],[1,0]])
                              np.tile(b,(n, n))
                              

                              【讨论】:

                              • 简短而简单
                              【解决方案25】:

                              基于 Eelco Hoogendoorn 的 answer,如果您想要一个具有各种瓷砖尺寸的棋盘,您可以使用这个:

                              def checkerboard(shape, tile_size):
                                  return (np.indices(shape) // tile_size).sum(axis=0) % 2
                              
                              

                              【讨论】:

                              • 似乎是可变瓷砖尺寸的最优雅的解决方案。谢谢
                              【解决方案26】:

                              perfplot 分析表明,最好(最快、最易读、内存效率最高)的解决方案是通过切片,

                              def slicing(n):
                                  A = np.zeros((n, n), dtype=int)
                                  A[1::2, ::2] = 1
                                  A[::2, 1::2] = 1
                                  return A
                              

                              堆叠解决方案比大型矩阵要快一些,但可以说可读性较差。票数最高的答案也是最慢的

                              重现情节的代码:

                              import numpy as np
                              import perfplot
                              
                              
                              def indices(n):
                                  return np.indices((n, n)).sum(axis=0) % 2
                              
                              
                              def slicing(n):
                                  A = np.zeros((n, n), dtype=int)
                                  A[1::2, ::2] = 1
                                  A[::2, 1::2] = 1
                                  return A
                              
                              
                              def tile(n):
                                  return np.tile([[0, 1], [1, 0]], (n // 2, n // 2))
                              
                              
                              def stacking(n):
                                  row0 = np.array(n // 2 * [0, 1] + (n % 2) * [0])
                                  row1 = row0 ^ 1
                                  return np.array(n // 2 * [row0, row1] + (n % 2) * [row0])
                              
                              
                              def ogrid(n):
                                  coords = np.ogrid[0:n, 0:n]
                                  return (coords[0] + coords[1]) % 2
                              
                              
                              b = perfplot.bench(
                                  setup=lambda n: n,
                                  kernels=[slicing, indices, tile, stacking, ogrid],
                                  n_range=[2 ** k for k in range(14)],
                                  xlabel="n",
                              )
                              b.save("out.png")
                              b.show()
                              

                              【讨论】:

                              • 我的支持;请注意,当我声称“可能是最快的”时,kron 是未在此处测试的最受好评的答案,而投票第二多的答案是未矢量化的。
                              【解决方案27】:

                              给定奇数或偶数“n”,以下方法在棋盘模式中生成“arr”,并且不使用循环。如果 n 是奇数,则使用起来非常简单。如果 n 是偶数,我们生成 n-1 的棋盘格,然后添加额外的行和列。

                              rows = n-1 if n%2 == 0 else n
                              arr=(rows*rows)//2*[0,1]
                              arr.extend([0])
                              arr = np.reshape(arr, (rows,rows))
                              
                              if n%2 == 0:
                                  extra = (n//2*[1,0])
                                  arr = np.concatenate((arr, np.reshape(extra[:-1], (1,n-1))))
                                  arr = np.concatenate((arr, np.reshape(extra, (n,1))), 1)
                              

                              【讨论】:

                                猜你喜欢
                                • 1970-01-01
                                • 2012-04-20
                                • 2022-11-04
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 1970-01-01
                                • 2021-05-24
                                • 2013-06-28
                                相关资源
                                最近更新 更多