Can't draw largest contour - opencv

I have the following code to draw the largest contour. But It seems there is something that I am doing wrong. Please advice
if(inputImage.data == NULL)
return HandInfo2();
Mat outputImage = Mat::zeros( inputImage.size(), CV_8UC1);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
vector<Point> largestContour;
int largestArea = -1;
findContours( inputImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
/// Approximate contours to polygons
vector<vector<Point> > polyContours( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{
approxPolyDP( Mat(contours[i]), polyContours[i], 3, true );
}
for( int i = 0; i < contours.size(); i++ )
{
int area = fabs(contourArea(polyContours[i],false));
if(area > largestArea && area > size)
{
largestArea = area;
largestContour = polyContours[i];
}
}
Scalar color = Scalar( 255 );
if(largestContour.size()>0)
drawContours( outputImage, largestContour, 0, color, 1, 8, vector<Vec4i>(), 0, Point() );
When drawContours() is being called, I get the following error
OpenCV Error: Assertion failed (i < 0) in unknown function, file ..\..\..\src\opencv\modules\core\src\matrix.cpp, line 957
What am I doing wrong here?

Ok, just for someone who makes the same mistake.
I needed the a vector<vector<Point>> largestContour; instead of vector largestContour;
And changed the code from largestContour = polyContours[i]; to largestContour.push_back(polyContours[i]);
That was it. Now I can extract the largest contour.

Related

object detection of various shapes in opencv

I have an image and want to detect various objects at a time using opencv methods.
I have tried detecting one object using contouring and using the area to filter other counters. But I need to detect other objects too but they vary in area and length.
Can anyone help me to use any methods for detecting it.
This is the original image:
this is the code that I have tried for detection:
int main()
{
Mat msrc = imread("Task6_Resources/Scratch.jpg", 1);
Mat src = imread("Task6_Resources/Scratch.jpg", 0);
Mat imgblur;
GaussianBlur(src, imgblur, Size(13,13), 0);
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
clahe->setClipLimit(8);
cv::Mat gcimg;
clahe->apply(imgblur, gcimg);
Mat thresh;
threshold(gcimg, thresh, 55, 255, THRESH_BINARY_INV);
Mat th_mina = minareafilter(thresh, 195); //function used to filter small and large blobs
Mat th_maxa = maxareafilter(th_mina, 393);
Mat imdilate;
dilate(th_maxa, imdilate, getStructuringElement(MORPH_RECT, Size(3, 1)), Point(-1, -1), 7);
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(imdilate, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
cout << "Number of contours" << contours.size() << endl;
//Largest contour according to area
for (int i = 0; i < contours.size(); i++){
double a = contourArea(contours[i], false);
if (a > largest_area) {
largest_area = a;
largest_contour_index = i;
bounding_rect = boundingRect(contours[i]);
}
}
for (int c = 0; c < contours.size(); c++){
printf(" * Contour[%d] Area OpenCV: %.2f - Length: %.2f \n",
c,contourArea(contours[c]), arcLength(contours[c], true));
}
rectangle(msrc, bounding_rect, Scalar(0, 255, 0), 2, 8, 0);
imshow("largest contour", msrc);
waitKey(0);
destroyAllWindows();
return 0;
}
This is the image on which I am applying contouring
After the code I am able to detect the green box using largest area in contouring, but I need to detect those red boxes too. (only the region of red boxes)
The problem is here I cannot apply again area parameter to filter the contours as some other contours have same area as the resultant contour.
The image result required:

find trapezoid's 4 points for wraping (rectangle )

I need to find trapezoid's 4 points. I tried to use "ret" but only 2 points, seems just 1point is good.
find biggest rectangle result
int main(int argc, char** argv)
{
Mat src = imread("IMG_20160708_1338252.jpg");
imshow("source", src);
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
Mat thr;
cvtColor(src, thr, COLOR_BGR2GRAY); //Convert to gray
threshold(thr, thr, 125, 255, THRESH_BINARY); //Threshold the gray
vector<vector<Point> > contours; // Vector for storing contours
findContours(thr, contours, RETR_CCOMP, CHAIN_APPROX_SIMPLE); // Find the contours in the image
for (size_t i = 0; i < contours.size(); i++) // iterate through each contour.
{
double area = contourArea(contours[i]); // Find the area of contour
//src면적이랑 area가 같으면 제외
//if (src.size().area != area) {
if (area > largest_area)
{
largest_area = area;
largest_contour_index = i; //Store the index of largest contour
bounding_rect = boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
//}
}
printf("top%d,%d\n", bounding_rect.tl().x, bounding_rect.tl().y);
printf("bottom%d,%d\n\n", bounding_rect.br().x, bounding_rect.br().y);
printf("top%d,%d\n", bounding_rect.x, bounding_rect.y);
printf("%d,%d\n", bounding_rect.x, bounding_rect.y+ bounding_rect.height);
printf("bottom%d,%d\n", bounding_rect.x + bounding_rect.width, bounding_rect.y);
printf("%d,%d\n\n", bounding_rect.x+ bounding_rect.width, bounding_rect.y+ bounding_rect.height);
//printf("bottom%d,%d\n", bounding_rect.br().x, bounding_rect.br().y);
//contours[largest_contour_index];//가장큰 사각형
//contours[largest_contour_index][0].x; contours[largest_contour_index][0].y;
printf("1-%d,", contours[largest_contour_index]);
printf("1-%d\n", contours[largest_contour_index][0].y);
printf("2-%d,", contours[largest_contour_index][1].x);
printf("2-%d\n", contours[largest_contour_index][1].y);
printf("3-%d,", contours[largest_contour_index][2].x);
printf("3-%d\n", contours[largest_contour_index][2].y);
printf("4-%d,", contours[largest_contour_index][3].x);
printf("4-%d\n", contours[largest_contour_index][3].y);
//printf("1%d,", contours[0][largest_contour_index].x);
drawContours(src, contours, largest_contour_index, Scalar(0, 255, 0), 2); // Draw the largest contour using previously stored index.
imshow("result", src);
waitKey();
return 0;
}
How can I find biggest rectangle?

How to improve the distance to detect objects?

I’m working on a project that should filter the red objects in an image and calculates the distance to this object with two webcams.
To detect the objects i convert the image from BGR to HSV and use the function inRange to threshold them.
Then i use findContours to get the contours in the image, which should be the contours of the red objects.
As last step i use boundingRect to get a Vector of Rect that contains one Rect per detected object.
The two images below shows my problem. The one with the pink rectangle is about 162cm away from the camera and the other about 175cm. If the Object is further then 170cm the object is not recognized, alltough the thresholded image is showing the contours of the object.
>170cm
<170cm
Is there a way to improve the distance in which the object is detected?
main.cpp
ObjectDetection obj;
StereoVision sv;
for (;;) {
cp.read(imgl);
cp2.read(imgr);
sv.calculateDisparity(imgl, imgr, dispfull, disp8, imgToDisplay);
Mat imgrt, imglt;
obj.filterColor(imgl, imgr, imglt, imgrt);
//p1 und p2 sind die gefundenen Konturen eines Bildes
vector<vector<Point> > p1 = obj.getPointOfObject(imglt);
vector<Rect> allRoisOfObjects = obj.getAllRectangles(imgl, p1);
for(int i = 0; i < allRoisOfObjects.size(); i++){
Rect pos = allRoisOfObjects.at(i);
pos.width -= 20;
pos.height -= 20;
pos.x += 10;
pos.y += 10;
disp = dispfull(pos);
float distance = sv.calculateAverageDistance(pos.tl(),pos.br(),dispfull);
stringstream ss;
ss << distance;
rectangle(imgToDisplay, allRoisOfObjects.at(i), color, 2,8, 0);
putText(imgToDisplay, ss.str(), pos.br(), 1, 1, color, 1);
ss.clear();
ss.str("");
newObjects.push_back(pos);
}
}
ObjectDetection.cpp
void ObjectDetection::filterColor(Mat& img1, Mat& img2, Mat& output1,
Mat& output2) {
Mat imgHSV, imgHSV2;
cvtColor(img1, imgHSV, COLOR_BGR2HSV); //Convert the captured frame from BGR to HSV
cvtColor(img2, imgHSV2, COLOR_BGR2HSV);
Mat imgThresholded, imgThresholded2;
inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV),
imgThresholded);
inRange(imgHSV2, Scalar(iLowH, iLowS, iLowV),
Scalar(iHighH, iHighS, iHighV), imgThresholded2);
output1 = imgThresholded;
output2 = imgThresholded2;
}
vector<vector<Point> > ObjectDetection::getPointOfObject(Mat img) {
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE,
Point(0, 0));
return contours;
}
vector<Rect> ObjectDetection::getAllRectangles(Mat & img, vector<vector<Point> > contours){
vector<vector<Point> > contours_poly(contours.size());
vector<Rect> boundRect(contours.size());
vector<Point2f> center(contours.size());
vector<float> radius(contours.size());
Rect rrect;
rrect.height = -1;
RNG rng(12345);
for (int i = 0; i < contours.size(); i++) {
approxPolyDP(Mat(contours[i]), contours_poly[i], 3, true);
boundRect[i] = boundingRect(Mat(contours_poly[i]));
}
return boundRect;
}

OpenCV draw rectangle from webcam with 2 largest objects

I need to draw rectangle with 2 largest object from webcam. I already got to draw contours with 2 largest object from webcam but now i confuse in how to draw 2 largest Rectangle.
Someone can show me the code Please~
//find and draw contours
void showconvex(Mat &thresh,Mat &frame) {
int largestIndex = 0;
int largestContour = 0;
int secondLargestIndex = 0;
int secondLargestContour = 0;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
//find contours
findContours(thresh, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
/// Find the convex hull object for each contour
vector<vector<Point> >hull(contours.size());
vector<vector<int> >inthull(contours.size());
vector<vector<Vec4i> >defects(contours.size());
for (int i = 0; i < contours.size(); i++)
{
convexHull(Mat(contours[i]), hull[i], false);
convexHull(Mat(contours[i]),inthull[i], false);
if (inthull[i].size()>3)
convexityDefects(contours[i], inthull[i], defects[i]);
}
//find 2 largest contour
for( int i = 0; i< contours.size(); i++ )
{
if(contours[i].size() > largestContour)
{
secondLargestContour = largestContour;
secondLargestIndex = largestIndex;
largestContour = contours[i].size();
largestIndex = i;
}
else if(contours[i].size() > secondLargestContour)
{
secondLargestContour = contours[i].size();
secondLargestIndex = i;
}
}
//show contours of 2 biggest and hull as well
if(contours.size()>0)
{
//check for contouraea function if error occur
//draw the 2 largest contour using previously stored index.
drawContours(frame, contours, largestIndex, CV_RGB(0,255,0), 2, 8, hierarchy);
drawContours(frame, contours, secondLargestIndex, CV_RGB(0,255,0), 2, 8, hierarchy);
}
}
take a look at the code below
based on sorting contours by bounding boxes or by areas.
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
struct contour_sorter_dsc // sorts contours by their bounding boxes descending
{
bool operator ()( const vector<Point>& a, const vector<Point> & b )
{
Rect ra( boundingRect(a) );
Rect rb( boundingRect(b) );
return ( ( rb.width * rb.height ) < ( ra.width * ra.height ) );
}
};
struct contour_sorter_dsc_area // sorts contours by their areas descending
{
bool operator ()( const vector<Point>& a, const vector<Point> & b )
{
double area_a = contourArea( a );
double area_b = contourArea( b );
return ( area_b < area_a );
}
};
int main( int argc, char** argv )
{
Mat src = imread( argv[1] );
if( src.empty() )
{
return -1;
}
Mat canvas1 = src.clone();
Mat canvas2 = src.clone();
Mat gray;
cvtColor( src, gray, COLOR_BGR2GRAY );
gray = gray > 127; // binarize image
vector<vector<Point> > contours;
findContours( gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE );
sort(contours.begin(), contours.end(), contour_sorter_dsc());
for( size_t i = 0; i< 2; i++ )
{ // checks if the first contour is image boundary
if( contours[0][0] == Point( 1, 1 ) & contours[0][1] == Point( 1, gray.rows -2 )
& contours[0][2] == Point( gray.cols - 2, gray.rows -2 ) & contours[0][3] == Point( gray.cols - 2, 1 ) )
{
contours[0] = contours[1];
contours[1] = contours[2];
}
if( i < contours.size())
{
drawContours( canvas1, contours, i, Scalar( 255,255,0 ) );
Rect minRect = boundingRect( Mat(contours[i]) );
rectangle( canvas1, minRect, Scalar( 0, 0, 255 ) );
}
}
imshow( "result of sorting contours by bounding boxes ", canvas1 );
sort(contours.begin(), contours.end(), contour_sorter_dsc_area());
for( size_t i = 0; i< 2; i++ )
{ // checks if the first contour is image boundary
if( contours[0][0] == Point( 1, 1 ) & contours[0][1] == Point( 1, gray.rows -2 )
& contours[0][2] == Point( gray.cols - 2, gray.rows -2 ) & contours[0][3] == Point( gray.cols - 2, 1 ) )
{
contours[0] = contours[1];
contours[1] = contours[2];
}
if( i < contours.size())
{
drawContours( canvas2, contours, i, Scalar( 255,255,0 ) );
Rect minRect = boundingRect( Mat(contours[i]) );
rectangle( canvas2, minRect, Scalar( 0, 0, 255 ) );
}
}
imshow( "result of sorting contours by areas ", canvas2 );
waitKey();
return 0;
}
Input image
Result Images according sort type

OpenCV: Retrieving color of the center of a contour

Im trying to detect the colour of a set of shapes in a black image using OpenCV, for which I use Canny detection. However the color output always comes back as black.
std::vector<std::pair<cv::Point, cv::Vec3b> > Asteroids::DetectPoints(const cv::Mat &image)
{
cv::Mat imageGray;
cv::cvtColor( image, imageGray, CV_BGR2GRAY );
cv::threshold(imageGray, imageGray, 1, 255, cv::THRESH_BINARY);
cv::Mat canny_output;
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
int thresh = 10;
// Detect edges using canny
cv::Canny( imageGray, canny_output, thresh, thresh*2, 3 );
// Find contours
cv::findContours( canny_output, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cv::Point(0, 0) );
std::vector<std::pair<cv::Point, cv::Vec3b> > points;
for(unsigned int i = 0; i < contours.size(); i++ )
{
cv::Rect rect = cv::boundingRect(contours[i]);
std::pair<cv::Point, cv::Vec3b> posColor;
posColor.first = cv::Point( rect.tl().x + (rect.size().width / 2), rect.tl().y + (rect.size().height / 2));
posColor.second = image.at<cv::Vec3b>( posColor.first.x, posColor.first.y );
//Dont add teh entry to the list if one with the same color and position is already pressent,
//The contour detection sometimes returns duplicates
bool isInList = false;
for(unsigned int j = 0; j < points.size(); j++)
if(points[j].first == posColor.first && points[j].second == posColor.second)
isInList = true;
if(!isInList)
points.push_back( posColor );
}
return points;
}
I know it has to be an issue with the positions or something along those lines, but I cant figure out what
I might be wrong, but off the top of my head :
Shouldn't this read
posColor.second = image.at<cv::Vec3b>(posColor.first.y, posColor.first.x);
and not the other way around like you did it ?
Matrix notation, not cartesian notation ?

Resources