Opencv app crashes when using external camera - opencv

was using contours for object identification. The code worked well with images and I modified the code to identify objects in real time with camera input. Things work well with my laptop's integrated cam but crashes after a few seconds when using an external camera. The external camera worked fine with a few other applications I developed using opencv. The camera is a 20MP camera. Please look at the code and help me figure out what might be wrong. My processor is good enough to handle images with high resolutions. It seems that the app crashes when I introduce an object in front of the cam which was not there before when the app started up.
include <iostream>
include "opencv2/highgui/highgui.hpp"
include "opencv2/imgproc/imgproc.hpp"
using namespace cv; using namespace std;
int main()
{
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
int x = 0;
int y = 0;
VideoCapture xps(0);
Mat src;
while (1)
{
xps.read(src);
vector<vector<Point>> contours; // Vector for storing contour
vector<Vec4i> hierarchy;
Mat thr(src.rows, src.cols, CV_8UC1);
Mat dst(src.rows, src.cols, CV_8UC1, Scalar::all(0));
cvtColor(src, thr, CV_BGR2GRAY); //Convert to gray
threshold(thr, thr, 80, 255, THRESH_BINARY_INV);
findContours(thr, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
for (int i = 0; i< contours.size(); i++) // iterate through each contour.
{
double a = contourArea(contours[i], false); // Find the area of contour
if (a>largest_area)
{
largest_area = a;
largest_contour_index = i;
bounding_rect = boundingRect(contours[i]);
}
}
Scalar color(255, 255, 255);
drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy);
rectangle(src, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);
x = bounding_rect.x + bounding_rect.width / 2;
y = bounding_rect.y + bounding_rect.height / 2;
circle(src, Point(x, y), 1, Scalar(0, 0, 255));
imshow("src", src);
imshow("largest Contour", dst);
waitKey(2);
}
}

I believe the crashes are due the contours which might not be found. To avoid this problem, use a flag and if the contours are found, then draw them.
bool found = findContours(thr, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
/* for loop */
if(found)
{
drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy);
rectangle(src, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);
x = bounding_rect.x + bounding_rect.width / 2;
y = bounding_rect.y + bounding_rect.height / 2;
circle(src, Point(x, y), 1, Scalar(0, 0, 255));
}

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:

Bounding a foreground object

I want to bound the foreground object by a rectangle, how shall I go about doing it?
I tried bounding the rectangle by collecting the white pixels , but it bounds the whole screen...
How shall I solve this problem?
//defined later
vector<Point> points;
RNG rng(12345);
int main(int argc, char* argv[])
{
//create GUI windows
namedWindow("Frame");
namedWindow("FG Mask MOG 2");
pMOG2 = createBackgroundSubtractorMOG2();
VideoCapture capture(0);
//update the background model
pMOG2->apply(frame, fgMaskMOG2);
frame_check = fgMaskMOG2.clone();
erode(frame_check, frame_check, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
dilate(frame_check, frame_check, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// Detect edges using Threshold
//threshold(frame_check, frame_check, 100, 255, THRESH_BINARY);
//find contours
findContours(frame_check, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
//points
for (size_t i = 0; i < contours.size(); i++) {
for (size_t j = 0; j < contours[i].size(); j++) {
if (contours[i].size() > 2000)
{
cv::Point p = contours[i][j];
points.push_back(p);
}
}
}
if (points.size() > 0){
Rect brect = cv::boundingRect(cv::Mat(points).reshape(2));
rectangle(frame, brect.tl(), brect.br(), CV_RGB(0, 255, 0), 2, CV_AA);
cout << points.size() << endl;
}
imshow("Frame", frame);
imshow("FG Mask MOG 2", fgMaskMOG2);
//get the input from the keyboard
keyboard = waitKey(1000);
}
}
Try this, it's from a project I am working on. To isolate objects I use color masks, which produce binary images, but in your case with a proper threshold on the foreground image (after filtering) you can achieve the same result.
// Morphological opening
erode(binary, binary, getStructuringElement(MORPH_ELLIPSE, filterSize));
dilate(binary, binary, getStructuringElement(MORPH_ELLIPSE, filterSize));
// Morphological closing
dilate(binary, binary, getStructuringElement(MORPH_ELLIPSE, filterSize));
erode(binary, binary, getStructuringElement(MORPH_ELLIPSE, filterSize));
// Find contours
vector<vector<Point>> contours;
findContours(binary, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
vector<Rect> rectangles;
for(auto& contour : contours)
{
// Produce a closed polygon with object's contours
vector<Point> polygon;
approxPolyDP(contour, polygon, 3, true);
// Get polygon's bounding rectangles
Rect rect = boundingRect(polygon);
rectangles.push_back(rect);
}
This is a small example on how to draw a bounding box around the foreground objects using the points of the contour. It's with OpenCV 2.9, so you probably need to change the initialization of the BackgroundSubtractorMOG2 if you're using OpenCV 3.0.
#include <opencv2\opencv.hpp>
using namespace cv;
int main(int argc, char *argv[])
{
BackgroundSubtractorMOG2 bg = BackgroundSubtractorMOG2(30, 16.0, false);
VideoCapture cap(0);
Mat3b frame;
Mat1b fmask;
for (;;)
{
cap >> frame;
bg(frame, fmask, -1);
vector<vector<Point>> contours;
findContours(fmask.clone(), contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE);
for(int i=0; i<contours.size(); ++i)
{
if(contours[i].size() > 200)
{
Rect roi = boundingRect(contours[i]);
drawContours(frame, contours, i, Scalar(0,0,255));
rectangle(frame, roi, Scalar(0,255,0));
}
}
imshow("frame", frame);
imshow("mask", fmask);
if (cv::waitKey(30) >= 0) break;
}
return 0;
}

Disparity map colors are backwards in opencv

My problem is that the colors in my disparity map are backwards. As in the farther away things are lighter than the things closer to the camera.
I have tried many things (i.e. convertTo, convertScaleAbs, and various combinations of values in them, etc.) and cannot seem to get the colors in the disparity map to reverse (i.e. be normal - where things closer are lighter than things farther away).
I need some help in doing that.
Also, out of curiosity, how can i change the color space of the disparity map to be like the colorful ones in MATLAB that I see online?
Here's my code and also on pastebin. http://pastebin.com/E3vVN6UU
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
void show(const char* windowname, Mat image)
{
namedWindow(windowname, CV_WINDOW_AUTOSIZE);
imshow(windowname, image);
}
int main()
{
Mat image1, image2;
Mat camMat1 = (Mat_<double>(3,3) << 793.1338, 0, 337.2309, 0, 792.0555, 256.9991, 0, 0, 1);
Mat camMat2 = (Mat_<double>(3,3) << 799.1271, 0, 319.8581, 0, 797.2460, 243.4638, 0, 0, 1);
Mat dispCoeffs1 = (Mat_<double>(1,5) << 0.0033, -0.1320, -0.0019, 0.0026, 0);
Mat dispCoeffs2 = (Mat_<double>(1,5) << -0.0109, -0.0188, -0.0014, -0.0055, 0);
Mat RotMat = (Mat_<double>(3,3) << 0.9998, -0.0023, 0.0221, 0.0022, 1, 0.0031, -0.0221, -0.0031, 0.9998);
Mat TransMat = (Mat_<double>(3,1) << 374.2306, -1.8319, 5.5745);
//Rectify
Mat R1, R2, P1, P2, Q;
stereoRectify(camMat1, dispCoeffs1, camMat2, dispCoeffs2, Size(640,480), RotMat, TransMat, R1, R2, P1, P2, Q, CV_CALIB_ZERO_DISPARITY, 1, Size(640,480));
//Define the mapping to the done
Mat rx1, ry1;
Mat rx2, ry2;
initUndistortRectifyMap(camMat1, dispCoeffs1, R1, P1, Size(640,480), CV_16SC2, rx1, ry1);
initUndistortRectifyMap(camMat2, dispCoeffs2, R2, P2, Size(640,480), CV_16SC2, rx2, ry2);
//SET THE BM STATE VARIABLES BEGIN - DONE GLOBALLY
StereoBM bm;
bm.state->preFilterSize = 31;
bm.state->preFilterCap = 63;
bm.state->SADWindowSize = 9;
bm.state->minDisparity = -128;
//bm.state->disp12MaxDiff = 2;
bm.state->numberOfDisparities = 128;
bm.state->textureThreshold = 50;
bm.state->uniquenessRatio = 15;
bm.state->speckleWindowSize = 100;
bm.state->speckleRange = 16;
//SET THE BM STATE VARIABLES END
VideoCapture cap3 = VideoCapture(0);
VideoCapture cap4 = VideoCapture(1);
//cap3.set(CV_CAP_PROP_FRAME_WIDTH, 320);
//cap3.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
//cap4.set(CV_CAP_PROP_FRAME_WIDTH, 320);
//cap4.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
cap3 >> image1;
cap4 >> image2;
Size imageSize = image1.size();
Mat gray_image1;
Mat gray_image2;
Mat frame1r;
//frame1r.create(image1.size(), CV_8U);
Mat frame2r;
//frame2r.create(image2.size(), CV_8U);
Mat frame1rf;
Mat frame2rf;
//Mat disp(image1.size(), CV_16S);
//Mat vdisp(image1.size(), CV_8U);
Mat disp, vdisp;
//Mat image3d(image1.size(), CV_32FC3);
Mat image3d;
Mat rectified_pair;
rectified_pair.create(imageSize.height, (imageSize.width)*2, CV_8UC3);
//Actually do the mapping -- based on the mapping definition
while(1)
{
bm.state->preFilterSize = 31;
bm.state->preFilterCap = 63;
bm.state->SADWindowSize = 21;
bm.state->minDisparity = -128;
//bm.state->disp12MaxDiff = 2;
bm.state->numberOfDisparities = 64;
bm.state->textureThreshold = 20;
bm.state->uniquenessRatio = 10;
bm.state->speckleWindowSize = 100;
bm.state->speckleRange = 32;
cvtColor(image1, gray_image1, CV_BGR2GRAY);
cvtColor(image2, gray_image2, CV_BGR2GRAY);
remap(gray_image1, frame1r, rx1, ry1, CV_INTER_LINEAR);
remap(gray_image2, frame2r, rx2, ry2, CV_INTER_LINEAR);
bm(frame1r, frame2r, disp);
normalize(disp, vdisp, 0, 255, NORM_MINMAX, CV_8U);
//convertScaleAbs(vdisp, vdisp, 1, 0);
disp.convertTo(vdisp, CV_8U, 255/(64*16.));
show("disparity", vdisp);
//reprojectImageTo3D(disp, image3d, Q, true);
//show("depth map", image3d);
//display image side by side for rectified window
//copy frame1r to the left side
cvtColor(frame1r, frame1rf, CV_GRAY2BGR);
frame1rf.copyTo(rectified_pair(Rect(0,0,imageSize.width, imageSize.height)));
//copy frame2r to the right side
cvtColor(frame2r, frame2rf, CV_GRAY2BGR);
frame2rf.copyTo(rectified_pair(Rect(imageSize.width,0,imageSize.width, imageSize.height)));
for(int i=0; i<imageSize.height; i+=32)
line(rectified_pair, Point(0,i), Point((imageSize.width)*2, i), CV_RGB(0,255,0));
show("rectified", rectified_pair);
cap3 >> image1;
cap4 >> image2;
if(waitKey(15) == 27)
break;
}
return 0;
}
I'm not using stereo pairs but get the same result using Kinect - far = light, near = dark
To change this I have used the below :
double min, max;
minMaxLoc(depthImage, &min, &max);
depthImage.convertTo(rImage, CV_8U, -255.0/max, 255);
I was facing the same problem then I tried swapping right and left images,and it worked!
Now I am getting correct image.

Color detection on HoughCircles using OpenCV

I have detected 22 balls and am struggling to find a way to run a color detection algorithm on these circles to get their colors. I am using HoughCircles to detect the circles but don't know how to check what color these circles are?
Source Code:
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <math.h>
int main(int argc, char** argv)
{
//load image from directory
IplImage* img = cvLoadImage("C:\\Users\\Nathan\\Desktop\\SnookerPic.png");
IplImage* gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
CvMemStorage* storage = cvCreateMemStorage(0);
//covert to grayscale
cvCvtColor(img, gray, CV_BGR2GRAY);
// This is done so as to prevent a lot of false circles from being detected
cvSmooth(gray, gray, CV_GAUSSIAN, 7, 7);
IplImage* canny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
IplImage* rgbcanny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
cvCanny(gray, canny, 50, 100, 3);
//detect circles
CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, 35.0, 75, 60,0,0);
cvCvtColor(canny, rgbcanny, CV_GRAY2BGR);
//draw all detected circles
for (int i = 0; i < circles->total; i++)
{
// round the floats to an int
float* p = (float*)cvGetSeqElem(circles, i);
cv::Point center(cvRound(p[0]), cvRound(p[1]));
int radius = cvRound(p[2]);
cvScalar c = cvGet2D(center.x, center.y);//colour of circle
// draw the circle center
cvCircle(img, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(img, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
//display coordinates
printf("x: %d y: %d r: %d\n",center.x,center.y, radius);
}
//create window
cvNamedWindow("circles", 1);
cvNamedWindow("SnookerImage", 1);
//show image in window
cvShowImage("circles", rgbcanny);
cvShowImage("SnookerImage", img);
cvSaveImage("out.png", rgbcanny);
cvWaitKey(0);
return 0;
}
If the balls each have a uniform color, you can check the color at the center:
CvMemStorage* storage = cvCreateMemStorage(0);
cvSmooth(image, image, CV_GAUSSIAN, 5, 5 );
CvSeq* results = cvHoughCircles(
image,
storage,
CV_HOUGH_GRADIENT,
2,
image->width/10
);
for( int i = 0; i < results->total; i++ )
{
float* p = (float*) cvGetSeqElem( results, i );
CvPoint center = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
CvScalar c = cvGet2D(image, center.x, center.y); //color of the center
}
Haven't tested the code but it should be ok.
EDIT:
Ooops, I forgot one parameter from the Get2D method, the actual image from which to get the color. Changed to the correct form.
We have written our own blob detection library in the open source vision framework:
http://www.simplecv.org
The code to do what you want is as easy as:
img = Image("/path/to/image.png")
blobs = img.findBlobs()
circle_blobs = blobs.filter(blobs.isCircle() == True)
list_of_blobs_colors = circle_blobs.meanColor()

Not detecting multiple circles in Image

My code is straightforward. i am trying to detect 22 balls but ionly getting a few. I think it has something to do with the CvSeq* circles = cvHoughCircles Can anyone help me please and thank you!
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <math.h>
int main(int argc, char** argv)
{
IplImage* img = cvLoadImage("C:\\Users\\Nathan\\Desktop\\SnookerPic.png");
IplImage* gray = cvCreateImage
(cvGetSize(img), IPL_DEPTH_8U, 1);
CvMemStorage* storage = cvCreateMemStorage(0);
cvCvtColor(img, gray, CV_BGR2GRAY);
// This is done so as to prevent a lot of false circles from being detected
cvSmooth(gray, gray, CV_GAUSSIAN, 7, 7);
IplImage* canny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
IplImage* rgbcanny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
cvCanny(gray, canny, 50, 100, 3);
CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, 40.0, 100, 100,0,0);
cvCvtColor(canny, rgbcanny, CV_GRAY2BGR);
for (int i = 0; i < circles->total; i++)
{
// round the floats to an int
float* p = (float*)cvGetSeqElem(circles, i);
cv::Point center(cvRound(p[0]), cvRound(p[1]));
int radius = cvRound(p[2]);
// draw the circle center
cvCircle(img, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(img, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
printf("x: %d y: %d r: %d\n",center.x,center.y, radius);
}
cvNamedWindow("circles", 1);
cvNamedWindow("Image", 1);
cvShowImage("circles", rgbcanny);
cvShowImage("Image", img);
cvSaveImage("out.png", rgbcanny);
cvWaitKey(0);
return 0;
}
I believe that the problem comes from your cvHoughCircles parameters:
CvSeq* cvHoughCircles(CvArr* image, CvMemStorage* circleStorage, int method, double dp, double minDist, double param1=100, double param2=100, int minRadius=0, int maxRadius=0 )
minDist – Minimum distance between the centers of the detected circles. If the parameter is too small, multiple neighbor circles may be falsely detected in addition to a true one. If it is too large, some circles may be missed.
You are using maybe a too large minDist (in your case max 2-3 balls will be detected vertically and probably also horizontally).

Resources