OpenCV changing Mat inside a function (Mat scope) - opencv

I am passing a Mat to another function and changing it inside the called function. I had expected that being a more complex type it was automatically passed by reference so that the matrix would have changed in the calling function, but it doesn't. Could someone point me at the explanation of how to correctly return a changed Mat from a function?
Here's the code snippet:
void callingFunction(Mat img)
{
Mat tst(100,500,CV_8UC3, Scalar(0,255,0));
saveImg(tst, "Original image", true);
testImg(tst);
saveImg(tst, "Want it to be same as inside testImg but is same as Original", true);
}
void testImg(Mat img)
{
int rs = 50; // rows
int cs = 100; // columns
img = Mat(rs, cs, CV_8UC3, Scalar(255,0,0));
Mat roi(img, Rect(0, 0, cs, rs/2));
roi = Scalar(0,0,255); // change a subsection to a different color
saveImg(img, "inside testImg", true);
}
Thanks!

You have to define Mat as parameter-reference (&). Here's edited code:
void callingFunction(Mat& img)
{
Mat tst(100,500,CV_8UC3, Scalar(0,255,0));
saveImg(tst, "Original image", true);
testImg(tst);
saveImg(tst, "Want it to be same as inside testImg but is same as Original", true);
}
void testImg(Mat& img)
{
int rs = 50; // rows
int cs = 100; // columns
img = Mat(rs, cs, CV_8UC3, Scalar(255,0,0));
Mat roi(img, Rect(0, 0, cs, rs/2));
roi = Scalar(0,0,255); // change a subsection to a different color
saveImg(img, "inside testImg", true);
}

I wondered about the same question myself, so I would like to further clarify the answer given by #ArtemStorozhuk (which is correct).
The OpenCV documentation is misleading here, because it appears you're passing the matrix by value, but in fact the constructor of cv::OutputArray is defined as follows:
_OutputArray::_OutputArray(Mat& m)
so it gets the matrix by reference!
Since operations like cv::Mat::create create a new matrix, the operation releases the reference and set the couter to 1. Thus, in order to keep the result in the calling function, you have to pass the matrix by reference.

If its true that you have to explicitly pass by reference, then how do all the OpenCV functions work? None of them pass values by reference, yet they somehow seem to write to the passed in Mat just fine. For example, here is the declaration for the Sobel function in imgproc.hpp:
//! applies generalized Sobel operator to the image
CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth,
int dx, int dy, int ksize=3,
double scale=1, double delta=0,
int borderType=BORDER_DEFAULT );
as you can see, it passes in src and dst without a &. And yet I know that after I call the Sobel with an empty dst, it will end up filled. No '&' involved.

Related

Read cv::Mat pixel without knowing its pixel format

I am aware there are several ways to read and write a pixel value of an OpenCV cv::Mat image/matrix.
A common one is the .at<typename T>(int, int) method http://opencv.itseez.com/2.4/modules/core/doc/basic_structures.html#mat-at .
However, this requires the typename to be known, for instance .at<double>.
The same thing applies to more direct pointer access OpenCV get pixel channel value from Mat image .
How can I read a pixel value without knowing its type? For instance, it would be ok to receive a more generic CvScalar value in return. Efficiency is not an issue, as I would like to read rather small matrices.
Kind of. You can construct cv::Mat_ and provide explicit type for elements, after that you don't have to write element type each time. Quoting opencv2/core/mat.hpp
While Mat is sufficient in most cases, Mat_ can be more convenient if you use a lot of element
access operations and if you know matrix type at the compilation time. Note that
Mat::at(int y,int x) and Mat_::operator()(int y,int x) do absolutely the same
and run at the same speed, but the latter is certainly shorter.
Mat_ and Mat are very similar. Again quote from mat.hpp:
The class Mat_<_Tp> is a thin template wrapper on top of the Mat class. It does not have any
extra data fields. Nor this class nor Mat has any virtual methods. Thus, references or pointers to
these two classes can be freely but carefully converted one to another.
You can use it like this
Mat_<Vec3b> dummy(3,3);
dummy(1, 2)[0] = 10;
dummy(1, 2)[1] = 20;
dummy(1, 2)[2] = 30;
cout << dummy(1, 2) << endl;
Why I said 'kind of' in the first place? Because if you want to pass this Mat_ somewhere - you have to specify it's type. Like this:
void test(Mat_<Vec3b>& arr) {
arr(1, 2)[0] = 10;
arr(1, 2)[1] = 20;
arr(1, 2)[2] = 30;
cout << arr(1, 2) << endl;
}
...
Mat_<Vec3b> dummy(3,3);
test(dummy);
Technically, you are not specifying your type during a pixel read, but actually you still have to know it and cast the Mat to the appropriate type beforehand.
I guess you can find a way around this using some low-level hacks (for example make a method that reads Mat's type, calculates element size and stride, and then accesses raw data using pointer arithmetic and casting...). But I don't know any 'clean' way to do this using OpenCV's functionality.
If you already know the type, you can use Mat_<> type for easy access. If you don't know the type, you can:
convert the data to double, so data won't be truncated in any case
switch over the number of channels to access correctly the double matrix. Note that you can have at most of 4 channels, since Scalar has at most 4 elements.
The following code will convert only the selected element of the source matrix to a double value (with N channels).
You get a Scalar containing the value at position row, col in the source matrix.
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Scalar valueAt(const Mat& src, int row, int col)
{
Mat dst;;
src(Rect(col, row, 1, 1)).convertTo(dst, CV_64F);
switch (dst.channels())
{
case 1: return dst.at<double>(0);
case 2: return dst.at<Vec2d>(0);
case 3: return dst.at<Vec3d>(0);
case 4: return dst.at<Vec4d>(0);
}
return Scalar();
}
int main()
{
Mat m(3, 3, CV_32FC3); // You can use any type here
randu(m, Scalar(0, 0, 0, 0), Scalar(256, 256, 256, 256));
Scalar val = valueAt(m, 1, 2);
cout << val << endl;
return 0;
}

matchTemplate with openCV in java

i have a code like this:
Mat img = Highgui.imread(inFile);
Mat templ = Highgui.imread(templateFile);
int result_cols = img.cols() - templ.cols() + 1;
int result_rows = img.rows() - templ.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);
Imgproc.matchTemplate(img, templ, result, Imgproc.TM_CCOEFF);
/////Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
for (int i = 0; i < result_rows; i++)
for (int j = 0; j < result_cols; j++)
if(result.get(i, j)[0]>?)
//match!
I need to parse the input image to find multiple occurrencies of the template image. I want to have a result like this:
result[0][0]= 15%
result[0][1]= 17%
result[x][y]= 47%
If i use TM_COEFF all results are [-xxxxxxxx.xxx,+xxxxxxxx.xxx]
If i use TM_SQDIFF all results are xxxxxxxx.xxx
If i use TM_CCORR all results are xxxxxxxx.xxx
How can i detect a match or a mismatch? What is the right condition into the if?
If i normalized the matrix the application set a value to 1 and i can't detect if the template isn't stored into the image (all mismatch).
Thanks in advance
You can append "_NORMED" to the method names (For instance: CV_TM_COEFF_NORMED in C++; could be slightly different in Java) to get a sensible value for your purpose.
By 'sensible', I mean that you will get values in the range of 0 to 1 which can be multiplied by 100 for your purpose.
Note: For CV_TM_SQDIFF_NORMED, it will be in the range -1 to 0, and you will have to subtract the value from 1 in order to make sense of it, because the lowest value if used in this method.
Tip: you can use the java equivalent of minMaxLoc() in order to get the minimum and maximum values. It's very useful when used in conjunction with matchtemplate.
I believe 'minMaxLoc' that is located inside the class Core.
Here's a C++ implementation:
matchTemplate( input_mat, template_mat, result_mat, method_NORMED );
double minVal, maxVal;
double percentage;
Point minLoc; Point maxLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
if( method_NORMED == CV_TM_SQDIFF_NORMED )
{
percentage=1-minVal;
}
else
{
percentage=maxVal;
}
Useful C++ docs:
Match template description along with available methods: http://docs.opencv.org/modules/imgproc/doc/object_detection.html
MinMaxLoc documentation:
http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=minmaxloc#minmaxloc
Another approach will be background differencing. You can observe the distortion.
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
public class BackgroundDifference {
public static void main(String[] arg){
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat model = Highgui.imread("e:\\answers\\template.jpg",Highgui.CV_LOAD_IMAGE_GRAYSCALE);
Mat scene = Highgui.imread("e:\\answers\\front7.jpg",Highgui.CV_LOAD_IMAGE_GRAYSCALE);
Mat diff = new Mat();
Core.absdiff(model,scene,diff);
Imgproc.threshold(diff,diff,15,255,Imgproc.THRESH_BINARY);
int distortion = Core.countNonZero(diff);
System.out.println("distortion:"+distortion);
Highgui.imwrite("e:\\answers\\diff.jpg",diff);
}
}

Reassign to Mat in OpenCV

I have the following function which extracts a sub-image from an OpenCV cv::Mat
void Process(int a,int b,int c,int d)
{
// Extract img(a:b,c:d) each time
subImg = img(cv::Range(a, b), cv::Range(c,d));
}
I call Process() in a loop. On each invocation, the values of a,b,c,d keep changing. If subImg has been declared as cv::Mat subImg;, can I do the above ? i.e. Can OpenCV dynamically resize subImg or do I have to go for a pointer-based approach where I declare:
cv::Mat* subImg; // Initialized to NULL in constructor
and modify the function as follows:
void Process(int a,int b,int c,int d)
{
// Extract img(a:b,c:d) each time
if(subImg) delete subImg;
subImg = img(cv::Range(a, b), cv::Range(c,d)).clone();
}
You can do this with cv::Mat subImg;. cv::Mat uses reference counting, and sub-matrix knows that it belongs to bigger matrix, so memory will be deallocated properly.

Freak Descriptor Row type

I have the following code:
//newImg is a mat of an image and orderedKeyPoint is the result from Fast
cv::FREAK extractor;
cv::Mat queryDescriptors;
extractor.compute(newImg, orderedKeyPoint, queryDescriptors);
I am trying to access individual freak descriptors using queryDescriptors.at< ???>(r,0) where r is an arbitrary valid row value but I am not sure of the type. All documentation states that it is just a descriptor, but is that of type Mat or double or something else? Is this the best way of doing it?
cv::Mat descriptor2 = queryDescriptors.at<cv::Mat>(2,0);
I would like to be able to reconstruct queryDescriptors (Mat of descriptors) from individual descriptors by taking them and putting them in the row values of a cv::Mat, ex:
queryDescriptors.at<cv::Mat>(2,0) = descriptor2;
Any help or insight would be greatly appreciated,
Isaac
the FREAK descriptor is a uchar Mat with 64 cols and numkeypoints rows.
so, to get to an element of it:
uchar elm = descriptor.at<uchar>(row,col);
where row is the keypoint id, and col is the element id.
If you have a look into \opencv\modules\features2d\src\freak.cpp you can see:
int FREAK::descriptorSize() const
{
return FREAK_NB_PAIRS / 8; // descriptor length in bytes
}
int FREAK::descriptorType() const
{
return CV_8U;
}
int FREAK::defaultNorm() const
{
return NORM_HAMMING;
}
} // END NAMESPACE CV
So uchar seems to be the type as berak already suggested.

Standard Hough Lines in EMGU CV

I am in need of using the standard Hough Transformation (instead of the using the HoughLinesBinary method which implements Probabilistic Hough Transform) and have attempted doing so by creating a custom version of the HoughLinesBinary method:
using (MemStorage stor = new MemStorage())
{
IntPtr lines = CvInvoke.cvHoughLines2(canny.Ptr, stor.Ptr, Emgu.CV.CvEnum.HOUGH_TYPE.CV_HOUGH_STANDARD, rhoResolution, (thetaResolution*Math.PI)/180, threshold, 0, 0);
Seq<MCvMat> segments = new Seq<MCvMat>(lines, stor);
List<MCvMat> lineslist = segments.ToList();
foreach(MCvMat line in lineslist)
{
//Process lines: (rho, theta)
}
}
My problem is that I am unsure of what type is the sequence returned. I believe it should be MCvMat, due to reading the documentation that CvMat* is used in OpenCV, which also states that for STANDARD "the matrix must be (the created sequence will be) of CV_32FC2 type"
I am unclear as to what I would need to do to return and process that correct output data from the STANDARD hough lines (i.e. the 2x1 vector for each line giving the rho and theta information).
Any help would be greatly appreciated. Thank you
-Sal
I had the same problem myself a couple of days ago. This is how I solved it using marshalling. Please let me know if you find a simpler solution.
using (MemStorage stor = new MemStorage())
{
IntPtr lines = CvInvoke.cvHoughLines2(canny.Ptr, stor.Ptr, Emgu.CV.CvEnum.HOUGH_TYPE.CV_HOUGH_STANDARD, rhoResolution, (thetaResolution*Math.PI)/180, threshold, 0, 0);
int maxLines = 100;
for(int i = 0; i < maxLines; i++)
{
IntPtr line = CvInvoke.cvGetSeqElem(lines, i);
if (line == IntPtr.Zero)
{
// No more lines
break;
}
PolarCoordinates coords = (PolarCoordinates)System.Runtime.InteropServices.Marshal.PtrToStructure(line, typeof(PolarCoordinates));
// Do something with your Hough lines
}
}
with a struct defined as follows:
public struct PolarCoordinates
{
public float Rho;
public float Theta;
}

Resources