Simple object detection using OpenCV and machine learning - c++

I have to code an object detector (in this case, a ball) using OpenCV. The problem is, every single search on google returns me something with FACE DETECTION in it. So i need help on where to start, what to use etc..
Some info:
The ball doesn't have a fixed color, it will probably be white, but it might change.
I HAVE to use machine learning, doesn't have to be a complex and reliable one, suggestion is KNN (which is WAY simpler and easier).
After all my searching, i found that calculating the histogram of samples ball-only images and teaching it to the ML could be useful, but my main concern here is that the ball size can and will change (closer and further from the camera) and i have no idea on what to pass to the ML to classify for me, i mean.. i can't (or can I?) just test every pixel of the image for every possible size (from, lets say, 5x5 to WxH) and hope to find a positive result.
There might be a non-uniform background, like people, cloth behind the ball and etc..
As I said, i have to use a ML algorithm, that means no Haar or Viola algorithms.
Also, I thought on using contours to find circles on a Canny'ed image, just have to find a way to transform a contour into a row of data to teach the KNN.
So... suggestions?
Thanks in advance.
;)

Well, basically you need to detect circles. Have you seen cvHoughCircles()? Are you allowed to use it?
This page has good info on how detecting stuff with OpenCV. You might be more interested on section 2.5.
This is a small demo I just wrote to detect coins in this picture. Hopefully you can use some part of the code to your advantage.
Input:
Outputs:
// compiled with: g++ circles.cpp -o circles `pkg-config --cflags --libs opencv`
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <math.h>
int main(int argc, char** argv)
{
IplImage* img = NULL;
if ((img = cvLoadImage(argv[1]))== 0)
{
printf("cvLoadImage failed\n");
}
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, gray->height/3, 250, 100);
cvCvtColor(canny, rgbcanny, CV_GRAY2BGR);
for (size_t 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(rgbcanny, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(rgbcanny, 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);
cvShowImage("circles", rgbcanny);
cvSaveImage("out.png", rgbcanny);
cvWaitKey(0);
return 0;
}
The detection of the circles depend a lot on the parameters of cvHoughCircles(). Note that in this demo I used Canny as well.

Related

OpenCV FAST Algorithm creating skewed keypoints on only part of an image

I'm trying to use OpenCV's FAST corner detection algorithm to get an outline of an image of a ball (Not my final project, I'm using it as a simple example). For some reason, it only works on a third of the input Mat, and stretches the Keypoints across the image. I'm not sure as to what could be going wrong here to make the FAST algorithm not apply to the entire Mat.
Code:
void featureDetection(const Mat& imgIn, std::vector<KeyPoint>& pointsOut) {
int fast_threshold = 20;
bool nonmaxSuppression = true;
FAST(imgIn, pointsOut, fast_threshold, nonmaxSuppression);
}
int main(int argc, char** argv) {
Mat out = imread("ball.jpg", IMREAD_COLOR);
// Detect features
std::vector<KeyPoint> keypoints;
featureDetection(out.clone(), keypoints);
Mat out2 = out.clone();
// Draw features (Normal, missing right side)
for(KeyPoint p : keypoints) {
drawMarker(out, Point(p.pt.x / 3, p.pt.y), Scalar(0, 255, 0));
}
imwrite("out.jpg", out, std::vector<int>(0));
// Draw features (Stretched)
for(KeyPoint p : keypoints) {
drawMarker(out2, Point(p.pt.x, p.pt.y), Scalar(127, 0, 255));
}
imwrite("out2.jpg", out2, std::vector<int>(0));
}
Input image
Output 1 (keypoint.x multiplied by a factor of 1/3, but missing right side)
Output 2 (Coordinates untouched)
I'm using OpenCV 4.5.4 on MinGW.
Most keypoint detectors use grayscale images as input.
If you interpret the memory of a bgr image as grayscale, you will have 3 times the number of pixels. Y axis is still ok if the algorithm uses the width-offset per row, which most algorithms do (because this is useful when subimaging or padding is used).
I don't know whether it is a bug or a feature, that FAST doesn't check for the number of channels snd doesnt throw an exception if the wrong number of channels ist given.
You can convert the image to grayscale by cv::cvtColor with the flag cv:: COLOR_BGR2GRAY

opencv - shrink objects to pixels

I am processing such an image as shown in Fig.1, which is composed of an array of points and required to convert to Fig. 2.
Fig.1 original image
Fig.2 wanted image
In order to finish the conversion, firstly I detect the edge of every point and then operate dilation. The result is satisfactory after choosing the proper parameters, seen in Fig. 3.
Fig.3 image after dilation
I processed the same image before in MATLAB. When it comes to shrink objects (in Fig.3) to pixels, function bwmorph(Img,'shrink',Inf) works and the result is exactly where Fig. 2 comes from. So how to get the same wanted image in opencv? It seems that there is no similar shrink function.
Here is my code of finding edge and dilation operation:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
using namespace cv;
// Global variables
Mat src, dilation_dst;
int dilation_size = 2;
int main(int argc, char *argv[])
{
IplImage* img = cvLoadImage("c:\\001a.bmp", 0); // 001a.bmp is Fig.1
// Perform canny edge detection
cvCanny(img, img, 33, 100, 3);
// IplImage to Mat
Mat imgMat(img);
src = img;
// Create windows
namedWindow("Dilation Demo", CV_WINDOW_AUTOSIZE);
Mat element = getStructuringElement(2, // dilation_type = MORPH_ELLIPSE
Size(2*dilation_size + 1, 2*dilation_size + 1),
Point(dilation_size, dilation_size));
// Apply the dilation operation
dilate(src, dilation_dst, element);
imwrite("c:\\001a_dilate.bmp", dilation_dst);
imshow("Dilation Demo", dilation_dst);
waitKey(0);
return 0;
}
1- Find all the contours in your image.
2- Using moments find their center of masses. Example:
/// Get moments
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ mu[i] = moments( contours[i], false ); }
/// Get the mass centers:
vector<Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
{ mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); }
3- Create zero(black) image and write all the center points on it.
4- Note that you will have extra one or two points coming from border contours. Maybe you can apply some pre-filtering according to the contour areas, since the border is a big connected contour having large area.
It's not very fast, but I implemented the morphological filtering algorithm from Digital Image Processing, 4th Edition by William K. Pratt. This should be exactly what you're looking for.
The code is MIT licensed and available on GitHub at cgmb/shrink.
Specifically, I've defined cv::Mat cgmb::shrink_max(cv::Mat in) to shrink a given cv::Mat of CV_8UC1 type until no further shrinking can be done.
So, if we compile Shrink.cxx with your program and change your code like so:
#include "Shrink.h" // add this line
...
dilate(src, dilation_dst, element);
dilation_dst = cgmb::shrink_max(dilation_dst); // and this line
imwrite("c:\\001a_dilate.bmp", dilation_dst);
We get this:
By the way, your image revealed a bug in Octave Image's implementation of bwmorph shrink. Figure 2 should not be the result of a shrink operation on Figure 3, as the ring shouldn't be broken by a shrink operation. If that ring disappeared in MATLAB, it presumably also suffers from some sort of similar bug.
At present, Octave and I have slightly different results from MATLAB, but they're pretty close.

Image differencing: How to find minor differences between images?

i want to find hwo to get diff b/w 2 similar grayscale images for implementation in system for security purposes. I want to check whether any difference has occurred between them. For object tracking, i have implementd canny detection in the program below. I get outline of structured objects easily.. which cn later be subtracted to give only the outline of the difference in the delta image....but what if there's a non structural difference such as smoke or fire in the second image? i have increased the contrast for clearer edge detection as well have modified threshold vals in the canny fn parameters..yet got no suitable results.
also canny edge detects shadows edges too. if my two similar image were taken at different times during the day, the shadows will vary, so the edges will vary and will give undesirable false alarm
how should i work around this? Can anyone help? thanks!
Using c language api in enter code hereopencv 2.4 in visual studio 2010
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
#include <math.h>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main()
{
IplImage* img1 = NULL;
if ((img1 = cvLoadImage("libertyH1.jpg"))== 0)
{
printf("cvLoadImage failed\n");
}
IplImage* gray1 = cvCreateImage(cvGetSize(img1), IPL_DEPTH_8U, 1); //contains greyscale //image
CvMemStorage* storage1 = cvCreateMemStorage(0); //struct for storage
cvCvtColor(img1, gray1, CV_BGR2GRAY); //convert to greyscale
cvSmooth(gray1, gray1, CV_GAUSSIAN, 7, 7); // This is done so as to //prevent a lot of false circles from being detected
IplImage* canny1 = cvCreateImage(cvGetSize(gray1),IPL_DEPTH_8U,1);
IplImage* rgbcanny1 = cvCreateImage(cvGetSize(gray1),IPL_DEPTH_8U,3);
cvCanny(gray1, canny1, 50, 100, 3); //cvCanny( const //CvArr* image, CvArr* edges(output edge map), double threshold1, double threshold2, int //aperture_size CV_DEFAULT(3) );
cvNamedWindow("Canny before hough");
cvShowImage("Canny before hough", canny1);
CvSeq* circles1 = cvHoughCircles(gray1, storage1, CV_HOUGH_GRADIENT, 1, gray1->height/3, 250, 100);
cvCvtColor(canny1, rgbcanny1, CV_GRAY2BGR);
cvNamedWindow("Canny after hough");
cvShowImage("Canny after hough", rgbcanny1);
for (size_t i = 0; i < circles1->total; i++)
{
// round the floats to an int
float* p = (float*)cvGetSeqElem(circles1, i);
cv::Point center(cvRound(p[0]), cvRound(p[1]));
int radius = cvRound(p[2]);
// draw the circle center
cvCircle(rgbcanny1, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(rgbcanny1, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
printf("x: %d y: %d r: %d\n",center.x,center.y, radius);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
IplImage* img2 = NULL;
if ((img2 = cvLoadImage("liberty_wth_obj.jpg"))== 0)
{
printf("cvLoadImage failed\n");
}
IplImage* gray2 = cvCreateImage(cvGetSize(img2), IPL_DEPTH_8U, 1);
CvMemStorage* storage = cvCreateMemStorage(0);
cvCvtColor(img2, gray2, CV_BGR2GRAY);
// This is done so as to prevent a lot of false circles from being detected
cvSmooth(gray2, gray2, CV_GAUSSIAN, 7, 7);
IplImage* canny2 = cvCreateImage(cvGetSize(img2),IPL_DEPTH_8U,1);
IplImage* rgbcanny2 = cvCreateImage(cvGetSize(img2),IPL_DEPTH_8U,3);
cvCanny(gray2, canny2, 50, 100, 3);
CvSeq* circles2 = cvHoughCircles(gray2, storage, CV_HOUGH_GRADIENT, 1, gray2->height/3, 250, 100);
cvCvtColor(canny2, rgbcanny2, CV_GRAY2BGR);
for (size_t i = 0; i < circles2->total; i++)
{
// round the floats to an int
float* p = (float*)cvGetSeqElem(circles2, i);
cv::Point center(cvRound(p[0]), cvRound(p[1]));
int radius = cvRound(p[2]);
// draw the circle center
cvCircle(rgbcanny2, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(rgbcanny2, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
printf("x: %d y: %d r: %d\n",center.x,center.y, radius);
}
You want code help here? This is not an easy task. There are few algorithms available in internet or you can try to invent new one. A lot of research is going on this. I have some idea about a process. You can find the edges by Y from YCbCr color system. Deduct this Y value from blurred image's Y value. Then you will get the edge. Now make an array representation. You have to divide the image in blocks. Now check the block with blocks. It may slide, rotated, twisted etc. Compare with array matching. Object tracking is difficult due to background. Take care/omit unnecessary objects carefully.
I think the way to go could be Background subtraction. It lets you cope with lighting conditions changes.
See wikipedia entry for an intro. The basic idea is you have to build a model for the scene background, then all differences are computed relative to the background.
I have done some analysis on Image Differencing but the code was written for java. Kindly look into the below link that may come to help
How to find rectangle of difference between two images
Cheers !

Drawing Bounding-Box using OpenCV in C++ Enviroment

Hello peeps I have developed a piece of software that draws contours of the input image, now I wont to take this to the next level and draw Bounding Box around objects of interest i.e. A person. I looked at boundingRect() function but i am struggling to understand it. Maybe there are different functions algorithms draw Bounding Box.....?
Here is the code of my program:
#include "iostream"
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv\ml.h>
#include<opencv\cxcore.h>
#include <iostream>
#include <string>
#include <opencv2/core/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/highgui/highgui.hpp> // Video write
using namespace cv;
using namespace std;
Mat image; Mat image_gray; Mat image_gray2; Mat threshold_output;
int thresh=100, max_thresh=255;
int main(int argc, char** argv) {
//Load Image
image =imread("C:/Users/Tomazi/Pictures/Opencv/tomazi.bmp");
//Convert Image to gray & blur it
cvtColor( image,
image_gray,
CV_BGR2GRAY );
blur( image_gray,
image_gray2,
Size(3,3) );
//Threshold Gray&Blur Image
threshold(image_gray2,
threshold_output,
thresh,
max_thresh,
THRESH_BINARY);
//2D Container
vector<vector<Point>> contours;
//Fnd Countours Points, (Imput Image, Storage, Mode1, Mode2, Offset??)
findContours(threshold_output,
contours, // a vector of contours
CV_RETR_EXTERNAL,// retrieve the external contours
CV_CHAIN_APPROX_NONE,
Point(0, 0)); // all pixels of each contours
// Draw black contours on a white image
Mat result(threshold_output.size(),CV_8U,Scalar(255));
drawContours(result,contours,
-1, // draw all contours
Scalar(0), // in black
2); // with a thickness of 2
//Create Window
char* DisplayWindow = "Source";
namedWindow(DisplayWindow, CV_WINDOW_AUTOSIZE);
imshow(DisplayWindow, result);
waitKey(5000);
return 1;
}
Can anyone suggest an solution...? Perhaps direct me to some sources, tutorials etc. Reading OpenCV documentation and looking at the boundingRect() function i still dont understand. HELP PLEASE :)
But you can also easily compute the bounding box yourself and then draw them using the rectangle function:
int maxX = 0, minX = image.cols, maxY=0, minY = image.rows;
for(int i=0; i<contours.size(); i++)
for(int j=0; j<contours[i].size(); j++)
{
Point p = contours[i][j];
maxX = max(maxX, p.x);
minX = min(minX, p.x);
maxY = max(maxY, p.y);
minY = min(minY, p.y);
}
rectangle( result, Point(minX,minY), Point(maxX, maxY), Scalar(0) );
This link was not helpful?
I think it demonstrates how to take the contour object and make it a polygon approximation, plus how to draw the bounding rectangle around it.
It seems to be one of the basic OpenCV demos.
I've talked about the bounding box technique in these posts:
How to detect Text Area from image?
Contours opencv : How to eliminate small contours in a binary image
OpenCv 2.3 C - How to isolate object inside image (simple C++ demo)
I think that the last one can probably help you understand how the standard technique works. What OpenCV offers is an easier approach.

OpenCV - HoughCircles causing program to crash

I want to detect circles in an image using OpenCV and C++. I COULD do that by referring to the official documentation and adjusting the parameters of the piece of code written by the OpenCV Team.
So, the code I'm working with is as follows: (parameters already adjusted)
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
int main(int, char** argv)
{
Mat src, src_gray;
/// Read the image
src = imread( argv[1], 1 );
if( !src.data )
{ return -1; }
/// Convert it to gray
cvtColor( src, src_gray, CV_BGR2GRAY );
/// Reduce the noise so we avoid false circle detection
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
vector<Vec3f> circles;
/// Apply the Hough Transform to find the circles
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 6.0, 5, 110, 70, 3, 20 );
/// Draw the circles detected
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][2]));
int radius = cvRound(circles[i][3]);
// circle center
circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
/// Show your results
namedWindow( "Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE );
imshow( "Hough Circle Transform Demo", src );
waitKey(0);
src.release();
src_gray.release();
return 0;
}
And the image whose circles I want to detect is the following: Test image
These are actually the contour of two blobs that I obtained using cvBlobsLib and redrew as a new image.
That algorithm is able to identify the centers of each circle, but, when I hit any key to close the program, it crashes... :( And I have to forcefully close it.
I need to adapt that algorithm to run in a camera, so I cannot proceed with the implementation while it crashes like that.
So, does anyone know what could be causing this problem?
I'm doing the development on Visual Studio 2012 and OpenCV version 2.4.2.
If someone could give me a suggestion of what it could be or maybe try running the algorithm, I would be very grateful!
I have four advices for you.
First: To see whether a Mat is empty or not, you use
if( src.empty() ) // instead of !src.data.
The chances are src.data has random (stale) value for an empty Mat.
Second: correct the indices like this:
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
(actually you don't need cvRound, but whatever).
Third: It is worth to check whether imread understood that you want to load the image in color mode, by checking its number of channels:
src.channels()==3
//or
src.type()==CV_8UC3; // that is what you are counting for, really.
Otherwise a line like CV_BGR2GRAY on a gray image could cause weird behaviour.
Fourth: you don't need to release Mat's. That's the reason they created Mat class in the first place, so that they automatically take care of releasing.
I don't see anything obvious except that you are overrunning the Vec3f bounds:
Point center(cvRound(circles[i][0]), cvRound(circles[i][2]));
int radius = cvRound(circles[i][3]);
Instead of index 2 and 3, I think you meant 1 and 2.
That wouldn't necessarily be causing the crash (by corrupting the stack or heap), but then again it is undefined behaviour...
The other thing I suggest is removing the two lines that follow the waitKey call:
src.release();
src_gray.release();
These are handled automatically by the destructor in the object, so I don't see why you need to do it manually. That might not change a thing, of course.
From there, if you are still getting crashes you should start omitting sections of your code until you can isolate the one that crashes it.
I started feeling suspicious about the environment, so I got a friend who had OpenCV all set up to try out my code and he could run it with no problem...
So I reinstalled everything, but this time I chose Microsoft Visual Studio 2010 SP1 and OpenCV 2.4.3, and it worked correctly.
If someone is having the same problem, I recommend downgrading to VS2010. Also, this video installation guide was really helpful when I was setting the environment!
Thank you :)
I was having the same problem. Please ensure that while running your application in release mode, you are using opencv release dll's. Doing this solved my problem.
Reference:
https://code.ros.org/trac/opencv/ticket/953