Using OpenCV Mat as an Array: VB vs C++ - c++

I'm using VS2015, EmguCV 3 and VB, and am trying to translate some C++ code.
C++
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(bw, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
for (size_t i = 0; i < contours.size(); ++i)
{...}
I'm trying to use some object orientation code given in full here. Basically the code is going to tell me the angle at which an object is oriented in an image. Unfortunately it is C++ code and VB developers' brains can explode at the sight of some C++ syntax. Any help avoiding the need to clean my screen again would be welcome. The explosive material was vector<vector<point> > contours; in this particular case, and my question is about how to translate it.
I got this far:
VB
Imports Emgu.CV
Imports Emgu.CV.Structure
...
contours = New Mat
hierarchy = New Mat
CvInvoke.FindContours(m, contours, hierarchy, CvEnum.RetrType.List, CvEnum.ChainApproxMethod.ChainApproxNone)
I'm using EmguCV 3. This claims that FindContours takes image As IInputOutputArray, contours As IOutputArray, hierarchy As IOutputArray. So I figured I could provide three Mats. m is defined earlier has been successfully processed (e.g. with Threshold) so I'm happy with m. contours and hierarchy on the other hand may be problematic. When I run the code, I get an unhandled exception:
Emgu.CV.Util.CvException: OpenCV: (_contours.kind() == _InputArray::STD_VECTOR_VECTOR || _contours.kind() == _InputArray::STD_VECTOR_MAT || _contours.kind() == _InputArray::STD_VECTOR_UMAT)
This seems to suggest I've passed the wrong types to OpenCV although I would have expected Emgu to handle that. But I have no clue. Any help?

Based on the Documentation and under the VB section:
"contours Type: Emgu.CV.IOutputArray -> Detected contours. Each contour
is stored as a vector of points."
Therefore, instead of sending a single MAT as your contours, you should be sending a container of vectors of points.
See here The Equivalent of C++ Vectors for VB.Net.

Related

Silhouette extraction from binary image

I am working with binary images from CASIA database and opencv in a C++ project. I am looking for a way of extracting only the silhouette(the bounding box containing the silhouette). The original images are 240x320 and my goal is to get only the silhouette in a new image (let’s say 100x50 size).
My first idea would be to get the minimum and maximum position of “white” pixels on rows and columns and get the pixels inside this rectangle in a new image, but I consider this not efficient at all. If you have any suggetion, I would be more than happy to hear it. On the left is the input and on the right is the output.
You can use the built-in OpenCV functionalities to find contours from your binary image:
e.g.
// using namespace cv;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( your_binary_mat, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE );
Note this will look for external contours (ignores inner contours which for the image above don't apply anyway) and retrieve a simplified approximation of the points.
Once you access the contour you can use either boundingRect() or minAreaRect() (wether you need the bounding box rotated or not).

output differences when using findContours in opencv2 and opencv3

I am using the exact same steps to find the contours of an image but I am getting two different results in Opencv 2.4.8 and Opencv 3.2! Anybody knows why?
Here is the procedure:
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::imwrite("binImageInB.jpg", binImageIn);
// find contour of the binary image
cv::findContours( binImageIn, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); // Find the contours in the image // save
cv::imwrite("binImageIn.jpg", binImageIn);
The input image is:
The output when using opencv 2.4.8:
And the output when using Opencv3.2:
The documentation for 2.4.x mentions:
Note: Source image is modified by this function.
The documentation for 3.3.1 mentions:
Since opencv 3.2 source image is not modified by this function.
In general, you use the contours and hierarchy output parameters. Since the later versions no longer modify the input image, I'd consided that a side effect, which was not intended to be useful.

OpenCV: findContours exception

my matlab code is:
h = fspecial('average', filterSize);
imageData = imfilter(imageData, h, 'replicate');
bwImg = im2bw(imageData, grayThresh);
cDist=regionprops(bwImg, 'Area');
cDist=[cDist.Area];
opencv code is:
cv::blur(dst, dst,cv::Size(filterSize,filterSize));
dst = im2bw(dst, grayThresh);
cv::vector<cv::vector<cv::Point> > contours;
cv::vector<cv::Vec4i> hierarchy;
cv::findContours(dst,contours,hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
here is my image2blackand white function
cv::Mat AutomaticMacbethDetection::im2bw(cv::Mat src, double grayThresh)
{
cv::Mat dst;
cv::threshold(src, dst, grayThresh, 1, CV_THRESH_BINARY);
return dst;
}
I'm getting an exception in findContours() C++ exception: cv::Exception at memory location 0x0000003F6E09E0A0.
Can you please explain what am I doing wrong.
dst is cv::Mat and I used it all along it has my original values.
Update here is my matrix written into *.txt file:
http://www.filedropper.com/gili
UPDATE 2:
I have added dst.convertTo(dst,CV_8U); like Micka suggested, I no longer have an exception. however values are nothing like expected.
Take a look at this question which has a similar problem to what you're encountering: Matlab and OpenCV calculate different image moment m00 for the same image.
Basically, the OP in the linked post is trying to find the zeroth image moment for both x and y of all closed contours - which is actually just the area, by using findContours in OpenCV and regionprops in MATLAB. In MATLAB, that can be accessed by the Area property from regionprops, and judging from your MATLAB code, you wish to find the same quantity.
From the post, there is most certainly a difference between how OpenCV and MATLAB finds contours in an image. This boils down to the way both platforms consider what is a "connected pixel". OpenCV only uses a four-pixel neighbourhood while MATLAB uses an eight-pixel neighbourhood.
As such, there is nothing wrong with your implementation, and converting to 8UC1 is good. However, the areas (and ultimately the total number of connected components and contours themselves) between both contours found with MATLAB and OpenCV are not the same. The only way for you to get exactly the same result is if you manually draw the contours found by findContours on a black image, and using the cv::moments function directly on this image.
However, because of the differing implementations of cv::blur() in comparison to fspecial with an averaging mask that is even, you still may not be able to get the same results along the borders of the image. If there are no important contours around the borders of your image, then hopefully this will give you the right result.
Good luck!

FindContours() Compiler issues?

Recently I have moved a project from visual studios 2010 to 2012. As soon as I did I started experiencing memory exceptions that result from the use of findContours(). I've played around with other solutions, but none of them seem to be working. However, based on those solutions I believe that the problem is with the project properties. Any suggestions?
To be more specific, the code crashes with a memory heap error. Here is the code:
//cameraFeed is of type Mat and is declared earlier on.
Mat temp;
Mat HSV;
Mat threshold;
Vid_mtx.lock();
//convert frame from BGR to HSV colorspace
cvtColor(cameraFeed,HSV,COLOR_BGR2HSV);
Vid_mtx.unlock();
//track objects based on the HSV slider values.
inRange(HSV,Scalar(H_MIN,S_MIN,V_MIN),Scalar(H_MAX,S_MAX,V_MAX),threshold);
morphOps(threshold);
//if(calibrationMode==true)
imshow(windowName2,threshold);
threshold.copyTo(temp);
//cvtColor(temp, temp_grey,COLOR_BGR2GRAY);
if(temp.empty()) printf("Whatcha doin?");
//these two vectors needed for output of findContours
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
//find contours of filtered image using openCV findContours function
findContours(temp,contours,hierarchy, CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);

Contours opencv : How to eliminate small contours in a binary image

I am currently working on image processing project. I am using Opencv2.3.1 with VC++.
I have written the code such that, the input image is filtered to only blue color and converted to a binary image. The binary image has some small objects which I don't want. I wanted to eliminate those small objects, so i used openCV's cvFindContours() method to detect contours in Binary image. but the problem is I cant eliminate the small objects in the image output. I used cvContourArea() function , but didn't work properly.. , erode function also didn't work properly.
So please someone help me with this problem..
The binary image which I obtained :
The result/output image which I want to obtain :
Ok, I believe your problem could be solved with the bounding box demo recently introduced by OpenCV.
As you have probably noticed, the object you are interested at should be inside the largest rectangle draw in the picture. Luckily, this code is not very complex and I'm sure you can figure it all out by investigating and experimenting with it.
Here is my solution to eliminate small contours.
The basic idea is check the length/area for each contour, then delete the smaller one from vector container.
normally you will get contours like this
Mat canny_output; //example from OpenCV Tutorial
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny(src_img, canny_output, thresh, thresh*2, 3);//with or without, explained later.
findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0,0));
With Canny() pre-processing, you will get contour segments, however each segment is stored with boundary pixels as a closed ring. In this case, you can check the length and delete the small one like
for (vector<vector<Point> >::iterator it = contours.begin(); it!=contours.end(); )
{
if (it->size()<contour_length_threshold)
it=contours.erase(it);
else
++it;
}
Without Canny() preprocessing, you will get contours of objects.
Similarity, you can also use area to define a threshold to eliminate small objects, as OpenCV tutorial shown
vector<Point> contour = contours[i];
double area0 = contourArea(contour);
this contourArea() is the number of non-zero pixels
Are you sure filtering by small contour area didn't work? It's always worked for me. Can we see your code?
Also, as sue-ling mentioned, it's a good idea to use both erode and dilate to approximately preserve area. To remove small noisy bits, use erode first, and to fill in holes, use dilate first.
And another aside, you may want to check out the new C++ versions of the cv* functions if you weren't aware of them already (documentation for findContours). They're much easier to use, in my opinion.
Judging by the before and after images, you need to determine the area of all the white areas or blobs, then apply a threshold area value. This would eliminate all areas less than the value and leave only the large white region which is seen in the 2nd image. After using the cvFindContours function, try using 0 order moments. This would return the area of the blobs in the image. This link might be helpful in implementing what I've just described.
http://www.aishack.in/2010/07/tracking-colored-objects-in-opencv/
I believe you can use morphological operators like erode and dilate (read more here)
You need to perform erosion with a kernel size near to the radius of the circle on the right (the one you want to eliminate).
followed by dilation using the same kernel to fill the gaps created by the erosion step.
FYI erosion followed by dilation using the same kernel is called opening.
the code will be something like this
int erosion_size = 30; // adjust with you application
Mat erode_element = getStructuringElement( MORPH_ELLIPSE,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
erode( binary_img, binary_img, erode_element );
dilate( binary_img, binary_img, erode_element );
It is not a fast way but may be usefull in some cases.
There is a new function in OpencCV 3.0 - connectedComponentsWithStats. With it we can get area of connected components and eliminate unnecessary. So we can easy remove circle with holes, with the same bounding box as solid circle.