It looks like you are confused by the data ordering of NumPy array storing an OpenCV images.
The natural ordering of image in OpenCV (in memory) is "raw major" with b
,g
,r
,b
,g
,r
... data ordering:
Row 0: BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR
Row 1: BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR
Row 3: BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR
The indexing of the image
array is: image[r, c, ch]
(row, column, color_channel):
image_modified
is a list of modified columns, each element in the list applies one color channel:
[
All columns of blue channel of column
Applies image column 0: BBBBBBBBBBBBBBBBBBBBBBBBBBB,
Applies image column 1: BBBBBBBBBBBBBBBBBBBBBBBBBBB,
Applies image column 2: BBBBBBBBBBBBBBBBBBBBBBBBBBB,
All columns of green channel of column
Applies image column 0: GGGGGGGGGGGGGGGGGGGGGGGGGGG,
Applies image column 1: GGGGGGGGGGGGGGGGGGGGGGGGGGG,
Applies image column 2: GGGGGGGGGGGGGGGGGGGGGGGGGGG,
All columns of red channel of column
Applies image column 0: RRRRRRRRRRRRRRRRRRRRRRRRRRR,
Applies image column 1: RRRRRRRRRRRRRRRRRRRRRRRRRRR,
Applies image column 2: RRRRRRRRRRRRRRRRRRRRRRRRRRR,
...
]
For fixing the ordering, we may apply np.reshape
followed by np.transpose
:
Reshape to 3
columns by <cols
> rows by <rows
> elements:
image_modified = np.reshape(image_modified, ((3, cols, rows)))
Transpose (permute) to rows
by cols
by 3
:
image_modified = np.transpose(image_modified, (2, 1, 0))
Code sample:
import numpy as np
import cv2
def fill_zeros_with_last(arr):
prev = np.arange(len(arr))
prev[arr == 0] = 0
prev = np.maximum.accumulate(prev)
return arr[prev]
image = cv2.imread('test_image.jpg')
rows, cols = image.shape[0], image.shape[1] # Get height and width of image
image_modified = [] # to store the processed image
for k in range(3):
for j in range(cols):
image1 = fill_zeros_with_last(image[:, j, k]) # replaces 0s with the previous nonzero value.
image_modified.append(image1)
image_modified = np.reshape(image_modified, ((3, cols, rows))) # to reshape the image
image_modified = np.transpose(image_modified, (2, 1, 0)) # Fix the data ordering to match OpenCV convention
cv2.imwrite('image_modified.png', image_modified) # Use cv2.imwrite instead of using PIL because the color ordering is different.
Instead of messing with the ordering, we may use NumPy array for storing image_modified
, instead of using a list:
import numpy as np
import cv2
def fill_zeros_with_last(arr):
prev = np.arange(len(arr))
prev[arr == 0] = 0
prev = np.maximum.accumulate(prev)
return arr[prev]
image = cv2.imread('test_image.jpg')
rows, cols = image.shape[0], image.shape[1] # Get height and width of image
#image_modified = [] # to store the processed image
image_modified = np.zeros_like(image) # Initialize image_modified to array of zeros with same size and type of image
for k in range(3):
for j in range(cols):
image1 = fill_zeros_with_last(image[:, j, k]) # replaces 0s with the previous nonzero value.
image_modified[:, j, k] = image1 # Update the column
#image_modified.append(image1)
cv2.imwrite('image_modified.png', image_modified) # Use cv2.imwrite instead of using PIL because the color ordering is different.
Output:
