How Can I Efficiently Map Each Pixel Of A Three Channel Image To One Channel?
I am writing a python program to preprocess images to be used as labels for a semantic segmentation task. The original images have three channels, where the vector of three values
Solution 1:
Approach #1
Here's one approach with views
and np.searchsorted
-
# https://stackoverflow.com/a/45313353/ @Divakar
def view1D(a, b): # a, b are arrays
a = np.ascontiguousarray(a)
b = np.ascontiguousarray(b)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(void_dt).ravel(), b.view(void_dt).ravel()
# Trace back a 2D array back to given labels
def labelrows(a2D, label_list):
# Reduce array and labels to 1D
a1D,b1D = view1D(a2D, label_list)
# Use searchsorted to trace back label indices
sidx = b1D.argsort()
return sidx[np.searchsorted(b1D, a1D, sorter=sidx)]
Hence, to use it for a 3D
image array, we need to reshape merging the height and width into one dimension and keeping the color channel dim as it is and use the labeling function.
Approach #2
Tuned for image elements that have [0,255]
range, we could leverage matrix-multiplication for the dimensionality-reduction and hence boost up the performance further, like so -
def labelpixels(img3D, label_list):
# scale array
s = 256**np.arange(img.shape[-1])
# Reduce image and labels to 1D
img1D = img.reshape(-1,img.shape[-1]).dot(s)
label1D = np.dot(label_list, s)
# Use searchsorted to trace back label indices
sidx = label1D.argsort()
return sidx[np.searchsorted(label1D, img1D, sorter=sidx)]
Sample run on how to extend for image case and also verify -
In [194]: label_list = [[0,255,255], [0,0,0], [0,0,255], [255, 0, 255]]
In [195]: idx = [2,0,3,1,0,3,1,2] # We need to retrieve this back
In [196]: img = np.asarray(label_list)[idx].reshape(2,4,3)
In [197]: img
Out[197]:
array([[[ 0, 0, 255],
[ 0, 255, 255],
[255, 0, 255],
[ 0, 0, 0]],
[[ 0, 255, 255],
[255, 0, 255],
[ 0, 0, 0],
[ 0, 0, 255]]])
In [198]: labelrows(img.reshape(-1,img.shape[-1]), label_list)
Out[198]: array([2, 0, 3, 1, 0, 3, 1, 2])
In [217]: labelpixels(img, label_list)
Out[217]: array([2, 0, 3, 1, 0, 3, 1, 2])
Finally, the output would need a reshape back to 2D
-
In [222]: labelpixels(img, label_list).reshape(img.shape[:-1])
Out[222]:
array([[2, 0, 3, 1],
[0, 3, 1, 2]])
Post a Comment for "How Can I Efficiently Map Each Pixel Of A Three Channel Image To One Channel?"