Take off pads with OpenCV - c++

I have to translate from Matlab to C this code:
% take off the pads
x = (1 + padSize) : (rows - pad8Size);
y = (1 + padSize) : (cols - padSize);
rpad=rpad(x,y);
1st and 2nd create 2 array, but I don t know how I have to delete it from rpad Mat object It can be something like(subtract every element)
for(int i=1+pad;i<=rows-pad;i++){
for(int j=1+pad;i<=cols-pad;j++){
subtract(rpad,x,rpad);
subtract(rpad,y,rpad);}}
Or something like(delete the external element)
int a=(rows-pad)-(1+pad);
int b=(cols-pad)-(1+pad);
rpad.create(img.rows - a,img.cols - b,original.type());
img.copyTo(rpad);

Try
cv::Rect roi(padSize, padSize, rpad.cols-2*padSize, rpad.rows-2*padSize);
cv::Mat result = rpad(roi);
And depending on whether you want continuous memory, you can choose to directly use result (discontinuous, usually okay for most OpenCV functions) or copy it to back to rpad (continuous)

Is it possible to multiply a Mat object with a bidimensional array? Imfft is obviously the Mat object
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
imfft=imfft*filter[i][j]
}
}

Related

how to covert Y,U,V buffer to one-dimensional array

I'm trying to convert an hls file to jpeg. firstly, I used openh264 to convert HLS file to YUV. I got a two dimensional array containing Y, U, V buffer (*pData[3]). After that, I try to combine the three arrays into one to pass it to CompressYUYV2JPEG.
here is how I convert:
for(i = 0; i < l; i++) {
inbuf.push_back(yuvData[0][i]);
}
l = bufferInfo.UsrData.sSystemBuffer.iWidth*bufferInfo.UsrData.sSystemBuffer.iHeight/4;
for(i = 0; i < l; i++) {
inbuf.push_back(yuvData[1][i]);
}
l = bufferInfo.UsrData.sSystemBuffer.iWidth*bufferInfo.UsrData.sSystemBuffer.iHeight/4;
for(i = 0; i < l; i++) {
inbuf.push_back(yuvData[2][i]);
}
but unfortunately, It doesn't produce the expected result. What is the proper way to convert 2-dimensional YUV array into a one-dimensional array?
You need YUV422. That means YUYV. inbuf must be dividable by 4 for every input data. You can use
for(i = 0; i < l/2; i++) {
inbuf.push_back(yuvData[0][2*i]);
inbuf.push_back((yuvData[1][2*i] + yuvData[1][2*i + 1])/2);
inbuf.push_back(yuvData[0][2*i + 1]);
inbuf.push_back((yuvData[2][2*i] + yuvData[2][2*i + 1])/2);
}
In this code snippet all Y values are used but only the average of two Cr resp. Cb values are used. Of course the number of elements in each yuvData channel must be even. Otherwise you have to find a solution for the last element.
I just now saw that you use YUV420. Then you can use this snippet
for(i = 0; i < l/2; i++) {
inbuf.push_back(yuvData[0][2*i]);
inbuf.push_back(yuvData[1][i/2]);
inbuf.push_back(yuvData[0][2*i + 1]);
inbuf.push_back(yuvData[2][i/2]);
}
In this code all Y values are used once and all Cr resp. Cb values are used twice.

return value of mxGetPr() -- equivalent looping

I am trying to implement a mexFunction() into "pure" C++ (OpenCV), but the returned value by mxGetPr() is not clear at all for me.
The following code is aimed to be implemented:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int *D = new int[N*L];
// where N and L are dimensions (cols and rows) of matrix prhs[3]
// prhs[3] is a NxL matrix containing floating point value
for (int i=0; i<N*L; i++)
D[i] = mxGetPr(prhs[3])[i];
}
My question is, what kind of value is given by mxGetPr(prhs[3])[i] and mxGetPr(prhs[4])[i]? And how is it looping through matrix?
I tried to do something like this:
for (int i=0; i<l; i++)
{
for(int j=0; j<n; j++)
{
D[iCounter] = (int)d.at<uchar>(i,j);
iCounter++;
}
}
Looping through d matrix which is the same as input value prhs[3], but apparently it is not correct.
I guess the order/type of the returned value is not the same as in the original mexFunction.
EDIT
Now I have cv::Mat d; instead of prhs[3] and try to do the same as in mexfunction.
int *D = new int[N*L];
int iCounter = 0;
for (int i=0; i<L; i++)
{
for(int j=0; j<N; j++)
{
D[iCounter] = (int)d.at<uchar>(i,j);
iCounter++;
}
}
But here (int)d.at(i,j) returns value of the "d" matrix...where in the roiginal code a pointer was returned by mxGetPr().
mxGetPr returns a pointer of type double so you can access your data using pointer arithmetic. Also, you must remember that the pointer returned to you has the data in column-major order. This means that you must traverse your data row-wise instead of column-wise like in traditional C order.
In column-major order, you access location (i, j) with the following linear index:
j * rows + i
rows is the number of rows in your matrix, with i and j being the row and column you want to access. In row-major or C order, the way you access data is:
i * cols + j
Here cols is the number of columns in your matrix. I'm assuming you want to lay out your data in row-major format rather than column major. Therefore if you want to loop through the data using two for loops, do something like this:
double *ptr = mxGetPr(prhs[3]);
// A L x N matrix - L rows, N columns
for (int i = 0; i < L; i++)
{
for (int j = 0; j < N; j++)
{
D[i * N + j] = (int) ptr[j * L + i];
}
}
Here D is a pointer pointing to integer data. You have to cast the data in order to do this as the pointer to the data from MATLAB is already double. It's nasty but that's what you have to do. You can use D in row-major order so it's compatible with the rest of your code. I'm assuming that you are using MATLAB MEX as way of making pre-written C++ code to be interfaced with MATLAB.

Access 2D array with 1D iteration

If I define an array as follows:
int rows = 10;
int cols = 10;
double **mat;
mat = new double*[rows];
mat[0] = new double[rows*cols];
for(int r=1; r<10; r++)
mat[r] = &(mat[0][r*cols]);
How do I iterate over this array via 1-dimension?
E.g. I'd like to do the following:
mat[10] = 1;
to achieve the same thing as
mat[1][0] = 1;
Is there a way to dereference the double** array to do this?
With your definition of mat, you can do this:
double* v = mat[0]; 'use v a uni-dimensional vector
for(int i =0; i< rows* cols; i++) v[i] = 1;
Alternatively,if what you wanted was to define mat itself as a uni-dimensional vector and use it as bi-dimensional in a tricky way:
double mat[rows * cols];
#define MAT(i, j) mat[i*cols + j]
MAT(1, 0) = 1;
<=>
mat[10] = 1
now you have the options to span the matrix in one-dimension using mat or bi-dimension using the MAT macro
mat[row * cols + column]
where row is the row you want to access and column is the column you want to access.
Of course an iteration over the array would just involve some kind of loop (best suited would be for) and just applying the pattern every time.

Speeding up access to a array with pointers in C++

I am trying to make a fast image threshold function. Currently what I do is:
void threshold(const cv::Mat &input, cv::Mat &output, uchar threshold) {
int rows = input.rows;
int cols = input.cols;
// cv::Mat for result
output.create(rows, cols, CV_8U);
if(input.isContinuous()) { //we have to make sure that we are dealing with a continues memory chunk
const uchar* p;
for (int r = 0; r < rows; ++r) {
p = input.ptr<uchar>(r);
for (int c = 0; c < cols; ++c) {
if(p[c] >= threshold)
//how to access output faster??
output.at<uchar>(r,c) = 255;
else
output.at<uchar>(r,c) = 0;
}
}
}
}
I know that the at() function is quite slow. How can I set the output faster, or in other words how to relate the pointer which I get from the input to the output?
You are thinking of at as the C++ standard library documents it for a few containers, performing a range check and throwing if out of bounds, however this is not the standard library but OpenCV.
According to the cv::Mat::at documentation:
The template methods return a reference to the specified array element. For the sake of higher performance, the index range checks are only performed in the Debug configuration.
So there's no range check as you may be thinking.
Comparing both cv::Mat::at and cv::Mat::ptr in the source code we can see they are almost identical.
So cv::Mat::ptr<>(row) is as expensive as
return (_Tp*)(data + step.p[0] * y);
While cv::Mat::at<>(row, column) is as expensive as:
return ((_Tp*)(data + step.p[0] * i0))[i1];
You might want to take cv::Mat::ptr directly instead of calling cv::Mat::at every column to avoid further repetition of the data + step.p[0] * i0 operation, doing [i1] by yourself.
So you would do:
/* output.create and stuff */
const uchar* p, o;
for (int r = 0; r < rows; ++r) {
p = input.ptr<uchar>(r);
o = output.ptr<uchar>(r); // <-----
for (int c = 0; c < cols; ++c) {
if(p[c] >= threshold)
o[c] = 255;
else
o[c] = 0;
}
}
As a side note you don't and shouldn't check for cv::Mat::isContinuous here, the gaps are from one row to another, you are taking pointers to a single row, so you don't need to deal with the matrix gaps.

Store a cv::Mat in a byte array for data transfer to a server

I need to read an image with OpenCV, get its size and send it to a server so it processes the image and give it back to me the extracted features.
I have been thinking of using a vector<byte>, but I don't understand how to copy the data to a cv::Mat. I wan't it to be fast so I am trying to access the data with a pointer but I have a runtime exception. I have something like this.
Mat image = imread((path + "name.jpg"), 0);
vector<byte> v_char;
for(int i = 0; i < image.rows; i++)
{
for(int j = 0; j < image.cols; j++)
{
v_char.push_back(*(uchar*)(image.data+ i + j));
}
}
Which is the best approach for this task?
Direct access is a good idea as it is the fastest for OpenCV, but you are missing the step and that is probably the reason why your program breaks. The next line is wrong:
v_char.push_back(*(uchar*)(image.data+ i + j));
You don't have to increment i, you have to increment i + image.step. It will be this way:
Mat image = imread((path + "name.jpg"), 0);
vector<byte> v_char;
for(int i = 0; i < image.rows; i++)
{
for(int j = 0; j < image.cols; j++)
{
v_char.push_back(*(uchar*)(image.data+ i*image.step + j));
}
}
You have received great answers so far, but this is not your main problem. What you probably want to do before sending an image to a server is to compress it.
So, take a look at cv::imencode() on how to compress it, and cv::imdecode() to transform it back to an OpenCV matrix in the server. just push the imencode ouptut to a socket and you're done.
Improving on Jav_Rock's answer here's how I would do it.
Mat image = ...;
vector<byte> v_char(image.rows * image.cols);
for (int i = 0; i < image.rows; i++)
memcpy(&v_char[i * image.cols], image.data + i * image.step, image.cols);
EDIT: Initialization by constructor will allocate enough space to avoid extra reallocation, but it will also set all items in the vector to default value (0). The following code avoids this extra initialization.
Mat image = ...;
vector<byte> v_char;
v_char.reserve(image.rows * image.cols);
for (int i = 0; i < image.rows; i++)
{
int segment_start = image.data + i * image.step;
v_char.insert(v_char.end(), segment_start, segment_start + image.cols);
}
I don't understand completely why you need to use a vector, but if it's really necessary I recommend you to do a simple memcpy:
vector<byte> v_char(image.width * image.height); //Allocating the vector with the same size of the matrix
memcpy(v_char.data(), image.data, v_char.size() * sizeof(byte));