Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to apply color matrix to RGB image using OpenCV 3.0?

I have a color image represented as an OpenCV Mat object (C++, image type CV_32FC3). I have a color correction matrix that I want to apply to each pixel of the RGB color image (or BGR using OpenCV convention, doesn't matter here). The color correction matrix is 3x3.

I could easily iterate over the pixels and create a vector v (3x1) representing RGB, and then compute M*v, but this would be too slow for my real-time video application.

The cv::cvtColor function is fast, but does not seem to allow for custom color transformations. http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#cvtcolor

Similar to the following, but I am using OpenCV for C++, not Python. Apply transformation matrix to pixels in OpenCV image

like image 859
chloelle Avatar asked Feb 03 '16 02:02

chloelle


Video Answer


2 Answers

Here's the code that worked using cv::reshape. It was fast enough for my application:

#define WIDTH 2048
#define HEIGHT 2048
...

Mat orig_img = Mat(HEIGHT, WIDTH, CV_32FC3);
//put some data in orig_img somehow ...

/*The color matrix
Red:RGB; Green:RGB; Blue:RGB
1.8786   -0.8786    0.0061
-0.2277    1.5779   -0.3313
0.0393   -0.6964    1.6321
*/

float m[3][3] = {{1.6321, -0.6964, 0.0393},
                {-0.3313, 1.5779, -0.2277}, 
                {0.0061, -0.8786, 1.8786 }};
Mat M = Mat(3, 3, CV_32FC1, m).t();

Mat orig_img_linear = orig_img.reshape(1, HEIGHT*WIDTH);
Mat color_matrixed_linear = orig_img_linear*M;
Mat final_color_matrixed = color_matrixed_linear.reshape(3, HEIGHT);

A few things to note from the above: The color matrix in the comment block is the one I would ordinarily apply to an RGB image. In defining the float array m, I switched rows 1 and 3, and columns 1 and 3 for OpenCV's BGR ordering. The color matrix also must be transposed. Usually a color matrix is applied as M* v = v_new, where M is 3x3 and v is 3x1 but here we are doing vT *MT = v_newT to avoid having to transpose each 3-channel pixel.

like image 105
chloelle Avatar answered Oct 06 '22 09:10

chloelle


Basically the linked answer uses reshape to convert your CV_32FC3 mat of size m x n to a CV_32F mat of size (mn) x 3. After that, each row of the matrix contains exactly color channels of one pixel. You can then apply usual matrix multiplication to obtain a new mat and reshape it back to the original shape with three channels.

Note: It may be worth noticing that the default color space of opencv is BGR, not RGB.

like image 20
Quang Hoang Avatar answered Oct 06 '22 10:10

Quang Hoang