How to effectively loop through each pixel for saving time with numpy?
Question:
As you know looping through each pixels and accessing their values with opencv takes too long. As a beginner I’m trying to learn opencv myself when I tried this approach it took me around 7-10 seconds of time to loop through image and perform operations.
code is as below
original_image = cv2.imread(img_f)
image = np.array(original_image)
for y in range(image.shape[0]):
for x in range(image.shape[1]):
# remove grey background
if 150 <= image[y, x, 0] <= 180 and
150 <= image[y, x, 1] <= 180 and
150 <= image[y, x, 2] <= 180:
image[y, x, 0] = 0
image[y, x, 1] = 0
image[y, x, 2] = 0
# remove green dashes
if image[y, x, 0] == 0 and
image[y, x, 1] == 169 and
image[y, x, 2] == 0:
image[y, x, 0] = 0
image[y, x, 1] = 0
image[y, x, 2] = 0
in above code i’m just trying to remove grey and green pixel colors.
I found similar question asked here but im not able to understand how to use numpy in my usecase as i’m beginner in python and numpy.
Any help or suggestion for solving this will be appreciated thanks
Answers:
You can apply numpy filtering to image. In your scenario it would be:
mask_gray = (
(150 <= image[:, :, 0]) & (image[:, :, 0] <= 180) &
(150 <= image[:, :, 1]) & (image[:, :, 1] <= 180) &
(150 <= image[:, :, 2]) & (image[:, :, 2] <= 180)
)
image[mask_gray] = 0
mask_green = (
(image[:, :, 0] == 0) &
(image[:, :, 1] == 169) &
(image[:, :, 2] == 0)
)
image[mask_green] = 0
mask_gray
and mask_green
here are boolean masks
You can take advantage of NumPy’s vectorized operations to eliminate all loops which should be much faster.
# Remove grey background
is_grey = ((150 <= image) & (image <= 180)).all(axis=2, keepdims=True)
image = np.where(is_grey, 0, image)
# Remove green dashes
is_green_dash = (image[..., 0] == 0) & (image[..., 1] == 169) & (image[..., 2] == 0)
is_green_dash = is_green_dash[..., np.newaxis] # append a new dim at the end
image = np.where(is_green_dash, 0, image)
Both invocations of np.where
rely on NumPy’s broadcasting.
One way to improve the performance of your code would be to use the cv2.inRange()
function to find pixels with the desired colors, and then use the cv2.bitwise_and()
function to remove those pixels from the image. This can be done more efficiently than looping through each pixel individually, which can be slow and computationally intensive. Here is an example of how this could be implemented:
import cv2
import numpy as np
# Read the image
original_image = cv2.imread('image.jpg')
# Define the colors to be removed as ranges of BGR values
grey_min = np.array([150, 150, 150], np.uint8)
grey_max = np.array([180, 180, 180], np.uint8)
green_min = np.array([0, 0, 0], np.uint8)
green_max = np.array([0, 169, 0], np.uint8)
# Use inRange() to find pixels with the desired colors
grey_mask = cv2.inRange(original_image, grey_min, grey_max)
green_mask = cv2.inRange(original_image, green_min, green_max)
# Use bitwise_and() to remove the pixels with
If you insist on writing your own loops…
You could just use numba
. It’s a JIT compiler for Python code.
from numba import njit
@njit
def your_function(input):
...
return output
input = cv.imread(...) # yes this will shadow the builtin of the same name
output = your_function(input)
The first time you call your_function
, it’ll take a second to compile. All further calls are blazingly fast.
As you know looping through each pixels and accessing their values with opencv takes too long. As a beginner I’m trying to learn opencv myself when I tried this approach it took me around 7-10 seconds of time to loop through image and perform operations.
code is as below
original_image = cv2.imread(img_f)
image = np.array(original_image)
for y in range(image.shape[0]):
for x in range(image.shape[1]):
# remove grey background
if 150 <= image[y, x, 0] <= 180 and
150 <= image[y, x, 1] <= 180 and
150 <= image[y, x, 2] <= 180:
image[y, x, 0] = 0
image[y, x, 1] = 0
image[y, x, 2] = 0
# remove green dashes
if image[y, x, 0] == 0 and
image[y, x, 1] == 169 and
image[y, x, 2] == 0:
image[y, x, 0] = 0
image[y, x, 1] = 0
image[y, x, 2] = 0
in above code i’m just trying to remove grey and green pixel colors.
I found similar question asked here but im not able to understand how to use numpy in my usecase as i’m beginner in python and numpy.
Any help or suggestion for solving this will be appreciated thanks
You can apply numpy filtering to image. In your scenario it would be:
mask_gray = (
(150 <= image[:, :, 0]) & (image[:, :, 0] <= 180) &
(150 <= image[:, :, 1]) & (image[:, :, 1] <= 180) &
(150 <= image[:, :, 2]) & (image[:, :, 2] <= 180)
)
image[mask_gray] = 0
mask_green = (
(image[:, :, 0] == 0) &
(image[:, :, 1] == 169) &
(image[:, :, 2] == 0)
)
image[mask_green] = 0
mask_gray
and mask_green
here are boolean masks
You can take advantage of NumPy’s vectorized operations to eliminate all loops which should be much faster.
# Remove grey background
is_grey = ((150 <= image) & (image <= 180)).all(axis=2, keepdims=True)
image = np.where(is_grey, 0, image)
# Remove green dashes
is_green_dash = (image[..., 0] == 0) & (image[..., 1] == 169) & (image[..., 2] == 0)
is_green_dash = is_green_dash[..., np.newaxis] # append a new dim at the end
image = np.where(is_green_dash, 0, image)
Both invocations of np.where
rely on NumPy’s broadcasting.
One way to improve the performance of your code would be to use the cv2.inRange()
function to find pixels with the desired colors, and then use the cv2.bitwise_and()
function to remove those pixels from the image. This can be done more efficiently than looping through each pixel individually, which can be slow and computationally intensive. Here is an example of how this could be implemented:
import cv2
import numpy as np
# Read the image
original_image = cv2.imread('image.jpg')
# Define the colors to be removed as ranges of BGR values
grey_min = np.array([150, 150, 150], np.uint8)
grey_max = np.array([180, 180, 180], np.uint8)
green_min = np.array([0, 0, 0], np.uint8)
green_max = np.array([0, 169, 0], np.uint8)
# Use inRange() to find pixels with the desired colors
grey_mask = cv2.inRange(original_image, grey_min, grey_max)
green_mask = cv2.inRange(original_image, green_min, green_max)
# Use bitwise_and() to remove the pixels with
If you insist on writing your own loops…
You could just use numba
. It’s a JIT compiler for Python code.
from numba import njit
@njit
def your_function(input):
...
return output
input = cv.imread(...) # yes this will shadow the builtin of the same name
output = your_function(input)
The first time you call your_function
, it’ll take a second to compile. All further calls are blazingly fast.