Issue with drawContours OpenCV c++ - opencv

I have a code in python and I am porting it to c++. I am getting a weird issue with drawContours function in OpenCV c++.
self.contours[i] = cv2.convexHull(self.contours[i])
cv2.drawContours(self.segments[object], [self.contours[i]], 0, 255, -1)
this is the function call in python and the value -1 for the thickness parameter is used for filling the contour and the result looks like
I am doing exactly the same in c++,
cv::convexHull(cv::Mat(contour), hull);
cv::drawContours(this->objectSegments[currentObject], cv::Mat(hull), -1, 255, -1);
but this is the resulting image:
(please look careful to see the convexhull points, this is not easily visible). I am getting only the points and not the filled polygon. I also tried using fillPoly like,
cv::fillPoly(this->objectSegments[currentObject],cv::Mat(hull),255);
but doesn't help.
Please help me in fixing the issue. I am sure that i am missing something very trivial but couldn't spot it.

The function drawContours() expects to receive a sequence of contours, each contour being a "vector of points".
The expression cv::Mat(hull) you use as a parameter returns the matrix in incorrect format, with each point being treated as a separate contour -- that's why you see only a few pixels.
According to the documentation of cv::Mat::Mat(const std::vector<_Tp>& vec) the vector passed into the constructor is used in the following manner:
STL vector whose elements form the matrix. The matrix has a single column and the number of rows equal to the number of vector elements.
Considering this, you have two options:
Transpose the matrix you've created (using cv::Mat::t()
Just use a vector of vectors of Points directly
The following sample shows how to use the vector directly:
cv::Mat output_image; // Work image
typedef std::vector<cv::Point> point_vector;
typedef std::vector<point_vector> contour_vector;
// Create with 1 "contour" for our convex hull
contour_vector hulls(1);
// Initialize the contour with the convex hull points
cv::convexHull(cv::Mat(contour), hulls[0]);
// And draw that single contour, filled
cv::drawContours(output_image, hulls, 0, 255, -1);

Related

why findchessboardcorners provides me in float values?

I am tring to figure out the chess board corners using openCV API. Below is the code snippet.
leftImage = cv2.imread ("left.jpg")
retVal, detectedCorners = cv2.findChessboardCorners (leftImage, (7, 6))
Now, detectedCorners[0] gives below values.
array([[ 475.44540405, 264.75949097]], dtype=float32)
My Question is :
How these pixels coordinate values are represented in the float value. It must have been the integer value of (x,y) in image?
I haven’t delved into the code yet. But I bet OpenCV is is using Harris corners here and calculating the sub pixel locations as described here
The result type is correct. They may decided it float to get more accurate results. As the documentation says:
The image points: This is a vector of Point2f vector which for
each input image contains coordinates of the important points (corners
for chessboard and centers of the circles for the circle pattern).
We have already collected this from findChessboardCorners or findCirclesGrid function. We just need to pass it on.

I am confused using the OpenCV sepfilter2D function's kernelX, and kernelY

I don't know how to use sepFilter2D properly. I'm confused using the function parameters such kernelX, kernelY in OpenCV sepFilter2D function.
vector<double> filter1; //row vector
sepFilter2D(src, convolvedImg, CV_64FC3, filter1, filter1, Point(-1, -1), 0.0, BORDER_DEFAULT);
//filter1 = [0.00443305 0.0540056 0.242036 0.39905 0.242036 0.0540056 0.00443305]
As you might be aware, the operation of convolution is widely used in image processing. It involves using a 2D filter, usually small in size (e.g. 3x3 or 5x5), and the short explanation is that you overlay the filter to each position, multiply the values in the filter with the values in the image and add everything together. The wikipedia page is much more detailed in presenting this operation.
Just to get a sense for this, assuming you have a MxN image and a UxV filter. For each pixel, you have to apply the filter once. Therefore, you have to perform MNU*V multiplications and additions.
Some filters have a nice property called separability. You can achieve the same effect of a UxV 2D filter by applying once a horizontal filter of size V and then a vertical filter of size U. Now you have MNU + MNV = MN(U+V) operations, therefore this is more efficient.
The sepFilter2D does exactly this: applies a vertical and a horizontal 1D filter. The full function signature is:
void sepFilter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernelX, InputArray kernelY, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT )
, where src is your initial image, the filtered image will be in dst, ddepth represents the desired type of the destination image, kernelX and kernelY are the horizontal and vertical 1D kernels I described above, anchor represents the kernel origin (default means center), delta represents a value that is added to the destination image to offset its brightness and borderType represents the method used around borders.
Use Mat data structure to declare kernels. (I'm not sure about vector, I'm not near me PC right now. I'll check later.)

Can't determine document edges from camera with OpenCV

I need find edges of document that in user hands.
1) Original image from camera:
2) Then i convert image to BG:
3) Then i make blur:
3) Finds edges in an image using the Canny:
4) And use dilate :
As you can see on the last image the contour around the map is torn and the contour is not determined. What is my error and how to solve the problem in order to determine the outline of the document completely?
This is code how i to do it:
final Mat mat = new Mat();
sourceMat.copyTo(mat);
//convert the image to black and white
Imgproc.cvtColor(mat, mat, Imgproc.COLOR_BGR2GRAY);
//blur to enhance edge detection
Imgproc.GaussianBlur(mat, mat, new Size(5, 5), 0);
if (isClicked) saveImageFromMat(mat, "blur", "blur");
//convert the image to black and white does (8 bit)
int thresh = 128;
Imgproc.Canny(mat, mat, thresh, thresh * 2);
//dilate helps to connect nearby line segments
Imgproc.dilate(mat, mat,
Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3)),
new Point(-1, -1),
2,
1,
new Scalar(1));
This answer is based on my above comment. If someone is holding the document, you cannot see the edge that is behind the user's hand. So, any method for detecting the outline of the document must be robust to some missing parts of the edge.
I suggest using a variant of the Hough transform to detect the document. The Wikipedia article about the Hough transform makes it sound quite scary (as Wikipedia often does with mathematical subjects), but don't be discouraged, actually they are not too difficult to understand or implement.
The original Hough transform detected straight lines in images. As explained in this OpenCV tutorial, any straight line in an image can be defined by 2 parameters: an angle θ and a distance r of the line from the origin. So you quantize these 2 parameters, and create a 2D array with one cell for every possible line that could be present in your image. (The finer the quantization you use, the larger the array you will need, but the more accurate the position of the found lines will be.) Initialize the array to zeros. Then, for every pixel that is part of an edge detected by Canny, you determine every line (θ,r) that the pixel could be part of, and increment the corresponding bin. After processing all pixels, you will have, for each bin, a count of how many pixels were detected on the line corresponding to that bin. Counts which are high enough probably represent real lines in the image, even if parts of the line are missing. So you just scan through the bins to find bins which exceed the threshold.
OpenCV contains Hough detectors for straight lines and circles, but not for rectangles. You could either use the line detector and check for 4 lines that form the edges of your document; or you could write your own Hough detector for rectangles, perhaps using the paper Jung 2004 for inspiration. Rectangles have at least 5 degrees of freedom (2D position, scale, aspect ratio, and rotation angle), and memory requirement for a 5D array obviously goes up pretty fast. But since the range of each parameter is limited (ie, the document's aspect ratio is known, and you can assume the document will be well centered and not rotated much) it is probably feasible.

Find defects in bottle shape using image processing using openCV

I am using Image processing, openCV , C++ to check the misshapes of bottles. I am very new to openCV. It will be a great help if someone can guide me a right direction how to achieve this. How can I detect the defects of the shape of the bottle using opencv and c++. I am giving bottle images as the inputs to the system.when a misshaped bottle is input system should detect it.
Defected bottle image :
Good Bottle image :
Basic approach:
you can extract the edges then Register the two images. In openCV you will get couple of filters for this.
Perfect Approach:
you can use statistical shape modeling algorithm, I am not sure if it is there in OPenCV.
Take the region of interest (ROI) and find contours.
Find convexhull
Find convexity defects
Do this for both the reference ROI and the defected ROI, then compare
The comparison would not be straightforward as you may have to establish some correspondence between the regions of the two contours(may be you can use a grid and use its cells as the ROIs - now many ROIs for a single image - to solve the correspondence complexities)
ROI in red:
Grid based approach (multiple ROIs):
You could try the opencv template matching function. From the opencv documentation:
Template matching is a technique for finding areas of an image that match (are similar) to a template image (patch).
It implements a sliding window scheme, by sliding the template image that we want to find over the source image and calculating a similarity metric that is stored in a result matrix.
In the result matrix, the darkest/brightest location indicates the highest matches (according to the template matching algorithm employed), which marks the position of the best match for the template. The brightest location can be found using the minMaxLoc function on the result matrix.
The signature of the matchTemplate method is as follows:
matchTemplate( image, template, result, match_method ); //Matches the template
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() ); //Normalizes the result
double minVal; double maxVal; Point minLoc; Point maxLoc; Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() ); //Finds the minimum and maximum values in the result
OpenCV provides several different algorithms for the matching, such as finding the normalized square difference of intensities(CV_TM_SQDIFF_NORMED). For the result matrix obtained using CV_TM_SQDIFF_NORMED, the lowest values correspond to the best matches. For other methods such as normalized cross correlation (CV_TM_CCORR_NORMED), the highest values correspond to the best matches.
In your case, you could threshold the result matrix with a tolerance value for deviation from the template image, and if the result on thresholding is an empty Mat, you could identify the bottle to be defective. You might have to experiment a little to find an appropriate threshold. If you want an exact match, you have to look for 0/1 (according to method) in the result matrix.
You can find more on opencv template matching here.
Hope this helps.

Converting matches from 8-bit 4 channels to 64-bit 1 channel in OpenCV

I have a vector of Point2f which have color space CV_8UC4 and need to convert them to CV_64F, is the following code correct?
points1.convertTo(points1, CV_64F);
More details:
I am trying to use this function to calculate the essential matrix (rotation/translation) through the 5-point algorithm, instead of using the findFundamentalMath included in OpenCV, which is based on the 8-point algorithm:
https://github.com/prclibo/relative-pose-estimation/blob/master/five-point-nister/five-point.cpp#L69
As you can see it first converts the image to CV_64F. My input image is a CV_8UC4, BGRA image. When I tested the function, both BGRA and greyscale images produce valid matrices from the mathematical point of view, but if I pass a greyscale image instead of color, it takes way more to calculate. Which makes me think I'm not doing something correctly in one of the two cases.
I read around that when the change in color space is not linear (which I suppose is the case when you go from 4 channels to 1 like in this case), you should normalize the intensity value. Is that correct? Which input should I give to this function?
Another note, the function is called like this in my code:
vector<Point2f>imgpts1, imgpts2;
for (vector<DMatch>::const_iterator it = matches.begin(); it!= matches.end(); ++it)
{
imgpts1.push_back(firstViewFeatures.second[it->queryIdx].pt);
imgpts2.push_back(secondViewFeatures.second[it->trainIdx].pt);
}
Mat mask;
Mat E = findEssentialMat(imgpts1, imgpts2, [camera focal], [camera principal_point], CV_RANSAC, 0.999, 1, mask);
The fact I'm not passing a Mat, but a vector of Point2f instead, seems to create no problems, as it compiles and executes properly.
Is it the case I should store the matches in a Mat?
I am no sure do you mean by vector of Point2f in some color space, but if you want to convert vector of points into vector of points of another type you can use any standard C++/STL function like copy(), assign() or insert(). For example:
copy(floatPoints.begin(), floatPoints.end(), doublePoints.begin());
or
doublePoints.insert(doublePoints.end(), floatPoints.begin(), floatPoints.end());
No, it is not. A std::vector<cv::Pointf2f> cannot make use of the OpenCV convertTo function.
I think you really mean that you have a cv::Mat points1 of type CV_8UC4. Note that those are RxCx4 values (being R and C the number of rows and columns), and that in a CV_64F matrix you will have RxC values only. So, you need to be more clear on how you want to transform those values.
You can do points1.convertTo(points1, CV_64FC4) to get a RxCx4 matrix.
Update:
Some remarks after you updated the question:
Note that a vector<cv::Point2f> is a vector of 2D points that is not associated to any particular color space, they are just coordinates in the image axes. So, they represent the same 2D points in a grey, rgb or hsv image. Then, the execution time of findEssentialMat doesn't depend on the image color space. Getting the points may, though.
That said, I think your input for findEssentialMat is ok (the function takes care of the vectors and convert them into their internal representation). In this cases, it is very useful to draw the points in your image to debug the code.

Resources