How would I integrate the contourArea() function in my OpenCV program? - c++

My code is for the purposes of detecting various shapes based off the number of vertices they have. I've finally accomplished that and it works perfectly for simple images like shown here: http://i.imgur.com/f9qvBwF.png However for this thresh image: http://i.imgur.com/jhl0NUQ.png it creates hundreds of shapes because of all the little pixels. Now I know enough of OpenCV to know there's eroding and dilating, but it seems like the best approach would be to exclude contours whose area is below a certain pixel count, however I don't know how to integrate the contourArea() function into my code such that it would work.
Here is my current code:
#include "opencv2/core/core.hpp"
#include "opencv2/flann/miniflann.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/photo/photo.hpp"
#include "opencv2/video/video.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/ml/ml.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/core/core_c.h"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/imgproc/imgproc_c.h"
using namespace cv;
using namespace std;
Mat img;
Mat img_gray;
void contour_finder(int, void*);
int main(int argc, char *argv[])
{
img = imread("C:/Users/wyndr_000/Documents/VisualStudio2013/Projects/OpenCV_Template/OpenCV_Template/testpic.png", CV_LOAD_IMAGE_UNCHANGED);
cvtColor(img, img_gray, CV_RGB2GRAY);
contour_finder(0, 0);
waitKey();
}
void contour_finder(int, void*)
{
Mat img_thresh;
Mat drawn_contours;
threshold(img_gray, img_thresh, 183, 255, 2);
imshow("Thresh Image", img_thresh);
vector<vector<Point> > contours;
vector<Point> result;
findContours(img_thresh, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
// Find a way to filter it out based on Area
for (size_t i = 0; i < contours.size(); i++){
approxPolyDP(Mat(contours[i]), result, arcLength(Mat(contours[i]), true)*0.02, true);
// if (contourArea(result) < 49)
//{
if (result.size() == 3)
{
cout << "TRIANGLE\n";
}
else if (result.size() == 4)
{
cout << "QUADRILATERAL\n";
}
else if (result.size() == 5)
{
cout << "PENTAGON\n";
}
else if (result.size() == 6)
{
cout << "HEXAGON\n";
}
else if (result.size() == 10)
{
cout << "STAR\n";
}
else if (result.size() == 12)
{
cout << "PLUS-SIGN\n";
}
// }
}
/* drawn_contours = Mat::zeros(img_thresh.size(), CV_8UC3);
for (int i = 0; i< contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawn_contours, contours, i, color, 2, 8, hierarchy, 0, Point());
}
namedWindow("Contours", CV_WINDOW_AUTOSIZE);
imshow("Contours", drawn_contours); */
}
You'll notice where I declare what different amounts of vertices indicate, I have a commented contourArea function, because that's where I imagined it would go.

Related

OpenCV: Unable to run Canny edge detection in C++

I have written a simple code to perform canny edge detection on a live stream. The code is as shown below,
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int lowThreshold=0;
int const max_lowThreshold = 100;
int kernel_size = 3;
int ratio = 3;
Mat img;
Mat display;
void CannyThreshold()
{
cvtColor(img, display, COLOR_RGB2GRAY);
// GaussianBlur(display,display,Size(7,7),3,3);
GaussianBlur(display, display, Size(1, 1), 1,1);
printf("%d\n",lowThreshold);
Canny(display,display,lowThreshold,3);
imshow("Canny",display);
}
int main()
{
VideoCapture cap(0);
namedWindow("Canny");
createTrackbar("Min Threshold: ","Canny",&lowThreshold,max_lowThreshold);
while(1)
{
cap.read(img);
int ret = waitKey(1);
CannyThreshold();
if(ret == 'q')
break;
}
cap.release();
return 0;
}
I get the following run-time error when I run the code. (I'm using OpenCV 4)
error: (-215:Assertion failed) ksize.width > 0 && ksize.width % 2 == 1 && ksize.height > 0 && ksize.height % 2 == 1 in function 'createGaussianKernels'
Any suggestions on how I can solve this error?
The issue is GaussianBlur cant accept kernel size of 1. Correct it to 3x3 or 5x5 in your code as follows
#include <opencv2/core/utility.hpp>
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <ctype.h>
using namespace cv;
using namespace std;
int main(int argc, const char** argv)
{
VideoCapture cap;
Mat frame;
Mat image; // from cap to image
Mat src_gray;
Mat dst;
Mat detected_edges;
const String window_name = "Canny Edge Detector - VideoCapture";
int lowThreshold = 10;
const int max_lowThreshold = 100;
const int ratio = 3;
const int kernel_size = 3;
int FPS;
int frame_width, frame_height;
int camNum = 0;
cap.open(camNum);
if (!cap.isOpened())
{
cout << "***Could not initialize capturing...***\n";
cout << "Current parameter's value: \n";
return -1;
}
FPS = cap.get(CAP_PROP_FPS);
frame_width = cap.get(CAP_PROP_FRAME_WIDTH);
frame_height = cap.get(CAP_PROP_FRAME_HEIGHT);
dst.create(frame_width, frame_height, CV_8UC3);
//cout << CV_8UC3;
while (true)
{
cap >> frame;
if (frame.empty())
break;
frame.copyTo(image);
// Convert the image to grayscale
cvtColor(image, src_gray, COLOR_BGR2GRAY);
//![reduce_noise]
/// Reduce noise with a kernel 3x3
blur(src_gray, detected_edges, Size(3, 3));
//![reduce_noise]
//![canny]
/// Canny detector
Canny(detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size);
//![canny]
/// Using Canny's output as a mask, we display our result
//![fill]
dst = Scalar::all(0);
//![fill]
//![copyto]
image.copyTo(dst, detected_edges);
//![copyto]
//![display]
imshow(window_name, dst);
if (waitKey(1000 / FPS) >= 0)
break;
}
return 0;
}

OpenCV Optical Flow Core Dumped

I am using the OpenCV LK Optical Flow example, for some robot vision application with ROS.
It seems to be working reasonably well, however, I am having the error below:
OpenCV Error: Assertion failed ((npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0) in calc, file /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/video/src/lkpyramid.cpp, line 1231
terminate called after throwing an instance of 'cv::Exception'
what(): /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/video/src/lkpyramid.cpp:1231: error: (-215) (npoints = prevPtsMat.checkVector(2, CV_32F, true)) >= 0 in function calc
Aborted (core dumped)
As far I could understand by reading the error message, and by the system behavior, it is happening when all of the initial tracking points are gone in the current frame.
There would be a way to restart this process (defining new points) instead of aborting?
My code by the way:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/video.hpp>
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <vector>
using namespace cv;
using namespace std;
static const std::string OPENCV_WINDOW = "Image_window";
class ImageConverter
{
ros::NodeHandle nh_;
image_transport::ImageTransport it_;
image_transport::Subscriber image_sub_;
image_transport::Publisher image_pub_;
public:
cv::Mat current_frame;
public:
ImageConverter()
: it_(nh_)
{
image_sub_ = it_.subscribe("/realsense/color/image_raw", 1,
&ImageConverter::imageCallback, this);
cv::namedWindow(OPENCV_WINDOW);
}
~ImageConverter()
{
cv::destroyWindow(OPENCV_WINDOW);
}
void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
cv_bridge::CvImagePtr cv_image;
try
{
cv_image = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
current_frame = cv_image->image;
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("cv_bridge exception: %s", e.what());
return;
}
}
};
int main(int argc, char** argv)
{
ros::init(argc, argv, "OpenCV_Node");
ImageConverter MyNode;
ros::Rate r(30);
r.sleep();
ros::spinOnce();
r.sleep();
// Tentative of Using Open CV Tools with a ROS Image
// Lucas-Kanade Optical Flow from: https://docs.opencv.org/master/d4/dee/tutorial_optical_flow.html
// Create some random colors
vector<Scalar> colors;
RNG rng;
for(int i = 0; i < 100; i++)
{
int r = rng.uniform(0, 256);
int g = rng.uniform(0, 256);
int b = rng.uniform(0, 256);
colors.push_back(Scalar(r,g,b));
}
Mat old_frame, old_gray;
vector<Point2f> p0, p1;
// Take first frame and find corners in it
old_frame = MyNode.current_frame;
cvtColor(old_frame, old_gray, COLOR_BGR2GRAY);
goodFeaturesToTrack(old_gray, p0, 100, 0.3, 7, Mat(), 7, false, 0.04);
// Create a mask image for drawing purposes
Mat mask = Mat::zeros(old_frame.size(), old_frame.type());
//while(true){
while(ros::ok()){
r.sleep();
Mat frame, frame_gray;
frame = MyNode.current_frame;
if (frame.empty())
break;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
// calculate optical flow
vector<uchar> status;
vector<float> err;
TermCriteria criteria = TermCriteria((TermCriteria::COUNT) + (TermCriteria::EPS), 10, 0.03);
calcOpticalFlowPyrLK(old_gray, frame_gray, p0, p1, status, err, Size(15,15), 2, criteria);
vector<Point2f> good_new;
for(uint i = 0; i < p0.size(); i++)
{
// Select good points
if(status[i] == 1) {
good_new.push_back(p1[i]);
// draw the tracks
line(mask,p1[i], p0[i], colors[i], 2);
circle(frame, p1[i], 5, colors[i], -1);
}
}
Mat img;
add(frame, mask, img);
imshow(OPENCV_WINDOW, img);
int keyboard = waitKey(30);
if (keyboard == 'q' || keyboard == 27)
break;
// Now update the previous frame and previous points
old_gray = frame_gray.clone();
p0 = good_new;
ros::spinOnce();
}
return 0;
}

opencv in c++ - findContours exception

I am working with visual-studio and opencv lib and I have been trying to use findContours() but no matter what parameters I give the function it always triggers a break-point,
I have tried to make the image binary (b&w), reinstalling the library in different versions, messing with the linker preferences and anything I'v found on the web.
(this code is one of many i found on the web - they all crush one they get to findContours)
Does anyone know how to solve this problem ?
#include <iostream>
#include <vector>
#include "opencv2/opencv.hpp"
using namespace cv;
using std::vector;
int main()
{
vector<vector<cv::Point>> contours = vector<vector<cv::Point>>();
vector<Vec4i> hierarchy;
Mat frame, cont, threshold_;
VideoCapture capture = VideoCapture(0);
if (!capture.isOpened())
{
return -1;
}
while (true)
{
capture >> frame;
if (frame.empty()) break;
cont = frame.clone();
cvtColor(cont, cont, COLOR_BGR2GRAY);
cv::threshold(cont, cont, 128, 255, THRESH_BINARY);
threshold_ = cont.clone();
findContours(cont, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
for (unsigned int i = 0; i < contours.size(); i++)
{
drawContours(frame, contours, i, Scalar(0, 0, 255), 2);
}
imshow("Contour", threshold_);
imshow("Video", frame);
if (cv::waitKey(30) == 'q')
{
break;
}
}
return 0;
}

OpenCV Buffer Overflow

I've got myself in a pickle on this project I'm working on. My main objective is to stitch two webcam feeds together and do object detection on them - bounding boxes, etc...the standard stuff.
I can't rid myself of buffer overflows though - the somewhat simplified code below (for readability) compiles x64 and soon after I get a buffer overflow error and this in the console:
"OpenCV Error: Assertion Failed (contour.checkVector(2) >= 0 && (contour.depth() == CV_32F || CV_32S) in unknown function, file...."
If comment out all of the lines that have to do with contours (from findContours to drawBoundingBoxes in main) it compiles and runs fine until I hit the spacebar to stop the program, and then I get another buffer overflow error. I get the same errors when I compile x32 as well, for the record.
Any help? Relevant code/pseudo-code pasted below:
// **defines.h**
//Definitions for anything in all caps, like WIDTH, HEIGHT, ERODEIT, etc...
// **protos.h**
// All function prototypes, nothing else
// **detection.cpp**
/* This is the code that related to background subtraction operations*/
#include <opencv2/opencv.hpp>
#include <iostream>
#include "defines.h"
using namespace std;
using namespace cv;
void initBackgroundSubtractor(BackgroundSubtractorMOG2 &bSub)
{
bSub.set("detectShadows", 1);
}
Mat doBackgroundSubtract(BackgroundSubtractorMOG2 &bSub, Mat panorama)
{
Mat foreground;
bSub.operator()(panorama, foreground);
erode(foreground, foreground, Mat(), Point(-1, -1), ERODEIT, BORDER_DEFAULT);
dilate(foreground, foreground, Mat(), Point(-1, -1), DILATEIT, BORDER_DEFAULT);
return foreground;
}
// **contourOps.cpp**
/* Functions that operate on, filter, or relate to OpenCV contours vectors */
#include <opencv2/opencv.hpp>
#include <vector>
#include <fstream>
#include "defines.h"
using namespace std;
using namespace cv;
/* Returns the centroid of a contour */
Point getCentroid(vector<Point> contour)
{
Point centroid;
Moments m;
m = moments(contour, false);
centroid.x = int(m.m10/m.m00);
centroid.y = int(m.m01/m.m00);
return centroid;
}
/* Draws a rectangle around a contour */
void drawBoundingBoxes(vector<vector<Point>> contours, Mat &img)
{
vector<Rect> boundRect(contours.size());
for(unsigned int j = 0; j < contours.size(); j++)
{
boundRect[j] = boundingRect(contours[j]);
rectangle(img, boundRect[j], Scalar(153,0,76), 2, 8, 0);
}
}
/* Removes contours from a vector if they're smaller than the argument "area" */
void contourSizeTrim (vector<vector<Point>> &contours, int area)
{
vector<vector<Point>>::iterator i = contours.begin();
while(i != contours.end())
{
if(contourArea(*i, false) < area)
i = contours.erase(i);
else
i++;
}
}
/* Removes contours from a vector if they're X % smaller than largest contour in vector */
void contourRelSizeTrim(vector<vector<Point>> &contours, int percent)
{
double maxArea = 0.0;
for(unsigned int i=0; i<contours.size(); i++)
{
if (contourArea(contours[i], false) > maxArea)
maxArea = contourArea(contours[i], false);
}
vector<vector<Point>>::iterator j = contours.begin();
while(j != contours.end())
{
if (contourArea(*j, false) < (double)(percent/100.0)*maxArea)
j = contours.erase(j);
else
j++;
}
}
// **realtimestitch.cpp**
#include <opencv2/opencv.hpp>
#include <opencv2/stitching/stitcher.hpp>
#include <vector>
#include <iostream>
#include "defines.h"
using namespace std;
using namespace cv;
void initStitcher(VideoCapture &capture1, VideoCapture &capture2, Stitcher &stitch)
{
capture1.set(CV_CAP_PROP_FRAME_WIDTH, WIDTH);
capture1.set(CV_CAP_PROP_FRAME_HEIGHT, HEIGHT);
capture2.set(CV_CAP_PROP_FRAME_WIDTH, WIDTH);
capture2.set(CV_CAP_PROP_FRAME_HEIGHT, HEIGHT);
detail::OrbFeaturesFinder *featureFinder = new detail::OrbFeaturesFinder(Size(3,1), 1000, 1.5f, 4);
stitch.setFeaturesFinder (featureFinder);
}
void calcCamTransform(VideoCapture &capture1, VideoCapture &capture2, Stitcher &stitch)
{
int64 t;
Mat fr1, fr2, copy1, copy2;
vector<Mat> imgs;
capture1 >> fr1;
capture2 >> fr2;
fr1.copyTo(copy1);
fr2.copyTo(copy2);
imgs.push_back(copy1);
imgs.push_back(copy2);
stitch.estimateTransform(imgs);
}
Mat doStitch(VideoCapture &capture1, VideoCapture &capture2, Stitcher &stitch)
{
Mat fr1, fr2, copy1, copy2, panorama;
vector<Mat> imgs;
capture1 >> fr1;
capture2 >> fr2;
fr1.copyTo(copy1);
fr2.copyTo(copy2);
imgs.push_back(copy1);
imgs.push_back(copy2);
Stitcher::Status status = stitch.composePanorama(imgs, panorama);
if (status != Stitcher::OK)
cout << "Error Stitching: Code: " << int(status) << endl;
return panorama;
}
// **main.cpp**
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include "defines.h"
#include "protos.h"
using namespace cv;
int main()
{
bool doTransform = true, doSizeFilter = true, doRelSizeFilter = true;
Mat pano, fGround;
vector<vector<Point>> contours;
VideoCapture cap1(0);
VideoCapture cap2(1);
Stitcher stitcher = Stitcher::createDefault();
BackgroundSubtractorMOG2 bGround;
initStitcher(cap1, cap2, stitcher);
initBackgroundSubtractor(bGround);
while (true)
{
if (doTransform)
{
calcCamTransform(cap1, cap2, stitcher);
doTransform = !doTransform;
}
pano = doStitch(cap1, cap2, stitcher);
fGround = doBackgroundSubtract(bGround, pano);
findContours(fGround, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
if (doSizeFilter)
contourSizeTrim(contours, AREATHRESH);
if (doRelSizeFilter)
contourRelSizeTrim(contours, RELSIZEPERCENT);
drawBoundingBoxes(contours, pano);
imshow("Stitched Image", pano);
if(waitKey(1) >= 0)
break;
}
return 0;
}
This is a problem related to OpenCV and VS2012 - on VS2010, there are no problems, and the code runs perfectly!
My opinion about this is that the contour you are trying to do something with an empty vector of contours. Have you verified that? Try a
if (contours.empty()) continue; // or here you can display the image to see if it is empty or not
I had the same problem because I was trying to give an epty vector to cv::IsContourConvex(...) function (see here).

Slow Video in Object Tracking Script using OpenCV

I wrote a short routine in openCV and C++ to track objects with a webcam. The webcam formulation was speedy with no lag, but before leaving work for the weekend, I recorded a typical sequence to use as a test template while I work until Monday. This and the corresponding change in code somehow make the video play back in really slow motion. Here is the code, opening "Test.avi", ~20 seconds long instead of running a constant stream off of the webcam:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
Mat drawBoundingBoxes (Mat canvasImage, vector<vector<Point>> contours);
int main(int argc, char** argv[])
{
Mat frame;
Mat back;
Mat fGround;
BackgroundSubtractorMOG2 bGround;
bGround.nmixtures = 3;
//bGround.nShadowDetection = 0;
bGround.fTau = .5;
VideoCapture cap;
cap.open("Test.avi");
if (!cap.isOpened())
{
cout << "Can't open video" << endl;
return -1;
}
vector<vector<Point>> contours;
namedWindow("video", CV_WINDOW_AUTOSIZE);
while (true)
{
static int count = 1;
cap >> frame;
if (frame.empty())
break;
bGround.operator()(frame, fGround);
bGround.getBackgroundImage(back);
erode(fGround, fGround, Mat(), Point(-1,-1), 2, BORDER_DEFAULT);
dilate(fGround, fGround, Mat(), Point(-1,-1), 10, BORDER_DEFAULT);
if (count > 50)
{
findContours(fGround, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(frame, contours, -1, Scalar(239,255,0), 2);
drawBoundingBoxes(frame, contours);
}
imshow("video", frame);
if(waitKey(30) >= 0)
break;
count++;
}
return 0;
}
Mat drawBoundingBoxes (Mat canvasImage, vector<vector<Point>> contours)
{
vector<Rect> boundRect(contours.size());
for (int i=0; i<contours.size(); i++)
{
boundRect[i] = boundingRect(contours[i]);
rectangle(canvasImage, boundRect[i], Scalar(153,0,76), 2, 8, 0);
}
return canvasImage;
}
Any ideas? Memory Leak somewhere? Thanks,
-Tony
I believe your recorded video has a higher framerate than that your PC can process real time. It's not a problem with a webcam as it just drops the frames. You could try to decrease the delay in the waitKey() procedure and see if that helps.