OpenCV construct range of size 1 - c++

In the following code, is there a better way to go about constructing the singleton ranges cv::Range(i, i+1) and cv::Range(j, j+1)? I would expect there to exist somewhere in OpenCV a function that creates a singleton range, e.g. just a constructor cv::Range(i) equivalent to cv::Range(i, i+1).
const int sizeA[] = { 100, 100, 100 };
cv::Mat matrix(3, sizeA, cv::DataType<int>::type);
// get submatrix (i, j, :)
int i = 8;
int j = 15;
const cv::Range ranges = { cv::Range(i, i+1), cv::Range(j, j+1), cv::Range::all() };
cv::Mat submatrix = matrix(ranges);

There is nothing built into OpenCV to do this. Simply write cv::Range(i, i+1) everywhere or write your own helper function.

Related

Copy only row indices of Mat from findNonZero function in C++ OpenCV

I am trying to convert MATLAB code to C++.
In MATLAB, I use the find function to get the indices of a vector and then copy these to other variables. For example:
idx = find(A>s);
B = idx;
% A, idx, and B are vectors; s is a scalar
In C++ OpenCV (C++14 / OpenCV 3.4.10) I know I can use the findNonZero function, but it returns both row and column indices:
double s;
Mat1d A;
Mat1i B;
Mat idx;
.
.
.
findNonZero(A>s, idx);
I do not know how I can copy only row-indices directly (without using a for loop). I thought it could be done by defining Mat2i idx and using mixChannels like this:
Mat2i idx;
findNonZero(A>s, idx);
B = Mat1i::zeros(idx.size());
int from_to[] = {1, 0};
mixChannels(&idx, 1, &B, 1, from_to, 1);
However, I get the following error while running the findNonZero function:
OpenCV(3.4.10) Error: Assertion failed (!fixedType() || ((Mat*)obj)->type() == mtype) in cv::debug_build_guard::_OutputArray::create,
But if I set Mat idx, I get another error while running the mixChannel function:
OpenCV(3.4.10) Error: Assertion failed (j < nsrcs && src[j].depth() == depth) in cv::mixChannels,
I'm not sure what I should do. Any help is appreciated.
MATLAB's find determines the column-major indices of where values are nonzero in the input matrix. This is true if you specify the single output version of it. If you provide two output variables, that generates both the row and column locations of the nonzero values in the input. In your example you have provided the single output version of find so I will be working with this.
OpenCV's cv::Mat lays out the image in row-major. I'm assuming you would like the row-major indices. If so, since cv::findNonZero outputs both the row and column coordinates, you must loop through the output coordinates yourself and create the row-major indices. You shouldn't be afraid of using loops here. In fact, for loops over cv::Mats are optimised for quick access. Therefore:
Mat2i idx;
Mat1d A; // Define somewhere else
double s; // Define somewhere else
findNonZero(A > s, idx);
B = Mat1i::zeros(idx.total());
for (int i = 0; i < idx.total(); ++i) {
B.at<int>(i) = idx.at<Point>(i).y * A.cols + idx.at<Point>(i).x;
}
B will contain the row-major indices in a cv::Mat1i. If I have misunderstood your inquiry and simply want the row locations of the nonzero values, then it's just:
Mat2i idx;
Mat1d A; // Define somewhere else
double s; // Define somewhere else
findNonZero(A > s, idx);
B = Mat1i::zeros(idx.total());
for (int i = 0; i < idx.total(); ++i) {
B.at<int>(i) = idx.at<Point>(i).y;
}
Remember you are only iterating over the nonzero values, so the worst case complexity is to iterate over the locations that are nonzero.

Eigen: Efficient way of referencing ArrayWrapper

I am interfacing some code with raw pointers. So I have extensive use of the map class:
void foo(T* raw_pointer){
const int rows = ...;
const int cols = ...;
Map<Matrix<T, rows, cols>> mat(raw_pointer);
// DO some stuff with "mat"
}
Now I want to apply some cwise operations in foo, which I accomplish using .array(). The code works, however, it looks very messy due to all of the .array() calls strewn in the function. For instance, for the sake of argument, let's suppose that the function looked like this:
void foo(T* raw_pointer){
const int rows = ...;
const int cols = ...;
Map<Matrix<T, rows, cols>> mat(raw_pointer);
for (int i = 0 ; i < 1000 ; ++i)
... something = i * mat.row(1).array() * sin(mat.row(4).array()) + mat.col(1).array();
}
Part of the problem with this is that it is very unclear what the code is actually doing. It would be much nicer if gave the variables names:
void foo(T* raw_pointer){
const int rows = ...;
const int cols = ...;
Map<Matrix<T, rows, cols>> mat(raw_pointer);
Matrix<T, 1, cols> thrust = mat.row(1);
Matrix<T, 1, cols> psi = mat.row(4);
Matrix<T, 1, cols> bias = mat.row(2);
for (int i = 0 ; i < 1000 ; ++i)
... something = i * thrust.array() * sin(psi.array()) + bias.array();
}
But it would be even nicer if I could get directly get a reference to the ArrayWrappers so that we aren't making any copies. However, the only way I can figure out how to get that to work is by using auto:
void foo(T* raw_pointer){
const int rows = ...;
const int cols = ...;
Map<Matrix<T, rows, cols>> mat(raw_pointer);
auto thrust = mat.row(1).array();
auto psi = mat.row(4).array();
auto bias = mat.row(2).array();
for (int i = 0 ; i < 1000 ; ++i)
... something = i * thrust * sin(psi) + bias;
}
This code works, and upon testing appears to reference the entries in the pointer (as opposed to making copies like in the previous snippet). However,
I am concerned about its efficiency since the Eigen documentation explicitly suggests NOT doing this. So could somebody please what the preferred way to define the types for the variables is in such a circumstance?
It seems to me like I should be using a Ref here, but I can't figure out how to get that to work. Specifically, I have tried replacing auto with
Eigen::Ref<Eigen::Array<T, 1, cols>>
and
Eigen::Ref<Eigen::ArrayWrapper<Eigen::Matrix<T, 1, cols>>>
but the compiler doesn't like either of those.
To avoid having to write array() every time you use the Map<Eigen::Matrix... you can use a Map<Eigen::Array... instead/in addition. This will use the default element-wise operators instead of the matrix operators. To use a matrix operator instead, you can use map.matrix() (similar to what you have in your post mat.array()).
auto thrust = [](auto&&mat){return mat.row(1).array();};
auto psi = [](auto&&mat){return mat.row(4).array();};
auto bias = [](auto&&mat){return mat.row(2).array();};
for (int i = 0 ; i < 1000 ; ++i)
... something = i * thrust(mat) * sin(psi(mat)) + bias(mat)
has names. And the array wrappers don't persist.

Faster way to pick up the blob at a given point

I am trying to create an equivalent function for matlab's bwselect. So, I want to display the blob (which contains the points I will provide) and mask the rest.
Here's what I have tried.
cv::Mat bwselect(cv::Mat matImg, int x, int y)
{
cv::Mat img_labels, stats, centroids, mask;
if (matImg.data)
{
int numOfLables = connectedComponentsWithStats(matImg, img_labels, stats, centroids, 8, CV_32S);
if (numOfLables > 1)
{
for (int i = 1; i < numOfLables; i++)
{
mask = cv::Mat::zeros(img_labels.size(), CV_8UC1);
mask = mask | (img_labels == i);
if (mask.at<uchar>(y, x) > 0)
{
break;
}
}
}
}
return mask;
}
It does the job. But it's slow. Is there any faster and efficient way to do this?
If the input image is large and if it contains many objects, then the bottleneck could arise because you are allocating/deallocating a large mask buffer a lot of times.
Furthermore, if you call this function lots of times, it would be wise to call connectedComponentsWithStats only once and then use its results as additional input for your function.
I would suggest that you replace this entire loop
for (int i = 1; i < numOfLabels; i++){/*...*/}
with this
// img_labels data type is CV_32S
int label_at_pos = img_labels.at<int>(y, x);
if (label_at_pos > 0)
{
// create mask here and return it
}
EDIT: I made a correction to my code sample above. The connectedComponentsWithStats computes labels image that contains integer values by default.

OpenCV cv::Mat "+="inside for loop

I'm working on a simple ghost-trail effect in C++. I am adding cv::Mat images into a std::vector, I have a function that can access the images, change opacity & add two together, which works:
void ghostEffect(std::vector<cv::Mat> &srcImages, cv::Mat &dstImage)
{
static int currFrame = 0;
dstImage = srcImages[currFrame%srcImages.size]*0.5+srcImages[(currFrame+1)%srcImages.size]*0.5;
currFrame++;
}
I would like to use a for() loop to iterate over many images in the vector, however when I do I get a seg fault. Wondering what I am doing wrong?
void ghostEffect(std::vector<cv::Mat> &srcImages, cv::Mat &dstImage)
{
static int currFrame = 0;
for (int i = 0; i < srcImages.size; i++)
{
dstImage += srcImages[(currFrame+i)%srcImages.size]*(1/srcImages.size);
}
currFrame++;
}
The code snippet is strange. It should not be compiled. std::vector::size is a method, thus your loop compares i with the address of the method std::vector::size, which may be much bigger than the vector size.
Also result of the expression 1/srcImages.size() is always zero if the vector size is greater then 1, since arguments of int type produces int type.
I suppose you have to code the function like bellow:
void ghostEffect(std::vector<cv::Mat> &srcImages, cv::Mat &dstImage)
{
static int currFrame = 0;
for (int i = 0; i < srcImages.size(); i++)
{
dstImage += srcImages[(currFrame+i)%srcImages.size()]*(1.0/srcImages.size());
}
currFrame++;
}
The first snippet is working by a lucky coincidence until currFrame exceeds the vector size. Replace srcImages.size with srcImages.size() too.

Need a faster way to convert a cv::Mat into 1 dimensional vector form

I have a for loop the takes an OpenCV Mat object of n x n dimensions, and returns a Mat object of n^2 x 1 dimensions. It works, but when I time the method it takes between 1 and 2 milliseconds. Since I am calling this method 3 or 4 million times its taking my program about an hour to run. A research paper I'm referencing suggests the author was able to produce a program with the same function that ran in only a few minutes, without running any threads in parallel. After timing each section of code, the only portion taking >1 ms is the following method.
static Mat mat2vec(Mat mat)
{
Mat toReturn = Mat(mat.rows*mat.cols, 1, mat.type());
float* matPt;
float* retPt;
for (int i = 0; i < mat.rows; i++) //rows
{
matPt = mat.ptr<float>(i);
for (int j = 0; j < mat.row(i).cols; j++) //col
{
retPt = toReturn.ptr<float>(i*mat.cols + j);
retPt[0] = matPt[j];
}
}
return toReturn;
}
Is there any way that I can increase the speed at which this method converts an n x n matrix into an n^2 x 1 matrix (or cv::Mat representing a vector)?
that solved most of the problem #berak, its running a lot faster now. however in some cases like below, the mat is not continuous. Any idea of how I can get an ROI in a continuous mat?
my method not looks like this:
static Mat mat2vec(Mat mat)
{
if ( ! mat.isContinuous() )
{
mat = mat.clone();
}
return mat.reshape(1,2500);
}
Problems occur at:
Mat patch = Mat(inputSource, Rect((inputPoint.x - (patchSize / 2)), (inputPoint.y - (patchSize / 2)), patchSize, patchSize));
Mat puVec = mat2vec(patch);
assuming that the data in your Mat is continuous, Mat::reshape() for the win.
and it's almost for free. only rows/cols get adjusted, no memory moved. i.e, mat = mat.reshape(1,1) would make a 1d float array of it.
Seeing this in OpenCV 3.2, but the function is now mat.reshape(1).