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:
