i am trying to use cvCamShift function in opencv. i have written a class for doing this.this is it's code:
#include <cv.h>
#include <highgui.h>
using namespace std;
class Tracker{
// File-level variables
IplImage * pHSVImg; // the input image converted to HSV color mode
IplImage * pHueImg; // the Hue channel of the HSV image
IplImage * pMask; // this image is used for masking pixels
IplImage * pProbImg; // the face probability estimates for each pixel
CvHistogram * pHist; // histogram of hue in the original face image
CvRect prevFaceRect; // location of face in previous frame
CvBox2D faceBox; // current face-location estimate
int vmin;
int vmax;
int smin;
void updateHueImage(IplImage* pImg);
public:
Tracker(IplImage * pImg, CvRect pFaceRect);
~Tracker();
CvBox2d track(IplImage* pImg);
};
Tracker::Tracker(IplImage * pImg, CvRect pFaceRect){
// File-level variables
int nHistBins = 30; // number of histogram bins
float rangesArr[] = {0,180}; // histogram range
vmin = 10;
vmax = 256;
smin = 55;
float * pRanges = rangesArr;
pHSVImg = cvCreateImage( cvGetSize(pImg), 8, 3 );
pHueImg = cvCreateImage( cvGetSize(pImg), 8, 1 );
pMask = cvCreateImage( cvGetSize(pImg), 8, 1 );
pProbImg = cvCreateImage( cvGetSize(pImg), 8, 1 );
pHist = cvCreateHist( 1, &nHistBins, CV_HIST_ARRAY, &pRanges, 1 );
float maxVal = 0.f;
// Create a new hue image
updateHueImage(pImg);
// Create a histogram representation for the face
cvSetImageROI( pHueImg, pFaceRect );
cvSetImageROI( pMask, pFaceRect );
cvCalcHist( &pHueImg, pHist, 0, pMask );
cvGetMinMaxHistValue( pHist, 0, &maxVal, 0, 0 );
cvConvertScale( pHist->bins, pHist->bins, maxVal? 255.0/maxVal : 0, 0 );
cvResetImageROI( pHueImg );
cvResetImageROI( pMask );
// Store the previous face location
prevFaceRect = pFaceRect;
}
Tracker::~Tracker(){
cvReleaseImage( &pHSVImg );
cvReleaseImage( &pHueImg );
cvReleaseImage( &pMask );
cvReleaseImage( &pProbImg );
cvReleaseHist( &pHist );
}
void Tracker::updateHueImage(IplImage * pImg)
{
// Convert to HSV color model
cvCvtColor( pImg, pHSVImg, CV_BGR2HSV );
// Mask out-of-range values
cvInRangeS( pHSVImg, cvScalar(0, smin, MIN(vmin,vmax), 0),
cvScalar(180, 256, MAX(vmin,vmax) ,0), pMask );
// Extract the hue channel
cvSplit( pHSVImg, pHueImg, 0, 0, 0 );
}
CvBox2D Tracker::track(IplImage * pImg)
{
CvConnectedComp components;
updateHueImage(pImg);
cvCalcBackProject( &pHueImg, pProbImg, pHist );
cvAnd( pProbImg, pMask, pProbImg, 0 );
cvCamShift( pProbImg, prevFaceRect,
cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
&components, &faceBox );
prevFaceRect = components.rect;
faceBox.angle = -faceBox.angle;
return faceBox;
}
it works good but when tracked object goes out of the frame or somthing comes front of it, it makes a runtime error. one of my friends has a code that it's very similar to my code and it doesn't make any runtime error even in the worst situations. please guide me how can i debug this.
I think when tracked object goes out of the frame or something comes front of it, the parameter prevFaceRect will be null and may be because of that, it is showing error. So before calling this function
cvCamShift( pProbImg, prevFaceRect,
cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
&components, &faceBox );
add a check, to know whether prevFaceRect is null or not
Related
I used openCV library to get the similarity percentage in images . I used compareHist function of openCv library which returns double value, there different method name (int value) are passed in this function and got different- different result for every Mehod .Now how to take decision on these double values????
Mat src_base, hsv_base;
Mat src_test1, hsv_test1;
// Mat src_test2, hsv_test2;
Mat hsv_half_down;
String baseImgPath = [baseImagePath UTF8String];
String firstCmpImgPath = [firstCmpImagePath UTF8String];//compare image path
src_base = imread( baseImgPath, 1 ); read source image
src_test1 = imread(firstCmpImgPath, 1 ); read compared image
// src_test2 = imread(secondCmpImgPath, 1 );
if( !src_base.data || !src_test1.data /*||!src_test2.data*/)
{
return nil;
}
cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
//cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV );
hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows - 1 ), Range( 0, hsv_base.cols - 1 ) );
/// Using 50 bins for hue and 60 for saturation
int h_bins = 50; int s_bins = 60;
int histSize[] = { h_bins, s_bins };
// hue varies from 0 to 179, saturation from 0 to 255
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float* ranges[] = { h_ranges, s_ranges };
// Use the o-th and 1-st channels
int channels[] = { 0, 1 };
/// Histograms
MatND hist_base;
MatND hist_half_down;
MatND hist_test1;
MatND hist_test2;
/// Calculate the histograms for the HSV images
calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false );
normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() );
calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false );
normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() );
calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false );
normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() );
for( int i = 0; i < 4; i++ )
{
int compare_method = i;
double base_test1 = compareHist( hist_base, hist_test1, compare_method );
}
compare method are CV_COMP_CORREL, CV_COMP_CHISQR , CV_COMP_INTERSECT , CV_COMP_BHATTACHARYYA
Reference link http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.html
For a bitmap it makes sense to define a similarity metric that computes the percentage of pixels in an image that are different from a target image.
However when you are using the histogram of a bitmap/image this metric looses sense because you already made a statistic on that image (or extracted a feature). From this point, to compute the similarity, you compare the features of the 2 images, in your case with compareHist.
A higher distance means a more different image and 0 distance could mean that the images are 100% identical. Now it depends if the algorithm can actually output 0. However a 0.5 distance does not mean that the images are identical 50%.
However you can artificially create a similarity degree measured in percentage. You can consider the following:
The 2 images with the lowest similarity degree between them (maximum distance) have 0% similarity; You can even compute this distance using one pure black image and one pure white image :)
Distance 0 is similarity 100%.
Based on these assumptions, you can extract the similarity measured in percentage, based on your computeHist distance.
I am trying to plot Histogram of lenna here the 8 bit single ch. gray scale image.
But it is not displaying the output correctly, as can be seen in the following output:
void show_histogram_image(Mat img1)
{
int sbins = 256;
int histSize[] = {sbins};
float sranges[] = { 0, 256 };
const float* ranges[] = { sranges };
cv::MatND hist;
int channels[] = {0};
cv::calcHist( &img1, 1, channels, cv::Mat(), // do not use mask
hist, 1, histSize, ranges,
true, // the histogram is uniform
false );
double maxVal=0;
minMaxLoc(hist, 0, &maxVal, 0, 0);
int xscale = 10;
int yscale = 10;
cv::Mat hist_image;
hist_image = cv::Mat::zeros(256, sbins*xscale, CV_8UC1);
for( int s = 0; s < sbins; s++ )
{
float binVal = hist.at<float>(s, 0);
int intensity = cvRound(binVal*255/maxVal);
rectangle( hist_image, cv::Point(s*xscale, 0),
cv::Point( (s+1)*xscale - 1, intensity),
cv::Scalar::all(255),
CV_FILLED );
}
imshow("Image1",hist_image);
waitKey(0);
}
Here is my main();
int main()
{
Mat img1 = imread("lena512.bmp", CV_8UC1);
if (img1.empty()) //check whether the image is valid or not
{
cout << "Error : Image cannot be read..!!" << endl;
system("pause"); //wait for a key press
return -1;
}
show_histogram_image(img1);
}
And here is the output Histogram image:
I tried changing the xscale even then it is not coming correctly.
Update
I made the following changes:
rectangle( hist_image, cv::Point(s*xscale, hist_image.rows),
cv::Point( (s+1)*xscale - 1, hist_image.rows - intensity),
cv::Scalar::all(255), CV_FILLED );
And now the output is:
It is much better , but I need lines and clearly visible bins. And it looks like some part is hidden on the right side.
Update 2
I changed CV_FILLED to '1' and now I have:
since the image origin in opencv is (0,0), and thus the y-axis is pointing downwards,
you will have to invert the y-values for your histogram-drawing:
rectangle( hist_image, cv::Point(s*xscale, hist_image.rows),
cv::Point( (s+1)*xscale - 1, hist_image.rows - intensity),
cv::Scalar::all(255),
CV_FILLED );
I have this really strange issue and I think I might be doing something wrong, but I have an opencv1 implementation for Pyramidal Lucas Kanade and an opencv2 implementation. The difference is that the opencv2 takes MUCH longer to run (in particular the goodFeaturesToTrack function) vs. the opencv1. In addition, including the opencv2 libs and headers in the opencv1 implmentation results in that one becoming extremely slow as well (we're talking about 0.002 s per two images vs. 1 second per two images). Am I doing something wrong?
Windows 7, 64 bit. Here is the opencv2 code that runs really slow, at about 1 frame per second. As I said, taking the opencv1 implementation and switching library version causes the same slow down by a factor of 10 or more. I think this is very weird and google came up with no information! THANKS!!!
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <cmath>
using namespace cv;
using namespace std;
int64 now, then;
double elapsed_seconds, tickspersecond=cvGetTickFrequency() * 1.0e6;
int main(int argc, char** argv)
{
// Load two images and allocate other structures
Mat imgA = imread("0000.png", CV_LOAD_IMAGE_GRAYSCALE);
Mat imgB = imread("0001.png", CV_LOAD_IMAGE_GRAYSCALE);
Size img_sz = imgA.size();
Mat imgC(img_sz,1);
int win_size = 15;
int maxCorners = 100;
double qualityLevel = 0.05;
double minDistance = 2.0;
int blockSize = 3;
double k = 0.04;
std::vector<cv::Point2f> cornersA;
cornersA.reserve(maxCorners);
std::vector<cv::Point2f> cornersB;
cornersB.reserve(maxCorners);
then = cvGetTickCount();
goodFeaturesToTrack( imgA,cornersA,maxCorners,qualityLevel,minDistance,cv::Mat(),blockSize,true);
goodFeaturesToTrack( imgB,cornersB,maxCorners,qualityLevel,minDistance,cv::Mat(),blockSize,true);
now = cvGetTickCount();
cout << (double)(now - then) / tickspersecond;
cornerSubPix( imgA, cornersA, Size( win_size, win_size ), Size( -1, -1 ),
TermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03 ) );
cornerSubPix( imgB, cornersB, Size( win_size, win_size ), Size( -1, -1 ),
TermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03 ) );
// Call Lucas Kanade algorithm
CvSize pyr_sz = Size( img_sz.width+8, img_sz.height/3 );
std::vector<uchar> features_found;
features_found.reserve(maxCorners);
std::vector<float> feature_errors;
feature_errors.reserve(maxCorners);
calcOpticalFlowPyrLK( imgA, imgB, cornersA, cornersB, features_found, feature_errors ,
Size( win_size, win_size ), 5,
cvTermCriteria( CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.3 ), 0 );
// Make an image of the results
for( int i=0; i < features_found.size(); i++ ){
// cout<<"Error is "<<feature_errors[i]<<endl;
//continue;
//cout<<"Got it"<<endl;
Point p0( ceil( cornersA[i].x ), ceil( cornersA[i].y ) );
Point p1( ceil( cornersB[i].x ), ceil( cornersB[i].y ) );
line( imgC, p0, p1, CV_RGB(255,255,255), 2 );
}
namedWindow( "ImageA", 0 );
namedWindow( "ImageB", 0 );
namedWindow( "LKpyr_OpticalFlow", 0 );
imshow( "ImageA", imgA );
imshow( "ImageB", imgB );
imshow( "LKpyr_OpticalFlow", imgC );
cvWaitKey(0);
return 0;
}
You're probably using the debug libraries (*d.lib) instead of the release ones. I had this same problem with ~1-2s per call for goodFeaturesToTrack() and switching to release solved it.
Why are you calling goodFeaturesToTrack twice ?
Call it once to get cornersA and then use LK to identify the same corners / features in imgB.
I created the following gaussian kernel in OpenCV and comparing it with the GaussianBlur function of OpenCV. However, I'm getting a black image instead of a smooth image. Can someone throw some light on this?
Mat src, dst1,dst2;
Mat gaussiankrnl(3,3,CV_32F);
Point anchor;
double delta;
int ddepth;
anchor = Point( -1, -1 );
delta = 0;
ddepth = -1;
src = imread("coins.pgm");
gaussiankrnl.at<double>(0,0) = 1/16;
gaussiankrnl.at<double>(0,1) = 2/16;
gaussiankrnl.at<double>(0,2) = 1/16;
gaussiankrnl.at<double>(1,0) = 2/16;
gaussiankrnl.at<double>(1,1) = 4/16;
gaussiankrnl.at<double>(1,2) = 2/16;
gaussiankrnl.at<double>(2,0) = 1/16;
gaussiankrnl.at<double>(2,1) = 2/16;
gaussiankrnl.at<double>(2,2) = 1/16;
filter2D(src, dst1, ddepth , gaussiankrnl, anchor, delta, BORDER_DEFAULT );
GaussianBlur(src, dst2, Size(3,3), 1.0);
imshow("result1", dst1 );
imshow("result2", dst2 );
cvWaitKey(0);
return 0;
You are dividing integers and making zero kernel.
Change 1/16 to 1.0/16.0 as well as other values.
I have a program that calculates the convex hull of an image. I'm trying to use this information in order to count the number of fingers that are present in an input image. From some surfing I found out that the way to do this (count fingers) is by
Finding contours
Convex Hull
Convexity defects
But I'm having trouble using the convexity defects function. It compiles fine but at runtime the program crashes with certain input images but not with others and I can't seem to figure out why.
These are the input images
this image causes a crash
but this does not.
this also causes a crash even though its similar to the above
code..
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv/cxcore.h>
#include <stdio.h>
#define CVX_RED CV_RGB(0xff,0x00,0x00)
#define CVX_GREEN CV_RGB(0x00,0xff,0x00)
#define CVX_BLUE CV_RGB(0x00,0x00,0xff)
int main(int argc, char* argv[]) {
cvNamedWindow( "original", 1 );
cvNamedWindow( "contours", 1 );
cvNamedWindow( "hull", 1 );
IplImage* original_img = NULL;
original_img = cvLoadImage("img.jpg", CV_LOAD_IMAGE_GRAYSCALE );
IplImage* img_edge = cvCreateImage( cvGetSize(original_img), 8, 1 );
IplImage* contour_img = cvCreateImage( cvGetSize(original_img), 8, 3 );
IplImage* hull_img = cvCreateImage( cvGetSize(original_img), 8, 3 );
cvThreshold( original_img, img_edge, 128, 255, CV_THRESH_BINARY );
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* first_contour = NULL;
int Nc = cvFindContours(
img_edge,
storage,
&first_contour,
sizeof(CvContour),
CV_RETR_LIST // Try all four values and see what happens
);
for( CvSeq* c=first_contour; c!=NULL; c=c->h_next ) {
cvCvtColor( original_img, contour_img, CV_GRAY2BGR );
cvDrawContours(
contour_img,
c,
CVX_RED,
CVX_BLUE,
0,
2,
8
);
}
//----------------------------------------------------------------------Convex Hull
CvMemStorage* hull_storage = cvCreateMemStorage();
CvSeq* retHulls = NULL;
for(CvSeq* i = first_contour; i != NULL; i = i->h_next){
retHulls = cvConvexHull2(i,hull_storage,CV_CLOCKWISE,0);
// with 1 it draws the Hull image but not with 0..?
// however it needs to be 0 for convexitydefects to work?
}
printf(" %d elements:\n", retHulls->total );
// drawing hull
for( CvSeq* j=retHulls; j!=NULL; j=j->h_next ) {
cvCvtColor( original_img, hull_img, CV_GRAY2BGR );
cvDrawContours(
hull_img,
j,
CVX_RED,
CVX_BLUE,
0,
2,
8
);
}
//----------------------------------------------------------------------Convexity Defects??
CvMemStorage* convexStorage = cvCreateMemStorage();
CvSeq* defect = NULL;
defect = cvConvexityDefects(first_contour,retHulls, convexStorage);
printf(" %d defect:\n", defect->total );
cvShowImage( "contours", contour_img );
cvShowImage( "original", original_img );
cvShowImage( "hull", hull_img );
cvWaitKey(0);
cvDestroyWindow( "contours" );
cvDestroyWindow( "original" );
cvDestroyWindow( "hull" );
cvReleaseImage( &original_img );
cvReleaseImage( &contour_img );
cvReleaseImage( &hull_img );
cvReleaseImage( &img_edge );
return 0;
}
cvConvexityDefects expects the convexHull sequence (second argument) to contain indices into the contour sequence (first argument):
Convex hull obtained using ConvexHull2 that should contain pointers or indices to the contour points, not the hull points themselves
In the most trivial case, where cvFindContours returns a single simple contour (your second image) you got lucky and your code would supply the correct sequence as the first parameter.
In case cvFindContours finds holes in the contour (your third image), or if there are several simple contours or contours with holes (your first image) your code:
finds a convex hull of each contour in turn, but only remembers the last one (since each iteration of the loop overwrites retHulls variable)
passes the whole hierarchy of the contours, which doesn't correspond to indices in retHulls, to cvConvexityDefects as the first argument.
Instead, you should have:
passed CV_RETR_EXTERNAL to the cvFindContour to only get the outer contours (you don't care for defects of holes)
moved the cvConvexityDefects inside the last loop.
Something like:
/* ... */
if (argc < 2) {
std::cerr << "Usage: convexity IMAGE\n";
exit(1);
}
cvNamedWindow( "original", 1 );
cvNamedWindow( "contours", 1 );
cvNamedWindow( "hull", 1 );
IplImage* original_img = NULL;
original_img = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE );
IplImage* img_edge = cvCreateImage( cvGetSize(original_img), 8, 1 );
IplImage* contour_img = cvCreateImage( cvGetSize(original_img), 8, 3 );
IplImage* hull_img = cvCreateImage( cvGetSize(original_img), 8, 3 );
cvThreshold( original_img, img_edge, 128, 255, CV_THRESH_BINARY );
CvMemStorage* storage = cvCreateMemStorage();
CvSeq* first_contour = NULL;
int Nc = cvFindContours(
img_edge,
storage,
&first_contour,
sizeof(CvContour),
CV_RETR_EXTERNAL // Try all four values and see what happens
);
cvCvtColor( original_img, contour_img, CV_GRAY2BGR );
for( CvSeq* c=first_contour; c!=NULL; c=c->h_next ) {
cvDrawContours(
contour_img,
c,
CVX_RED,
CVX_BLUE,
0,
2,
8
);
}
cvShowImage( "contours", contour_img );
//----------------------------------------------------------------------Convex Hull
//-------------------------------------------------------------------Convex Defects
CvMemStorage* hull_storage = cvCreateMemStorage();
CvSeq* retHulls = NULL;
cvCvtColor( original_img, hull_img, CV_GRAY2BGR );
for(CvSeq* i = first_contour; i != NULL; i = i->h_next){
retHulls = cvConvexHull2(i,hull_storage,CV_CLOCKWISE,0);
printf(" %d elements:\n", retHulls->total );
CvSeq* defect = NULL;
defect = cvConvexityDefects(i,retHulls, NULL); // reuse storage of the contour
printf(" %d defect:\n", defect->total );
// drawing hull.... you can't use the one returned above since it only
// contains indices
retHulls = cvConvexHull2(i,hull_storage,CV_CLOCKWISE,1);
cvDrawContours(
hull_img,
retHulls,
CVX_RED,
CVX_BLUE,
0,
2,
8
);
}
cvShowImage( "hull", hull_img );
/* ... */
Running your application with the problematic images freezes it, but I see no crash with OpenCV 2.4.2, and the problem is really happening at cvConvexityDefects(), according to gdb:
(gdb) bt
#0 0x00000001002b1491 in cvConvexityDefects ()
#1 0x0000000100001a8d in main ()
Can't tell you why, though. Since the parameters seem to be OK, you might want to register a new issue here.
Using Python 3 and opencv 4.5.1, I encountered a similar issue where the indices from convexHull() were 'not monotonic'.
I found that for some reason the indices were returned from this function out of order.
To resolve the issue, I simply sorted the numpy array in descending order before passing the indices to convexityDefects().
hull = cv2.convexHull(contours, returnPoints=False)
hull[::-1].sort(axis=0)
defects = cv2.convexityDefects(contours, hull)
I've seen this problem before and that's when I use MAT with OpenCV 4.4.0 and I guess the crash happened with this error.
"The convex hull indices are not monotonous, which can be in the case when the input contour contains self-intersections in function 'convexityDefects'.
The solution was easy as you read the crash report in details, Which is that the indices are not sorted in order, and may be that's because there is some self-intersections in the contour, (or it might be a glitch since ver 2.1 fixed on ver 3.2 then back again on the 4.4.0 Check:
https://github.com/opencv/opencv/issues/4539
So in order not to wonder about this issue a lot, I have solve it by resorting the hull indices it self before extracting the defects from the contours.
As you see the hull indices is sorted upside down as if the hull cell size is 6 it means the indices in this cell will be:
[0] = 5
[1] = 4
[2] = 3
[3] = 2
[4] = 1
[5] = 0
But for the intersection or some other reasons it may not be sorted as it should like for example:
[0] = 6
[1] = 5
[2] = 4
[3] = 2
[4] = 1
[5] = 0
So all we need to do is to resort it
check this code
vector <vector <Vec4i> > defects(contour.size()); // Defects Vectors
vector <vector <cv::Point> > hullsP(contour.size()); // Hulls contour points
vector <vector <int> > hullsI(contour.size()); // Indices to hulls contour points
for(int i = 0; i < contour.size(); i++)
{
convexHull(contour[i], hullsP[i], CV_CLOCKWISE, false);
convexHull(contour[i], hullsI[i], CV_CLOCKWISE, false);
for(size_t k =0; k < hullsI[i].size(); k++) //Here we resort the indices
{
if (hullsI[i].size() > 0)
{
hullsI[i][k] = (int)((hullsI[i].size() - k)-1);
}
}
if(hullsI[i].size() > 3 ) // You need more than 3 indices
{
convexityDefects(contour[i], hullsI[i], defects[i]);
}
}