Using the Mat type carelessly might lead your project to take a noticeable performance hit.





    Due to the nature of how the OpenCV Java works (and Java itself), the overuse of some functions could be pretty impactful.

 

Explaining

    Here, I’ll talk about the .get() function from the Mat class. With it, after an image is loaded as a Mat object, it is possible to access each pixel individually by using Image.get(row,col); (there’s also a set equivalent, called Image.put(row,col,PixelValue); )

    I have been using the get  and put  functions for ages, and never noticed any performance changes… until I needed to access every single pixel on an image individually, multiple times. The increase in time I experienced was terrible, even considering that accessing all image pixels can be a costly operation (sometimes O(N^2).

 

Evaluating

On one of my attempts to address the performance issue, I converted the image into a primitive three-dimensional array, performed all the operations, and then converted it back to a Mat . To my surprise (or perhaps not so surprising), the performance improved considerably!

To make things more precise, I decided to quantify how much time this “conversion” approach could reduce.

 

The approach

  I coded a program to do the following steps:

  • Load an image;
  • Use OpenCV Mat.get  on all of its pixels;
  • Calculate the total time spent;
  • Convert the Mat   image to array;
  • Iterate throughout all the pixels, including channels;
  • Calculate the total time spent;
  • Iterate throughout all the pixels, excluding channels;
  • Calculate the total time spent;
  • Test Mat.put.

    The results for two images (both available here) one with 3840x2160x3 and 10109x4542x3 are in Figure 1.

 

OpenCV image evaluation, test 1

OpenCV image evaluation, test 2

Figure 1 – Outputs of the script with 2 different images.

 

    To do the comparison on Mat.get() , (presented as “[MAT.GET]” in Figure 1) I considered the “[NO CHANNEL/AS ARRAY]” value, because both methods do not go through all channels, they just return an array with the BGR values, and… there is a ~74% time decrease.

 

Ok… should I stop using Mat.get?

    Each case is different,  however, there is no way to be exempt from the numerical conclusions. If your goal is performance, my advice is to always avoid using repeated Mat.get() calls. If it is strictly necessary, convert to a three-dimensional vector. And remember to always consider the time spent on the conversion of your codebase.

 

 

 

Liked this post? There are others performance analysis here like this one with the UMat class!

 

Project Github Link

How to use OpenCV Java using Eclipse

 

 

 

Have fun with your projects! 
If this post helped you, please consider buying me a coffee 🙂