I would like to implement some white balance algorithms from wiki
http://en.wikipedia.org/wiki/Color_balance
They are just some simple matrix manipulation
Do openCV offer any functions to do some multiplication
on a group of pixels like following?
example, 2 x 2, 3 channels Mat A =
0 0 0 1 1 1
2 2 2 3 3 3
3 x 3, 1 channels Mat B =
1 0 0
0 2 0
0 0 3
A x B = C and C =
0 0 0 1 2 3
2 4 6 3 6 9
I have wrote some generic functions to deal with pixel transformation
but I would prefer the build in function of openCV if it exist since the
functions of openCV may do some optimization
template<typename T, typename UnaryFunctor>
void transform_channel(cv::Mat &src, int channel, UnaryFunctor functor)
{
int const channels = src.channels();
if(channels == 1 && src.isContinuous()){
return transform_continuous_channel<T>(src, functor);
}
for(int row = 0; row != src.rows; ++row)
{
auto dst_ptr = get_pointer<T>(src, row, channel);
for(int col = 0; col != src.cols; ++col){
*dst_ptr = functor(*dst_ptr);
dst_ptr += channels;
}
}
}
You will notice that color-balance operations consist only of diagonal matrices, which corresponds to an element-wise multiplication by a scalar. Thus, the transform in your example would be:
image = image.mul(cv::Scalar(1,2,3));
for a 3-channel image. I do not know of a function to apply arbitrary pixel-wise matrix transformations.
Matrix multiplication is implementend in OpenCV with the * operator.
If you want to make it work though, you should reshape your RGB images into 1-channel matrices using cv::Mat::reshape() (documentation here).
Hint: cv::Mat::reshape() returns a reference to the new matrix without copying the data (unnecessary and slow). Hence, it is usually a good idea to use it like this:
cv::Mat someMatrix;
someMatrix = someMatrix.reshape(1);
Or this way (using another matrix variable):
cv::Mat rgbMatrix, myMatrix;
myMatrix = rgbMatrix.reshape(1);
Again, I emphasize that this does not copy the data, so you are not losing any memory.
Related
I would like to create my own nonlinear filter in OpenCV using C++, and if I see it correctly, I can use the FilterEngine class to do so. Unfortunately, I'm not really able to follow the documentation of this class. (Link: http://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html#filterengine).
Could someone be so kind to explain the class to me in a little bit more detail?
I'm grateful for every input and every example you can provide me with :-)
.
My specific needs:
1) I would like learn how to create my own nonlinear filters in general.
2) I would like to apply a rank-transform filter to my images:
Meaning: I have a kernel/region and I would like to flag every pixel inside that region with a one if the intensity-value of that (neighbourhood-) pixel is lower than the intensity of the center-pixel. Next, I want to use a simple convolution to save the sum of the transformed region, and store the value at the center-pixel. Let's look at a simple example:
100 120 200 rank-trans. 1 0 0 convolution
110 120 220 --> 1 0 0 --> 2
180 200 200 0 0 0
P.S: I know that I can archive the result of 2) by combining 255 threshold-operations with 255 box-filter operations, and then looping over every pixel and selecting the correct value. However, that seems quite inefficient to me ...
.
Code-Snipped [Edit]:
As I still struggle to understand the FilterEngine(), I started to write my own function for the above-descripted usecase. I would also be happy if you could comment on it to improve its efficiency, as it is quite slow at the moment. (~2sec. for a 1080x1920 image on one CPU-core).
void rankTransform(Mat& out, Mat in, int kernal_size, int borderType) {
// Issue warning if neccessary:
if (kernal_size >= 17) {
std::cout << "Warning, need to change Mat-type. Unsigned short only supports kernels up-to the size of 15x15" << std::endl << std::endl;
};
// First: Get borders around the image:
int border_size = (kernal_size - 1) / 2;
Mat in_incl_border = Mat(1080 + 2 * border_size, 1920 + 2 * border_size, in.depth());
copyMakeBorder(in, in_incl_border, border_size, border_size, border_size, border_size, borderType);
// Second: Loop through the image, conduct a rank transform and
// then sum over the kernel-size:
int start_pixel = 0 + (border_size + 1);
int end_pixel_width = 1920 + border_size;
int end_pixel_height = 1080 + border_size;
int i, j;
int x_1, x_2, y_1;
for (i = start_pixel; i < end_pixel_height; ++i) {
x_1 = i - border_size;
x_2 = i + border_size + 1;
for (j = start_pixel; j < end_pixel_width; ++j) {
y_1 = j - border_size;
out.at<unsigned short>(x_1-1, y_1-1) = static_cast<unsigned short>( (sum( in_incl_border(Range(x_1, x_2), Range(y_1, j + border_size + 1)) < in_incl_border.at<unsigned short>(i, j) )[0])/255 );
};
};
I just wanted to ask if someone could tell me the reason behind why my eig function computation time is different for the same size of matrices?
I am performing a lot of eig(A,B) operations on 4x4, 4x4 matrices to get eigenvalues and eigen vectors.
It happens 557 * 4 * 267 times.
std::pair<MatrixXcd, VectorXd> eig(const MatrixXcd& A, const MatrixXcd& B)
{
Eigen::GeneralizedSelfAdjointEigenSolver<MatrixXcd> solver(A, B);
MatrixXcd V = solver.eigenvectors();
VectorXd D = solver.eigenvalues();
return std::make_pair(V, D);
}
(...)
for (int t = 0; t < 557; t++)
{
(...)
for(int sig = 0; sig < 4; sig++)
{
for(int f = 0; f < 267; f++)
{
// calculation of Xi and Xfs
mRt = mXfs * mXfs.adjoint();
mRj = mXfi * mXfi.adjoint();
eValVec = eig(mRt, mRj);
(...)
}
(...)
}
}
For t<=7 eig computes 4 * 267 iterations in around 3 sec.
For t>7 it suddenly becomes really fast and computes 4 * 267 iterations in ~0.1 sec.
I checked for sure that its eig that slows my program by commenting other parts of code and leaving only that function. I always use 4x4 matrices.
I guess important notice might be that all values or Rj matrix in t<=7 equals 0. So its like:
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
While Rx has always values. After t>7 Rj also gain non zero values and computation becomes faster. So eig function might have problem to deal with zeros? I don't change anything related to eig function - only numbers in 4x4 matrices I insert to it changes. Still computation time differs. And this lag never happens after.
Do anyone have idea how could I fix it/debug it or make it more stable? I am doing processing in real time and 3 sec is quite too long for me.
In MATLAB, you can create a binary matrix B by thresholding a matrix A as follows:
B = A > threshold
Where threshold is some value. In Eigen for C++, I have been able see similar results, but have faced an inability to assign the output. That is, given
MatrixXd M =
0 1 2
0 1 2
0 1 2
(I know that's not proper initialization but for the sake of the question, go with it)
cout << (M < 1)
produces
1 0 0
1 0 0
1 0 0
but
MatrixXd N = M < 1;
and
M = M < 1;
both give build errors.
Can someone please explain the correct way to save the binary output of this threshold to a variable?
operator< is defined only in the array world, so you have to use .array() to see your MatrixXd as an ArrayXXd (no copy here), and then the result is a array of boolean, so if you want double, then you have to cast explicitly:
MatrixXd M(3,3);
M << 0, 1, 2,
0, 1, 2,
0, 1, 2;
MatrixXb Rb = (M.array() < 0.5); // result as a matrix of bool
MatrixXd Rd = (M.array() < 0.5).cast<double>(); // result as a matrix of double
I cannot reproduce your results using std::cout << (M < 1) and also cannot find this documented anywhere.
You can create a new matrix from an existing one by applying a unary function to each element by using the unaryExpr member function. Using C++11 lambda expressions, this becomes really straight forward.
#include <iostream>
#include <Eigen/Dense>
int
main()
{
Eigen::MatrixXd m1(4, 3);
m1.setRandom();
Eigen::MatrixXd m2 = m1.unaryExpr([](double d){ return d < 0.5; });
std::cout << m1 << "\n\n" << m2 << "\n";
}
Possible output:
0.680375 0.823295 -0.444451
-0.211234 -0.604897 0.10794
0.566198 -0.329554 -0.0452059
0.59688 0.536459 0.257742
0 0 1
1 1 1
0 1 1
0 0 1
Not that I know exactly why you would like to have the results of a boolean operation stored in a real matrix, but you can certainly do it. Also, you should generally avoid to explicitly convert the result of a matrix expression to a MatrixXd (or any other explicit type) since every time you do that, you set a cut in Eigen's powerful expression template chaining. In C++11, use auto a lot unless you really need eager evaluation / type conversion.
In Matlab, this function blkdiag construct block diagonal matrix. For example, if I have
a = [ 2, 2;
2, 2]
Then blkdiag(a,a) will return this output
>> blkdiag(a,a)
ans =
2 2 0 0
2 2 0 0
0 0 2 2
0 0 2 2
Is there an alternative in Eigen Library for blkdiag? The size of the big matrix varies which means classical approaches won't work. I mean to directly construct a matrix like the aforementioned output.
A simple function like
MatrixXd blkdiag(const MatrixXd& a, int count)
{
MatrixXd bdm = MatrixXd::Zero(a.rows() * count, a.cols() * count);
for (int i = 0; i < count; ++i)
{
bdm.block(i * a.rows(), i * a.cols(), a.rows(), a.cols()) = a;
}
return bdm;
}
does the job.
If the argument sub-matrix a can be fixed-size or dynamic-size or an expression then the following is a better choice
template <typename Derived>
MatrixXd blkdiag(const MatrixBase<Derived>& a, int count)
{
MatrixXd bdm = MatrixXd::Zero(a.rows() * count, a.cols() * count);
for (int i = 0; i < count; ++i)
{
bdm.block(i * a.rows(), i * a.cols(), a.rows(), a.cols()) = a;
}
return bdm;
}
Your problem is already solved! Just see the eigen documentation for topleftcorner and bottomrightcorner in http://eigen.tuxfamily.org/dox/classEigen_1_1DenseBase.html#a6f5fc5fe9d3fb70e62d4a9b1795704a8 and http://eigen.tuxfamily.org/dox/classEigen_1_1DenseBase.html#a2b9618f3c9eb4d4c9813ae8f6a8e70c5 respectively.
All you have to do is assign a matrix to those places, more or less like this:
//Assuming A is the result and has the right size allocated with zeroes, and a is the matrix you have.
A.topLeftCorner(a.rows(),a.cols())=a;
same for bottom right corner, unless you want to flip matrix (try methods .reverse() and .transpose() to get the desired flip effect) a before copying it there.
You can also try the .block() function for better handling of the matrices.
This may be simple, but definetly I couldn't find an efficient answer, sorry ...
Lets say that I have a matrix A, and I want to copy its first column several times into the matrix B; ie;
A = [1 2 3; 2 3 4; 5 6 7]
and I want to extract
A(:,1);
and copy this vector into another matrix, B. thus leading us to
B = [1 2 3; 1 2 3; 1 2 3];
after the next loop, then, B will be:
B = [2 3 4; 2 3 4; 2 3 4];
and so on until I get sequentially all the A's columns in matrix B
Is there a practical solution for this in opencv? i've tried with copyTo(), Range, and row, col, but I get nothing. I'll really appreciate your help.
regards;
jenn.
Simply use Mat::row to access each row of your Matrix in a loop and use Mat::copyTo to copy selected row to new Mat
See example
Mat A=(Mat_<uchar>(3,3)<< 1,2,3,\
2,3,4,\
5,6,7);
Mat B(A.rows,A.cols,CV_8UC1);
for(int i=0;i<A.rows;i++) {
for(int j=0;j<A.rows;j++){
A.row(i).copyTo(B.row(j));
}
cout<<B<<endl;
}
You can do this using Mat::push_back as well.
See example
Mat A=(Mat_<uchar>(3,3)<< 1,2,3,\
2,3,4,\
5,6,7);
for(int i=0;i<A.rows;i++) {
Mat B;
for(int j=0;j<A.rows;j++){
B.push_back(A.row(i));
}
cout<<B<<endl;
}