We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF or read online on Scribd
You are on page 1/ 12
so7r020 Image shading with OpenCV and Numpy
‘Open Data Stories Ottawa Share this SP
MAY 2020 / NUMPY
Image shading with
OpenCV and Numpy
Twas working on a project recently that involved creating images,
from one image source, that could come close to mimicking a
different image. I was using the OpenCV package, which contains
many helpful functions for image processing.
However, one function that I could not find was one for darkening or
brightening an image. After writing a function to take care of this for
me, I realized that it also offered a good, simple lesson on
manipulating arrays with numpy.
All the code, including the final light filtering function, is available
here.
You can follow along with this tutorial by checking out the
imageFiltering.ipynb notebook provided there. The
numpyFunctions.ipynb notebook provides a simpler view of
some of the numpy functions used herein.
The file imageFilter.py provides a ready to use function that can
apply image filtering to a provide image loaded with OpenCV.
cv2.imread (r'{}\toronto.jpg' . format (imgpath) )
I will be working with two pictures I took with my phone.
opendatastoriosotiawa camage-shading-with-opency-and-aumpy! ane.so7r020 Image shading with OpenCV and Numpy
Open Data Stories Ottawa Share this <7
Hello, Toronto!
eal tan al
Hello, New York City!
We can import OpenCV and load the images with this function.
cv2.imread (r'{}\toronto.jpg' . format (imgpath) )
opendatastoriosotiawa camage-shading-with-opency-and-aumpy!
anesorr2020 Image shading wth OpenGV and Numpy
‘Open Data Stories Ottawa Share this SP
at WeIr snape nere py Cain Unage_array.snape.
Shape of Toronto Image: (3024, 4032, 3)
Shape of N¥C Image: (1339, 4032, 3)
As both are quite large, I will first resize them to 25% of their
original size.
New shape of Toronto Image: (75, 100, 3)
New shape of NYC Image: (33, 100, 3)
Note the dimensions of the array. From the shapes, we can tell the
image’s height and width (dimensions 1 and 2 respectively), but
what is the third dimension? If you are familiar with a computer's
colour display, this will be a no-brainer — it’s the pixel’s RGB values!
The third dimension is simply the red, green, and blue values. Each
one is a number between 0 and 255, and together they give that pixel
a specific colouring.
The process of filtering, or lightening /darkening an image, requires
only that we increase/decrease these values. For each pixel, we need
to do this at the same level for each colour channel.
*Note that you can get access to solid filters like those describe in
Part 1 via the Pillow package for Python. If you want to skip this
section, go to gradient filtering in Part 2 below.
PART 1 - SOLID FILTERING
If we wanted to apply the same level of brightening across an entire
image, we could just update every single pixel with the same
percentage, essentially brightening each point by the same amount
‘opendialastoriesotawa calimage-shading-with-opencv-and-numpy! anaso7r020 Image shading with OpenCV and Numpy
Share this SP
To do so, the first thing we could try is a basic loop. We loop over all
3 dimensions of the array, and update the base elements (the colour
channel values), by adding a certain percentage on to them.
However, remember that we are constrained by the channel's
themselves. We cannot have a value outside of 0-255. In this case,
we can take advantage of Python’s built in min() function, and take
the minimum of 255 or our new pixel value.
scare = cima.tiae()
for i sn cance (1en(s02"_ses))
for j Sp range(ien (Gest ngl3))
for k dm range (ien{feet S03 (41 311)
amg (11 (3) be¥vanue)
Eosyeess seo)
Total time taken: 7.325523614883423
This length of time is fine for just one image. But what if we needed
to process hundreds or thousands? That was the problem I faced, as
generating thousands of images was already a fairly time-consuming
task. Here comes numpy to the rescue!
Since the imace we coe is ctared aga numny array we ean inctaad
‘opendalastriesotawa.calimage-shading-with-opencv-and-numpy! ana,so7r020 Image shading with OpenCV and Numpy
‘Open Data Stories Ottawa Share this SP
Specifically, we can use vectorization of a function to apply it across
the entire array in a fraction of the original time. While vectorize is
actually running loops in the background, it is also running those on
compiled C code, which is much quicker than our Python equivalent.
To perform vectorization on our matrix, the first thing we will need
is a function. Another handy built-in Python method is the lambda.
Lambdas allow us to write quick, one-line functions, and then apply
them to our data.
Delghten = tama x: min(255, x + ( * (pet/100199
In this case, we are simply creating a function based off our original
pixel update.
We can then use numpy's vectorize to make the function applicable
to our numpy array.
array brighten = np.vectorize (brighten)
test_img = array brighten (imgs['NYC'])
test_img = test_img.astype(np.uint8)
The final result looks like this.
‘opendiatastriesotawa.calimage-shading-aith-opencv-and-numpy! sieso7r020 Image shading with OpenCV and Numpy
‘Open Data Stories Ottawa Share this SP
PART 2 - GRADIENT FILTERING
Another way to apply filtering to an image is on a gradient.
Think of a gradient as a gradually changing wave across the image.
We can set a starting percentage and ending percentage, and apply a
gradient filter that gradually takes the image brighter or darker
according to those percentages.
Once again, we can imagine that numpy’s vectorization will help us
apply a gradient filtering quickly and ea
. We will need to update
our method of application however.
First, let’s consider what we are trying to do. We are trying to apply a
gradually changing percentage acro:
n entire array. For example,
we would start at 20% at the leftmost column, and slowly up the
percentage until we hit 100% at the rightmost column. Each RGB
‘opendialastoriesotawa.calimage-shading-with-opencv-and-numpy! enzso7r020 Image shading with OpenCV and Numpy
‘Open Data Stories Ottawa Share this SP
column should be updated by a higher percentage. Here’s what that
might look like.
[[20,40,60,80, 100]
[20,40,60,80, 100]
[20,40,60,80, 100]
[20,40,60,80, 100]
[20,40,60,80, 100]]
Asample grid of gradient brightening percentages
The next thing to consider is how we can apply this array with the
original image array. Obviously, we will want to generate this
percentage array to be the same size as the image. However, we will
not need the third dimension to be of size 3, we can apply the same
percentage value across each colour channel.
As it turns out, vectorizing can take in a function that requires two
different matrices, and apply the values from one towards updating
the other. This means we can use lambda with np.vectorize again, we
copendatatorisotawa.calmage-shadng-witropency and-aumpy/ m2so7r020 Image shading with OpenCV and Numpy
‘Open Data Stories Ottawa Share this SP
brighten_gradient = lambda x, y: min(255, x + (x * (y/100)))
The last thing we need to figure out is the creation of our percentage
matrix. Luckily, numpy still has us covered.
First, we can create our incremental percentages with the function
MGrid. This function takes in a low number, a high number, and an.
increment value, and then increments between the two (the top
value is exclusive, while the bottom is inclusive).
new grid = np-mgrid[20:101:20]
Initial Grid
[ 20 40 60 80 100]
Now, we need to consider how we will use this array of numbers. If
we repeat the same array downwards, the gradient will move from
left-to-right. If we turn the array into a column, and repeat it to the
side, we will have a set of percentages changing from top-to-bottom.
To repeat this grid downwards, and create the left-right gradient, we
can use np.stack. This function takes in a tuple of arrays to stack, so
we will create a tuple with our array repeated n times, and pass it to
stack.
# to create vertical columns of the same numbers, we can stack the above grid
arid list = 11
for i in range(3)
arid_list.append (new_gria)
grid_tu = tuple(grid list) # tuple is required submission for np.stack
stack_grid = np.stack (grid_tu)
‘opendiatastriesotawa.calimage-shading-aith-opencv-and-numpy! anaso7r020 Image shading with OpenCV and Numpy
‘Open Data Stories Ottawa Share this