hi everybody,
we have implemented a colour detection, as can be seen in the attached code. the problem is, that when moving the object, that shall be detected, reveils a delay of about 3 seconds. we assume the problem is the buffer size of the processed frames is too big.
a solution might be to process only every n-th frame, instead of each. unfortunately I can't access the lab these days, so if someone has further ideas I'm very thankful for every input.
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
#include <math.h>
using namespace cv;
//initial min and max HSV filter values.
//these will be changed using trackbars
int H_MIN = 167;
int H_MAX = 195;
int S_MIN = 121;
int S_MAX = 256;
int V_MIN = 0;
int V_MAX = 256;
//default capture width and height
const int FRAME_WIDTH = 640;
const int FRAME_HEIGHT = 480;
//max number of objects to be detected in frame
const int MAX_NUM_OBJECTS=50;
//minimum and maximum object area
const int MIN_OBJECT_AREA = 5*5;
const int MAX_OBJECT_AREA = FRAME_HEIGHT*FRAME_WIDTH/1.5;
//names that will appear at the top of each window
const string windowName = "Original Image";
const string windowName1 = "HSV Image";
const string windowName2 = "Thresholded Image";
const string windowName3 = "After Morphological Operations";
const string trackbarWindowName = "Trackbars";
// Marker Jump
#define ArraySize 5
int CoordinatesHistory[ArraySize][2];
int CurrentCoordinates[1][2];
int distance = 0;
int radius = 0;
int history = 0;
void on_trackbar( int, void* )
{//This function gets called whenever a
// trackbar position is changed
}
string intToString(int number){
std::stringstream ss;
ss << number;
return ss.str();
}
void createTrackbars(){
//create window for trackbars
createTrackbar( "H_MIN", trackbarWindowName, &H_MIN, H_MAX, on_trackbar );
createTrackbar( "H_MAX", trackbarWindowName, &H_MAX, H_MAX, on_trackbar );
createTrackbar( "S_MIN", trackbarWindowName, &S_MIN, S_MAX, on_trackbar );
createTrackbar( "S_MAX", trackbarWindowName, &S_MAX, S_MAX, on_trackbar );
createTrackbar( "V_MIN", trackbarWindowName, &V_MIN, V_MAX, on_trackbar );
createTrackbar( "V_MAX", trackbarWindowName, &V_MAX, V_MAX, on_trackbar );
}
void drawObject(int x, int y,Mat &frame){
//use some of the openCV drawing functions to draw crosshairs
//on your tracked image!
//UPDATE:JUNE 18TH, 2013
//added 'if' and 'else' statements to prevent
//memory errors from writing off the screen (ie. (-25,-25) is not within the window!)
circle(frame,Point(x,y),20,Scalar(0,255,0),2);
if(y-25>0)
line(frame,Point(x,y),Point(x,y-25),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(x,0),Scalar(0,255,0),2);
if(y+25<FRAME_HEIGHT)
line(frame,Point(x,y),Point(x,y+25),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(x,FRAME_HEIGHT),Scalar(0,255,0),2);
if(x-25>0)
line(frame,Point(x,y),Point(x-25,y),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(0,y),Scalar(0,255,0),2);
if(x+25<FRAME_WIDTH)
line(frame,Point(x,y),Point(x+25,y),Scalar(0,255,0),2);
else line(frame,Point(x,y),Point(FRAME_WIDTH,y),Scalar(0,255,0),2);
putText(frame,intToString(x)+","+intToString(y),Point(x,y+30),1,1,Scalar(0,255,0),2);
}
void morphOps(Mat &thresh){
//create structuring element that will be used to "dilate" and "erode" image.
//the element chosen here is a 3px by 3px rectangle
Mat erodeElement = getStructuringElement( MORPH_RECT,Size(3,3));
//dilate with larger element so make sure object is nicely visible
Mat dilateElement = getStructuringElement( MORPH_RECT,Size(8,8));
erode(thresh,thresh,erodeElement);
erode(thresh,thresh,erodeElement);
dilate(thresh,thresh,dilateElement);
dilate(thresh,thresh,dilateElement);
}
void trackFilteredObject(int &x, int &y, Mat &threshold, Mat &cameraFeed)
{
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
Mat temp;
threshold.copyTo(temp);
double diameter;
// find external contours ignores holes
cv::findContours(temp, contours, hierarchy, CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);
//if number of objects greater than MAX_NUM_OBJECTS we have a noisy filter
if (contours.size() > MAX_NUM_OBJECTS)
{
putText(cameraFeed, "TOO MUCH NOISE! ADJUST FILTER", Point(0, 50), 1, 2, Scalar(0, 0, 255), 2);
return;
}
double refArea = 0;
bool objectFound = false;
//int largest = -1;
for (size_t i = 0; i < contours.size(); i++)
{
cv::Moments moment = moments(contours[i]);
double area = moment.m00;
double perimeter = cv::arcLength(contours[i], true);
diameter = perimeter/(M_PI);
int cx = cvRound(moment.m10 / area);
int cy = cvRound(moment.m01 / area);
if ( area > refArea && area > MIN_OBJECT_AREA && area < MAX_OBJECT_AREA )
{
cv::Point center(cx, cy);
int radius = cvRound(sqrt(area / CV_PI));
// circle center
circle(cameraFeed, center, 3, Scalar(0, 255, 0), -1, 8, 0);
// circle outline
circle(cameraFeed, center, radius, Scalar(255, 0, 0), 3, 8, 0);
// DRAW GREEN CROSS
drawObject(cx, cy, cameraFeed);
objectFound = true;
x = cx;
y = cy;
refArea = area;
}
else
{
objectFound = false;
x = -1;
y = -1;
}
}
//let user know you found an object
if (objectFound == true)
{
//std::cout << "Object Found" << std::endl;
putText(cameraFeed, "Tracking Object", Point(0, 50), 2, 1, Scalar(0, 255, 0), 2);
}
}
int main(int argc, char* argv[])
{
//some boolean variables for different functionality within this
//program
bool trackObjects = true;
bool useMorphOps = true;
//Matrix to store each frame of the webcam feed
Mat cameraFeed;
//matrix storage for HSV image
Mat HSV;
//matrix storage for binary threshold image
Mat threshold;
//x and y values for the location of the object
int x=-1, y=-1;
//create slider bars for HSV filtering
createTrackbars();
//open capture object at location zero (default location for webcam)
VideoCapture capture(0);//
capture.open(0);// open the video file for reading
//set height and width of capture frame
capture.set(CV_CAP_PROP_FRAME_WIDTH,FRAME_WIDTH);
capture.set(CV_CAP_PROP_FRAME_HEIGHT,FRAME_HEIGHT);
//start an infinite loop where webcam feed is copied to cameraFeed matrix
//all of our operations will be performed within this loop
while(1){
auto Start_Time = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
//store image to matrix
capture.read(cameraFeed);
//convert frame from BGR to HSV colorspace
cvtColor(cameraFeed,HSV,COLOR_RGB2HSV);
capture.
//filter HSV image between values and store filtered image to
//threshold matrix
inRange(HSV,Scalar(H_MIN,S_MIN,V_MIN),Scalar(H_MAX,S_MAX,V_MAX),threshold);
//perform morphological operations on thresholded image to eliminate noise
//and emphasize the filtered object(s)
if(useMorphOps)
morphOps(threshold);
for ( int j = ArraySize-1; j < 0;j--)
{
CoordinatesHistory[j][0]=CoordinatesHistory[j-1][0];
CoordinatesHistory[j][1]=CoordinatesHistory[j-1][1];
}
CoordinatesHistory[0][0]=x;
CoordinatesHistory[0][1]=y;
distance = sqrt(pow(x-CoordinatesHistory[history][0],2)+pow(y-CoordinatesHistory[history][1],2));
if (distance >= radius)
{
x = -1;
y = -1;
}
vector<Vec3f> circles;
//pass in thresholded frame to our object tracking function
//this function will return the x and y coordinates of the
//filtered object
if(trackObjects)
trackFilteredObject(x,y,threshold,cameraFeed);
if (x > 0 && y > 0)
{
Vec3b hsv=HSV.at<Vec3b>(y,x);
int H = hsv.val[0];
int S = hsv.val[1];
int V = hsv.val[2];
std::cout << "H: " << H << std::endl;
std::cout << "S: " << S << std::endl;
std::cout << "V: " << V << std::endl;
}
// Functionalty: Check for "Marker-Jumps"
for ( int j = ArraySize-1; j < 0;j--)
{
CoordinatesHistory[j][0]=CoordinatesHistory[j-1][0];
CoordinatesHistory[j][1]=CoordinatesHistory[j-1][1];
}
CoordinatesHistory[0][0]=x;
CoordinatesHistory[0][1]=y;
//show frames
imshow(windowName2,threshold);
imshow(windowName,cameraFeed);
imshow(windowName1,HSV);
//delay 30ms so that screen can refresh.
//image will not appear without this waitKey() command
waitKey(1);
auto End_Time = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
int Duration = End_Time-Start_Time;
int Framerate = 1000/Duration;
std::cout << "Duration:" << Duration << std::endl;
std::cout << "Framerate:"<< Framerate << std::endl;
std::cout << "Coordinates: "<< x <<"/" <<y << std::endl;
}
return 0;
}
best grisi