【问题标题】:Python - How to crop an image according to its values?Python - 如何根据其值裁剪图像?
【发布时间】:2020-06-26 18:20:17
【问题描述】:

我有一个像这样的图像:全零像素;具有一些非零值的正方形。我想裁剪图像以创建仅具有非零值的新图像。我尝试过image = np.extract(image != 0, image)image = image[image != 0] 之类的东西,但它们返回一个数组,不再返回一个矩阵。 我该如何解决? 谢谢

example of image

【问题讨论】:

    标签: python image numpy opencv matrix


    【解决方案1】:

    一种方法是使用np.nonzerondarray.reshape

    x, y = np.nonzero(image)
    xl,xr = x.min(),x.max()
    yl,yr = y.min(),y.max()
    image[xl:xr+1, yl:yr+1]
    

    使用示例数组:

    image = np.array([[0,0,0,0,0], [0,0,1,2,0], [0,0,3,3,0], [0,0,0,0,0], [0,0,0,0,0]])
    
    print(image)
    
    array([[0, 0, 0, 0, 0],
           [0, 0, 1, 2, 0],
           [0, 0, 3, 3, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0]])
    
    x, y = np.nonzero(image)
    xl,xr = x.min(),x.max()
    yl,yr = y.min(),y.max()
    image[xl:xr+1, yl:yr+1]
    
    array([[1, 2],
           [3, 3]])
    

    【讨论】:

    • 提取最小值和最大值后,您可以直接切片为image[x.min(): x.max()+1, y.min(): y.max()+1] 来获取子矩阵,而不是使用reshape。
    • cv.boundingRect 做同样的事情并且速度更快
    【解决方案2】:

    作为@yatu 解决方案的替代方案,您可以使用numpy.ix_,它允许索引传递数组的叉积:

    import numpy as np
    image = np.array([[0,0,0,0,0], [0,0,1,2,0], [0,0,3,3,0], [0,0,0,0,0], [0,0,0,0,0]])
    
    x, y = np.nonzero(image)
    image[np.ix_(np.unique(x),np.unique(y))]
    array([[1, 2],
           [3, 3]])
    

    在哪里

    np.ix_(np.unique(x),np.unique(y))
    (array([[1],
            [2]], dtype=int64), array([[2, 3]], dtype=int64))
    

    【讨论】:

      【解决方案3】:

      如果你不想使用 numpy np.nonzero,你可以使用cv.boundingRect

      另外,cv.boundingRect 比 numpy 快(可能是因为 C++ 绑定?)。

      image = np.array([[0,0,0,0,0], [0,0,1,2,0], [0,0,3,3,0], [0,0,0,0,0], [0,0,0,0,0]])
      
      # the line below is usually not necessary when dealing with
      # gray scale images opened with imread(), but you need it if 
      # you're working with the array created above, to get uint8 values
      image = cv.convertScaleAbs(image)
      
      x, y, w, h = cv.boundingRect(image)
      newImg = image[y:y+h, x:x+w]
      

      时间

      在上面的示例中,使用 5x5 数组,cv.boundingRect 快 2 倍:

      %timeit x, y = np.nonzero(image)
      1.4 µs ± 219 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
      
      %timeit x, y, w, h = cv.boundingRect(image)
      722 ns ± 30.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
      

      对于 1000x1500 的图像,cv.boundingRect 的速度要快得多(40 倍到 2000 倍以上,具体取决于图像的内容):

      # blank (all zero) image 
      image = np.zeros((1500,1000), dtype=np.uint8)
      
      %timeit x, y = np.nonzero(image)
      6.67 ms ± 40 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      
      %timeit x, y, w, h = cv.boundingRect(image)
      159 µs ± 1.14 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
      
      # only non-zero pixels
      image = np.ones((1500,1000), dtype=np.uint8)
      
      %timeit x, y = np.nonzero(image)
      17.2 ms ± 155 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      
      %timeit x, y, w, h = cv.boundingRect(image)
      7.48 µs ± 46.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
      

      如果您只处理一张图像,Numpy 仍然足够快。但是,例如,在处理实时视频帧时情况会有所不同。

      【讨论】:

        猜你喜欢
        • 2016-05-04
        • 1970-01-01
        • 2021-10-02
        • 1970-01-01
        • 2022-07-24
        • 2021-04-01
        • 2012-11-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多