Search code examples
pythonnumpyopencvpng

Get unique pixels in image


The following:

image = cv2.imread("image.png")
print(image.shape)
print(np.unique(image,axis=1))

if giving:

(700, 500, 3)
[[[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 ...

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ...
  [255 255 255]
  [255 255 255]
  [255 255 255]]]

How do I get the unique pixels? For example, [255 255 255] should be one of the unique pixel values.


Solution

  • As per comments, one of the ways to do that is np.unique(image.reshape(-1,3), axis=0) but this is can be improved significantly using dimensionality reduction with numba

    import numpy as np
    from numba import njit, prange
    
    @njit(parallel=True)
    def _numba_dot(arr, dimshape, len_arr, len_dimshape, su):
        for i in prange(len_arr):
            for j in range(len_dimshape):
                su[i] = su[i] + arr[i][j] * dimshape[j]
            
    def numba_dimreduce(arr, dtype=int):
        dimshape = np.array([1, 256, 65536])
        su = np.zeros(len(arr), dtype=dtype)
        _numba_dot(arr, dimshape, len(arr), len(dimshape), su)
        return su
    
    >>> image = np.array([[[255, 255, 255], [255, 254, 254]], [[255, 254, 254], [254, 254, 254]]])
    >>> img = image.reshape(-1, 3))
    >>> img
    array([[255, 255, 255],
       [255, 254, 254],
       [255, 254, 254],
       [254, 254, 254]])
    >>> u, idx = np.unique(numba_dimreduce(img), return_index=True)
    >>> img[idx]
    array([[254, 254, 254],
           [255, 254, 254],
           [255, 255, 255]])
    

    In case you have large images, you might like to try np.bincount-like methods for further speed ups.