converted some OpenCV C samples to C++
@@ -0,0 +1,214 @@
|
||||
#include <opencv2/video/tracking.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <ctype.h>
|
||||
|
||||
IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *backproject = 0, *histimg = 0;
|
||||
CvHistogram *hist = 0;
|
||||
|
||||
int backproject_mode = 0;
|
||||
int select_object = 0;
|
||||
int track_object = 0;
|
||||
int show_hist = 1;
|
||||
CvPoint origin;
|
||||
CvRect selection;
|
||||
CvRect track_window;
|
||||
CvBox2D track_box;
|
||||
CvConnectedComp track_comp;
|
||||
int hdims = 16;
|
||||
float hranges_arr[] = {0,180};
|
||||
float* hranges = hranges_arr;
|
||||
int vmin = 10, vmax = 256, smin = 30;
|
||||
|
||||
void onMouse( int event, int x, int y, int flags, void* param )
|
||||
{
|
||||
if( selectObject )
|
||||
{
|
||||
selection.x = MIN(x, origin.x);
|
||||
selection.y = MIN(y, origin.y);
|
||||
selection.width = selection.x + std::abs(x - origin.x);
|
||||
selection.height = selection.y + std::abs(y - origin.y);
|
||||
|
||||
selection.x = MAX(selection.x, 0);
|
||||
selection.y = MAX(selection.y, 0);
|
||||
selection.width = MIN(selection.width, image.cols);
|
||||
selection.height = MIN(selection.height, image.rows);
|
||||
selection.width -= selection.x;
|
||||
selection.height -= selection.y;
|
||||
}
|
||||
|
||||
switch( event )
|
||||
{
|
||||
case CV_EVENT_LBUTTONDOWN:
|
||||
origin = Point(x,y);
|
||||
selection = Rect(x,y,0,0);
|
||||
selectObject = true;
|
||||
break;
|
||||
case CV_EVENT_LBUTTONUP:
|
||||
selectObject = false;
|
||||
if( selection.width > 0 && selection.height > 0 )
|
||||
trackObject = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Scalar hsv2rgb( float hue )
|
||||
{
|
||||
int rgb[3], p, sector;
|
||||
static const int sectorData[][3]=
|
||||
{{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
|
||||
hue *= 0.033333333333333333333333333333333f;
|
||||
sector = cvFloor(hue);
|
||||
p = cvRound(255*(hue - sector));
|
||||
p ^= sector & 1 ? 255 : 0;
|
||||
|
||||
rgb[sector_data[sector][0]] = 255;
|
||||
rgb[sector_data[sector][1]] = 0;
|
||||
rgb[sector_data[sector][2]] = p;
|
||||
|
||||
return cvScalar(rgb[2], rgb[1], rgb[0],0);
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
CvCapture* capture = 0;
|
||||
|
||||
if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
|
||||
capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
|
||||
else if( argc == 2 )
|
||||
capture = cvCaptureFromAVI( argv[1] );
|
||||
|
||||
if( !capture )
|
||||
{
|
||||
fprintf(stderr,"Could not initialize capturing...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf( "Hot keys: \n"
|
||||
"\tESC - quit the program\n"
|
||||
"\tc - stop the tracking\n"
|
||||
"\tb - switch to/from backprojection view\n"
|
||||
"\th - show/hide object histogram\n"
|
||||
"To initialize tracking, select the object with mouse\n" );
|
||||
|
||||
cvNamedWindow( "Histogram", 1 );
|
||||
cvNamedWindow( "CamShiftDemo", 1 );
|
||||
cvSetMouseCallback( "CamShiftDemo", on_mouse, 0 );
|
||||
cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0 );
|
||||
cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0 );
|
||||
cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
IplImage* frame = 0;
|
||||
int i, bin_w, c;
|
||||
|
||||
frame = cvQueryFrame( capture );
|
||||
if( !frame )
|
||||
break;
|
||||
|
||||
if( !image )
|
||||
{
|
||||
/* allocate all the buffers */
|
||||
image = cvCreateImage( cvGetSize(frame), 8, 3 );
|
||||
image->origin = frame->origin;
|
||||
hsv = cvCreateImage( cvGetSize(frame), 8, 3 );
|
||||
hue = cvCreateImage( cvGetSize(frame), 8, 1 );
|
||||
mask = cvCreateImage( cvGetSize(frame), 8, 1 );
|
||||
backproject = cvCreateImage( cvGetSize(frame), 8, 1 );
|
||||
hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 );
|
||||
histimg = cvCreateImage( cvSize(320,200), 8, 3 );
|
||||
cvZero( histimg );
|
||||
}
|
||||
|
||||
cvCopy( frame, image, 0 );
|
||||
cvCvtColor( image, hsv, CV_BGR2HSV );
|
||||
|
||||
if( track_object )
|
||||
{
|
||||
int _vmin = vmin, _vmax = vmax;
|
||||
|
||||
cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
|
||||
cvScalar(180,256,MAX(_vmin,_vmax),0), mask );
|
||||
cvSplit( hsv, hue, 0, 0, 0 );
|
||||
|
||||
if( track_object < 0 )
|
||||
{
|
||||
float max_val = 0.f;
|
||||
cvSetImageROI( hue, selection );
|
||||
cvSetImageROI( mask, selection );
|
||||
cvCalcHist( &hue, hist, 0, mask );
|
||||
cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 );
|
||||
cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 );
|
||||
cvResetImageROI( hue );
|
||||
cvResetImageROI( mask );
|
||||
track_window = selection;
|
||||
track_object = 1;
|
||||
|
||||
cvZero( histimg );
|
||||
bin_w = histimg->width / hdims;
|
||||
for( i = 0; i < hdims; i++ )
|
||||
{
|
||||
int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 );
|
||||
CvScalar color = hsv2rgb(i*180.f/hdims);
|
||||
cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),
|
||||
cvPoint((i+1)*bin_w,histimg->height - val),
|
||||
color, -1, 8, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
cvCalcBackProject( &hue, backproject, hist );
|
||||
cvAnd( backproject, mask, backproject, 0 );
|
||||
cvCamShift( backproject, track_window,
|
||||
cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
|
||||
&track_comp, &track_box );
|
||||
track_window = track_comp.rect;
|
||||
|
||||
if( backproject_mode )
|
||||
cvCvtColor( backproject, image, CV_GRAY2BGR );
|
||||
if( !image->origin )
|
||||
track_box.angle = -track_box.angle;
|
||||
cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );
|
||||
}
|
||||
|
||||
if( select_object && selection.width > 0 && selection.height > 0 )
|
||||
{
|
||||
cvSetImageROI( image, selection );
|
||||
cvXorS( image, cvScalarAll(255), image, 0 );
|
||||
cvResetImageROI( image );
|
||||
}
|
||||
|
||||
cvShowImage( "CamShiftDemo", image );
|
||||
cvShowImage( "Histogram", histimg );
|
||||
|
||||
c = cvWaitKey(10);
|
||||
if( (char) c == 27 )
|
||||
break;
|
||||
switch( (char) c )
|
||||
{
|
||||
case 'b':
|
||||
backproject_mode ^= 1;
|
||||
break;
|
||||
case 'c':
|
||||
track_object = 0;
|
||||
cvZero( histimg );
|
||||
break;
|
||||
case 'h':
|
||||
show_hist ^= 1;
|
||||
if( !show_hist )
|
||||
cvDestroyWindow( "Histogram" );
|
||||
else
|
||||
cvNamedWindow( "Histogram", 1 );
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
cvReleaseCapture( &capture );
|
||||
cvDestroyWindow("CamShiftDemo");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
Mat img(500, 500, CV_8UC3);
|
||||
RNG& rng = theRNG();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char key;
|
||||
int i, count = (unsigned)rng%100 + 1;
|
||||
|
||||
vector<Point> points;
|
||||
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
Point pt;
|
||||
pt.x = rng.uniform(img.cols/4, img.cols*3/4);
|
||||
pt.y = rng.uniform(img.rows/4, img.rows*3/4);
|
||||
|
||||
points.push_back(pt);
|
||||
}
|
||||
|
||||
vector<int> hull;
|
||||
convexHull(Mat(points), hull, CV_CLOCKWISE);
|
||||
|
||||
img = Scalar::all(0);
|
||||
for( i = 0; i < count; i++ )
|
||||
circle(img, points[i], 3, Scalar(0, 0, 255), CV_FILLED, CV_AA);
|
||||
|
||||
int hullcount = (int)hull.size();
|
||||
Point pt0 = points[hull[hullcount-1]];
|
||||
|
||||
for( i = 0; i < hullcount; i++ )
|
||||
{
|
||||
Point pt = points[hull[i]];
|
||||
line(img, pt0, pt, Scalar(0, 255, 0), 1, CV_AA);
|
||||
pt0 = pt;
|
||||
}
|
||||
|
||||
imshow("hull", img);
|
||||
|
||||
key = (char)waitKey();
|
||||
if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
int _brightness = 100;
|
||||
int _contrast = 100;
|
||||
|
||||
Mat image;
|
||||
|
||||
/* brightness/contrast callback function */
|
||||
void updateBrightnessContrast( int arg, void* )
|
||||
{
|
||||
int histSize = 64;
|
||||
int brightness = _brightness - 100;
|
||||
int contrast = _contrast - 100;
|
||||
|
||||
/*
|
||||
* The algorithm is by Werner D. Streidt
|
||||
* (http://visca.com/ffactory/archives/5-99/msg00021.html)
|
||||
*/
|
||||
double a, b;
|
||||
if( contrast > 0 )
|
||||
{
|
||||
double delta = 127.*contrast/100;
|
||||
a = 255./(255. - delta*2);
|
||||
b = a*(brightness - delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
double delta = -128.*contrast/100;
|
||||
a = (256.-delta*2)/255.;
|
||||
b = a*brightness + delta;
|
||||
}
|
||||
|
||||
Mat dst, hist;
|
||||
image.convertTo(dst, CV_8U, a, b);
|
||||
imshow("image", dst);
|
||||
|
||||
calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, 0);
|
||||
Mat histImage = Mat::ones(200, 320, CV_8U)*255;
|
||||
|
||||
normalize(hist, hist, 0, histImage.rows, CV_MINMAX, CV_32F);
|
||||
|
||||
histImage = Scalar::all(255);
|
||||
int binW = cvRound((double)histImage.cols/histSize);
|
||||
|
||||
for( int i = 0; i < histSize; i++ )
|
||||
rectangle( histImage, Point(i*binW, histImage.rows),
|
||||
Point((i+1)*binW, histImage.rows - cvRound(hist.at<float>(i))),
|
||||
Scalar::all(0), -1, 8, 0 );
|
||||
imshow("histogram", histImage);
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
// Load the source image. HighGUI use.
|
||||
image = imread( argc == 2 ? argv[1] : "baboon.jpg", 0 );
|
||||
|
||||
if( image.empty() )
|
||||
{
|
||||
cout << "Image was not loaded.\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
namedWindow("image", 0);
|
||||
namedWindow("histogram", 0);
|
||||
|
||||
createTrackbar("brightness", "image", &_brightness, 200, updateBrightnessContrast);
|
||||
createTrackbar("contrast", "image", &_contrast, 200, updateBrightnessContrast);
|
||||
|
||||
updateBrightnessContrast(0, 0);
|
||||
waitKey();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
const char* filename = argc >=2 ? argv[1] : "lena.jpg";
|
||||
|
||||
Mat img = imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
|
||||
if( img.empty() )
|
||||
{
|
||||
cout << "Usage: dft <image_name>" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int M = getOptimalDFTSize( img.rows );
|
||||
int N = getOptimalDFTSize( img.cols );
|
||||
Mat padded;
|
||||
copyMakeBorder(img, padded, 0, M - img.rows, 0, N - img.cols, BORDER_CONSTANT, Scalar::all(0));
|
||||
|
||||
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
|
||||
Mat complexImg;
|
||||
merge(planes, 2, complexImg);
|
||||
|
||||
dft(complexImg, complexImg);
|
||||
|
||||
// compute log(1 + sqrt(Re(DFT(img))**2 + Im(DFT(img))**2))
|
||||
split(complexImg, planes);
|
||||
magnitude(planes[0], planes[1], planes[0]);
|
||||
Mat mag = planes[0];
|
||||
mag += Scalar::all(1);
|
||||
log(mag, mag);
|
||||
|
||||
// crop the spectrum, if it has an odd number of rows or columns
|
||||
mag = mag(Rect(0, 0, mag.cols & -2, mag.rows & -2));
|
||||
|
||||
int cx = mag.cols/2;
|
||||
int cy = mag.rows/2;
|
||||
|
||||
// rearrange the quadrants of Fourier image
|
||||
// so that the origin is at the image center
|
||||
Mat tmp;
|
||||
Mat q0(mag, Rect(0, 0, cx, cy));
|
||||
Mat q1(mag, Rect(cx, 0, cx, cy));
|
||||
Mat q2(mag, Rect(0, cy, cx, cy));
|
||||
Mat q3(mag, Rect(cx, cy, cx, cy));
|
||||
|
||||
q0.copyTo(tmp);
|
||||
q3.copyTo(q0);
|
||||
tmp.copyTo(q3);
|
||||
|
||||
q1.copyTo(tmp);
|
||||
q2.copyTo(q1);
|
||||
tmp.copyTo(q2);
|
||||
|
||||
normalize(mag, mag, 0, 1, CV_MINMAX);
|
||||
|
||||
imshow("spectrum magnitude", mag);
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
int maskSize0 = CV_DIST_MASK_5;
|
||||
bool buildVoronoi = false;
|
||||
int edgeThresh = 100;
|
||||
int distType0 = CV_DIST_L1;
|
||||
|
||||
// The output and temporary images
|
||||
Mat gray;
|
||||
|
||||
// threshold trackbar callback
|
||||
void onTrackbar( int, void* )
|
||||
{
|
||||
static const Scalar colors[] =
|
||||
{
|
||||
Scalar(0,0,0),
|
||||
Scalar(255,0,0),
|
||||
Scalar(255,128,0),
|
||||
Scalar(255,255,0),
|
||||
Scalar(0,255,0),
|
||||
Scalar(0,128,255),
|
||||
Scalar(0,255,255),
|
||||
Scalar(0,0,255),
|
||||
Scalar(255,0,255)
|
||||
};
|
||||
|
||||
int maskSize = buildVoronoi ? CV_DIST_MASK_5 : maskSize0;
|
||||
int distType = buildVoronoi ? CV_DIST_L2 : distType0;
|
||||
|
||||
Mat edge = gray >= edgeThresh, dist, labels, dist8u;
|
||||
|
||||
if( !buildVoronoi )
|
||||
distanceTransform( edge, dist, distType, maskSize );
|
||||
else
|
||||
distanceTransform( edge, dist, labels, distType, maskSize );
|
||||
|
||||
if( !buildVoronoi )
|
||||
{
|
||||
// begin "painting" the distance transform result
|
||||
dist *= 5000;
|
||||
pow(dist, 0.5, dist);
|
||||
|
||||
Mat dist32s, dist8u1, dist8u2;
|
||||
|
||||
dist.convertTo(dist32s, CV_32S, 1, 0.5);
|
||||
dist32s &= Scalar::all(255);
|
||||
|
||||
dist32s.convertTo(dist8u1, CV_8U, 1, 0);
|
||||
dist32s *= -1;
|
||||
|
||||
dist32s += Scalar::all(255);
|
||||
dist32s.convertTo(dist8u2, CV_8U);
|
||||
|
||||
Mat planes[] = {dist8u1, dist8u2, dist8u2};
|
||||
merge(planes, 3, dist8u);
|
||||
}
|
||||
else
|
||||
{
|
||||
dist8u.create(labels.size(), CV_8UC3);
|
||||
for( int i = 0; i < labels.rows; i++ )
|
||||
{
|
||||
const int* ll = (const int*)labels.ptr(i);
|
||||
const float* dd = (const float*)dist.ptr(i);
|
||||
uchar* d = (uchar*)dist8u.ptr(i);
|
||||
for( int j = 0; j < labels.cols; j++ )
|
||||
{
|
||||
int idx = ll[j] == 0 || dd[j] == 0 ? 0 : (ll[j]-1)%8 + 1;
|
||||
int b = cvRound(colors[idx][0]);
|
||||
int g = cvRound(colors[idx][1]);
|
||||
int r = cvRound(colors[idx][2]);
|
||||
d[j*3] = (uchar)b;
|
||||
d[j*3+1] = (uchar)g;
|
||||
d[j*3+2] = (uchar)r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
imshow("Distance Map", dist8u );
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
char* filename = argc == 2 ? argv[1] : (char*)"stuff.jpg";
|
||||
gray = imread(filename, 0);
|
||||
if(gray.empty())
|
||||
{
|
||||
printf("Usage: distrans <image_name>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf( "Hot keys: \n"
|
||||
"\tESC - quit the program\n"
|
||||
"\tC - use C/Inf metric\n"
|
||||
"\tL1 - use L1 metric\n"
|
||||
"\tL2 - use L2 metric\n"
|
||||
"\t3 - use 3x3 mask\n"
|
||||
"\t5 - use 5x5 mask\n"
|
||||
"\t0 - use precise distance transform\n"
|
||||
"\tv - switch Voronoi diagram mode on/off\n"
|
||||
"\tSPACE - loop through all the modes\n" );
|
||||
|
||||
namedWindow("Distance Map", 1);
|
||||
createTrackbar("Brightness Threshold", "Distance Map", &edgeThresh, 255, onTrackbar, 0);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Call to update the view
|
||||
onTrackbar(0, 0);
|
||||
|
||||
int c = cvWaitKey(0);
|
||||
|
||||
if( (char)c == 27 )
|
||||
break;
|
||||
|
||||
if( (char)c == 'c' || (char)c == 'C' )
|
||||
distType0 = CV_DIST_C;
|
||||
else if( (char)c == '1' )
|
||||
distType0 = CV_DIST_L1;
|
||||
else if( (char)c == '2' )
|
||||
distType0 = CV_DIST_L2;
|
||||
else if( (char)c == '3' )
|
||||
maskSize0 = CV_DIST_MASK_3;
|
||||
else if( (char)c == '5' )
|
||||
maskSize0 = CV_DIST_MASK_5;
|
||||
else if( (char)c == '0' )
|
||||
maskSize0 = CV_DIST_MASK_PRECISE;
|
||||
else if( (char)c == 'v' )
|
||||
buildVoronoi = !buildVoronoi;
|
||||
else if( (char)c == ' ' )
|
||||
{
|
||||
if( buildVoronoi )
|
||||
{
|
||||
buildVoronoi = false;
|
||||
maskSize0 = CV_DIST_MASK_3;
|
||||
distType0 = CV_DIST_C;
|
||||
}
|
||||
else if( distType0 == CV_DIST_C )
|
||||
distType0 = CV_DIST_L1;
|
||||
else if( distType0 == CV_DIST_L1 )
|
||||
distType0 = CV_DIST_L2;
|
||||
else if( maskSize0 == CV_DIST_MASK_3 )
|
||||
maskSize0 = CV_DIST_MASK_5;
|
||||
else if( maskSize0 == CV_DIST_MASK_5 )
|
||||
maskSize0 = CV_DIST_MASK_PRECISE;
|
||||
else if( maskSize0 == CV_DIST_MASK_PRECISE )
|
||||
buildVoronoi = true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
static Scalar randomColor(RNG& rng)
|
||||
{
|
||||
int icolor = (unsigned)rng;
|
||||
return Scalar(icolor&255, (icolor>>8)&255, (icolor>>16)&255);
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
char wndname[] = "Drawing Demo";
|
||||
const int NUMBER = 100;
|
||||
const int DELAY = 5;
|
||||
int lineType = CV_AA; // change it to 8 to see non-antialiased graphics
|
||||
int i, width = 1000, height = 700;
|
||||
int x1 = -width/2, x2 = width*3/2, y1 = -height/2, y2 = height*3/2;
|
||||
RNG rng(-1);
|
||||
|
||||
Mat image = Mat::zeros(height, width, CV_8UC3);
|
||||
imshow(wndname, image);
|
||||
waitKey(DELAY);
|
||||
|
||||
for (i = 0; i < NUMBER; i++)
|
||||
{
|
||||
Point pt1, pt2;
|
||||
pt1.x = rng.uniform(x1, x2);
|
||||
pt1.y = rng.uniform(y1, y2);
|
||||
pt2.x = rng.uniform(x1, x2);
|
||||
pt2.y = rng.uniform(y1, y2);
|
||||
|
||||
line( image, pt1, pt2, randomColor(rng), rng.uniform(1,10), lineType );
|
||||
|
||||
imshow(wndname, image);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUMBER; i++)
|
||||
{
|
||||
Point pt1, pt2;
|
||||
pt1.x = rng.uniform(x1, x2);
|
||||
pt1.y = rng.uniform(y1, y2);
|
||||
pt2.x = rng.uniform(x1, x2);
|
||||
pt2.y = rng.uniform(y1, y2);
|
||||
int thickness = rng.uniform(-3, 10);
|
||||
|
||||
rectangle( image, pt1, pt2, randomColor(rng), MAX(thickness, -1), lineType );
|
||||
|
||||
imshow(wndname, image);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUMBER; i++)
|
||||
{
|
||||
Point center;
|
||||
center.x = rng.uniform(x1, x2);
|
||||
center.y = rng.uniform(y1, y2);
|
||||
Size axes;
|
||||
axes.width = rng.uniform(0, 200);
|
||||
axes.height = rng.uniform(0, 200);
|
||||
double angle = rng.uniform(0, 180);
|
||||
|
||||
ellipse( image, center, axes, angle, angle - 100, angle + 200,
|
||||
randomColor(rng), rng.uniform(-1,9), lineType );
|
||||
|
||||
imshow(wndname, image);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i< NUMBER; i++)
|
||||
{
|
||||
Point pt[2][3];
|
||||
pt[0][0].x = rng.uniform(x1, x2);
|
||||
pt[0][0].y = rng.uniform(y1, y2);
|
||||
pt[0][1].x = rng.uniform(x1, x2);
|
||||
pt[0][1].y = rng.uniform(y1, y2);
|
||||
pt[0][2].x = rng.uniform(x1, x2);
|
||||
pt[0][2].y = rng.uniform(y1, y2);
|
||||
pt[1][0].x = rng.uniform(x1, x2);
|
||||
pt[1][0].y = rng.uniform(y1, y2);
|
||||
pt[1][1].x = rng.uniform(x1, x2);
|
||||
pt[1][1].y = rng.uniform(y1, y2);
|
||||
pt[1][2].x = rng.uniform(x1, x2);
|
||||
pt[1][2].y = rng.uniform(y1, y2);
|
||||
const Point* ppt[2] = {pt[0], pt[1]};
|
||||
int npt[] = {3, 3};
|
||||
|
||||
polylines(image, ppt, npt, 2, true, randomColor(rng), rng.uniform(1,10), lineType);
|
||||
|
||||
imshow(wndname, image);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i< NUMBER; i++)
|
||||
{
|
||||
Point pt[2][3];
|
||||
pt[0][0].x = rng.uniform(x1, x2);
|
||||
pt[0][0].y = rng.uniform(y1, y2);
|
||||
pt[0][1].x = rng.uniform(x1, x2);
|
||||
pt[0][1].y = rng.uniform(y1, y2);
|
||||
pt[0][2].x = rng.uniform(x1, x2);
|
||||
pt[0][2].y = rng.uniform(y1, y2);
|
||||
pt[1][0].x = rng.uniform(x1, x2);
|
||||
pt[1][0].y = rng.uniform(y1, y2);
|
||||
pt[1][1].x = rng.uniform(x1, x2);
|
||||
pt[1][1].y = rng.uniform(y1, y2);
|
||||
pt[1][2].x = rng.uniform(x1, x2);
|
||||
pt[1][2].y = rng.uniform(y1, y2);
|
||||
const Point* ppt[2] = {pt[0], pt[1]};
|
||||
int npt[] = {3, 3};
|
||||
|
||||
fillPoly(image, ppt, npt, 2, randomColor(rng), lineType);
|
||||
|
||||
imshow(wndname, image);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUMBER; i++)
|
||||
{
|
||||
Point center;
|
||||
center.x = rng.uniform(x1, x2);
|
||||
center.y = rng.uniform(y1, y2);
|
||||
|
||||
circle(image, center, rng.uniform(0, 300), randomColor(rng),
|
||||
rng.uniform(-1, 9), lineType);
|
||||
|
||||
imshow(wndname, image);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < NUMBER; i++)
|
||||
{
|
||||
Point org;
|
||||
org.x = rng.uniform(x1, x2);
|
||||
org.y = rng.uniform(y1, y2);
|
||||
|
||||
putText(image, "Testing text rendering", org, rng.uniform(0,8),
|
||||
rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType);
|
||||
|
||||
imshow(wndname, image);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Size textsize = getTextSize("OpenCV forever!", CV_FONT_HERSHEY_COMPLEX, 3, 5, 0);
|
||||
Point org((width - textsize.width)/2, (height - textsize.height)/2);
|
||||
|
||||
Mat image2;
|
||||
for( i = 0; i < 255; i += 2 )
|
||||
{
|
||||
image2 = image - Scalar::all(i);
|
||||
putText(image2, "OpenCV forever!", org, CV_FONT_HERSHEY_COMPLEX, 3,
|
||||
Scalar(i, i, 255), 5, lineType);
|
||||
|
||||
imshow(wndname, image2);
|
||||
if(waitKey(DELAY) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _EiC
|
||||
main(1,"drawing.c");
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
int edgeThresh = 1;
|
||||
Mat image, gray, edge, cedge;
|
||||
|
||||
// define a trackbar callback
|
||||
void onTrackbar(int, void*)
|
||||
{
|
||||
blur(gray, edge, Size(3,3));
|
||||
|
||||
// Run the edge detector on grayscale
|
||||
Canny(edge, edge, edgeThresh, edgeThresh*3, 3);
|
||||
cedge = Scalar::all(0);
|
||||
|
||||
image.copyTo(cedge, edge);
|
||||
imshow("Edge map", cedge);
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
char* filename = argc == 2 ? argv[1] : (char*)"fruits.jpg";
|
||||
|
||||
image = imread(filename, 1);
|
||||
if(image.empty())
|
||||
{
|
||||
cout << "Usage: edge <image_name>" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cedge.create(image.size(), image.type());
|
||||
cvtColor(image, gray, CV_BGR2GRAY);
|
||||
|
||||
// Create a window
|
||||
namedWindow("Edge map", 1);
|
||||
|
||||
// create a toolbar
|
||||
createTrackbar("Canny threshold", "Edge map", &edgeThresh, 100, onTrackbar);
|
||||
|
||||
// Show the image
|
||||
onTrackbar(0, 0);
|
||||
|
||||
// Wait for a key stroke; the same function arranges events processing
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#include <opencv2/video/tracking.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
void drawOptFlowMap(const Mat& flow, Mat& cflowmap, int step,
|
||||
double, const Scalar& color)
|
||||
{
|
||||
for(int y = 0; y < cflowmap.rows; y += step)
|
||||
for(int x = 0; x < cflowmap.cols; x += step)
|
||||
{
|
||||
const Point2f& fxy = flow.at<Point2f>(y, x);
|
||||
line(cflowmap, Point(x,y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)),
|
||||
color);
|
||||
circle(cflowmap, Point(x,y), 2, color, -1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
VideoCapture cap(0);
|
||||
|
||||
if( !cap.isOpened() )
|
||||
return -1;
|
||||
|
||||
Mat prevgray, gray, flow, cflow, frame;
|
||||
namedWindow("flow", 1);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
cap >> frame;
|
||||
cvtColor(frame, gray, CV_BGR2GRAY);
|
||||
|
||||
if( prevgray.data )
|
||||
{
|
||||
calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);
|
||||
cvtColor(prevgray, cflow, CV_GRAY2BGR);
|
||||
drawOptFlowMap(flow, cflow, 16, 1.5, CV_RGB(0, 255, 0));
|
||||
imshow("flow", cflow);
|
||||
}
|
||||
if(waitKey(30)>=0)
|
||||
break;
|
||||
std::swap(prevgray, gray);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
Mat image0, image, gray, mask;
|
||||
int ffillMode = 1;
|
||||
int loDiff = 20, upDiff = 20;
|
||||
int connectivity = 4;
|
||||
int isColor = true;
|
||||
bool useMask = false;
|
||||
int newMaskVal = 255;
|
||||
|
||||
void onMouse( int event, int x, int y, int, void* param )
|
||||
{
|
||||
if( event != CV_EVENT_LBUTTONDOWN )
|
||||
return;
|
||||
|
||||
Point seed = Point(x,y);
|
||||
int lo = ffillMode == 0 ? 0 : loDiff;
|
||||
int up = ffillMode == 0 ? 0 : upDiff;
|
||||
int flags = connectivity + (newMaskVal << 8) +
|
||||
(ffillMode == 1 ? CV_FLOODFILL_FIXED_RANGE : 0);
|
||||
int b = (unsigned)theRNG() & 255;
|
||||
int g = (unsigned)theRNG() & 255;
|
||||
int r = (unsigned)theRNG() & 255;
|
||||
Rect ccomp;
|
||||
|
||||
Scalar newVal = isColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114);
|
||||
Mat dst = isColor ? image : gray;
|
||||
int area;
|
||||
|
||||
if( useMask )
|
||||
{
|
||||
threshold(mask, mask, 1, 128, CV_THRESH_BINARY);
|
||||
area = floodFill(dst, mask, seed, newVal, &ccomp, Scalar(lo, lo, lo),
|
||||
Scalar(up, up, up), flags);
|
||||
imshow( "mask", mask );
|
||||
}
|
||||
else
|
||||
{
|
||||
area = floodFill(dst, seed, newVal, &ccomp, Scalar(lo, lo, lo),
|
||||
Scalar(up, up, up), flags);
|
||||
}
|
||||
|
||||
imshow("image", dst);
|
||||
cout << area << " pixels were repainted\n";
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
char* filename = argc >= 2 ? argv[1] : (char*)"fruits.jpg";
|
||||
image0 = imread(filename, 1);
|
||||
|
||||
if( image0.empty() )
|
||||
{
|
||||
cout << "Usage: ffilldemo <image_name>\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
cout << "Hot keys: \n"
|
||||
"\tESC - quit the program\n"
|
||||
"\tc - switch color/grayscale mode\n"
|
||||
"\tm - switch mask mode\n"
|
||||
"\tr - restore the original image\n"
|
||||
"\ts - use null-range floodfill\n"
|
||||
"\tf - use gradient floodfill with fixed(absolute) range\n"
|
||||
"\tg - use gradient floodfill with floating(relative) range\n"
|
||||
"\t4 - use 4-connectivity mode\n"
|
||||
"\t8 - use 8-connectivity mode\n";
|
||||
|
||||
image0.copyTo(image);
|
||||
cvtColor(image0, gray, CV_BGR2GRAY);
|
||||
mask.create(image0.rows+2, image0.cols+2, CV_8UC1);
|
||||
|
||||
namedWindow( "image", 0 );
|
||||
createTrackbar( "lo_diff", "image", &loDiff, 255, 0 );
|
||||
createTrackbar( "up_diff", "image", &upDiff, 255, 0 );
|
||||
|
||||
setMouseCallback( "image", onMouse, 0 );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
imshow("image", isColor ? image : gray);
|
||||
|
||||
int c = waitKey(0);
|
||||
switch( (char)c )
|
||||
{
|
||||
case 27:
|
||||
cout << "Exiting ...\n";
|
||||
return 0;
|
||||
case 'c':
|
||||
if( isColor )
|
||||
{
|
||||
cout << "Grayscale mode is set\n";
|
||||
cvtColor(image0, gray, CV_BGR2GRAY);
|
||||
mask = Scalar::all(0);
|
||||
isColor = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Color mode is set\n";
|
||||
image0.copyTo(image);
|
||||
mask = Scalar::all(0);
|
||||
isColor = true;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if( useMask )
|
||||
{
|
||||
destroyWindow( "mask" );
|
||||
useMask = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
namedWindow( "mask", 0 );
|
||||
mask = Scalar::all(0);
|
||||
imshow("mask", mask);
|
||||
useMask = true;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
cout << "Original image is restored\n";
|
||||
image0.copyTo(image);
|
||||
cvtColor(image, gray, CV_BGR2GRAY);
|
||||
mask = Scalar::all(0);
|
||||
break;
|
||||
case 's':
|
||||
cout << "Simple floodfill mode is set\n";
|
||||
ffillMode = 0;
|
||||
break;
|
||||
case 'f':
|
||||
cout << "Fixed Range floodfill mode is set\n";
|
||||
ffillMode = 1;
|
||||
break;
|
||||
case 'g':
|
||||
cout << "Gradient (floating range) floodfill mode is set\n";
|
||||
ffillMode = 2;
|
||||
break;
|
||||
case '4':
|
||||
cout << "4-connectivity mode is set\n";
|
||||
connectivity = 4;
|
||||
break;
|
||||
case '8':
|
||||
cout << "8-connectivity mode is set\n";
|
||||
connectivity = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 80 KiB |
@@ -0,0 +1,318 @@
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
const Scalar RED = Scalar(0,0,255);
|
||||
const Scalar PINK = Scalar(230,130,255);
|
||||
const Scalar BLUE = Scalar(255,0,0);
|
||||
const Scalar LIGHTBLUE = Scalar(255,255,160);
|
||||
const Scalar GREEN = Scalar(0,255,0);
|
||||
|
||||
const int BGD_KEY = CV_EVENT_FLAG_CTRLKEY;
|
||||
const int FGD_KEY = CV_EVENT_FLAG_SHIFTKEY;
|
||||
|
||||
void getBinMask( const Mat& comMask, Mat& binMask )
|
||||
{
|
||||
if( comMask.empty() || comMask.type()!=CV_8UC1 )
|
||||
CV_Error( CV_StsBadArg, "comMask is empty or has incorrect type (not CV_8UC1)" );
|
||||
if( binMask.empty() || binMask.rows!=comMask.rows || binMask.cols!=comMask.cols )
|
||||
binMask.create( comMask.size(), CV_8UC1 );
|
||||
binMask = comMask & 1;
|
||||
}
|
||||
|
||||
class GCApplication
|
||||
{
|
||||
public:
|
||||
enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 };
|
||||
static const int radius = 2;
|
||||
static const int thickness = -1;
|
||||
|
||||
void reset();
|
||||
void setImageAndWinName( const Mat& _image, const string& _winName );
|
||||
void showImage() const;
|
||||
void mouseClick( int event, int x, int y, int flags, void* param );
|
||||
int nextIter();
|
||||
int getIterCount() const { return iterCount; }
|
||||
private:
|
||||
void setRectInMask();
|
||||
void setLblsInMask( int flags, Point p, bool isPr );
|
||||
|
||||
const string* winName;
|
||||
const Mat* image;
|
||||
Mat mask;
|
||||
Mat bgdModel, fgdModel;
|
||||
|
||||
uchar rectState, lblsState, prLblsState;
|
||||
bool isInitialized;
|
||||
|
||||
Rect rect;
|
||||
vector<Point> fgdPxls, bgdPxls, prFgdPxls, prBgdPxls;
|
||||
int iterCount;
|
||||
};
|
||||
|
||||
void GCApplication::reset()
|
||||
{
|
||||
if( !mask.empty() )
|
||||
mask.setTo(Scalar::all(GC_BGD));
|
||||
bgdPxls.clear(); fgdPxls.clear();
|
||||
prBgdPxls.clear(); prFgdPxls.clear();
|
||||
|
||||
isInitialized = false;
|
||||
rectState = NOT_SET;
|
||||
lblsState = NOT_SET;
|
||||
prLblsState = NOT_SET;
|
||||
iterCount = 0;
|
||||
}
|
||||
|
||||
void GCApplication::setImageAndWinName( const Mat& _image, const string& _winName )
|
||||
{
|
||||
if( _image.empty() || _winName.empty() )
|
||||
return;
|
||||
image = &_image;
|
||||
winName = &_winName;
|
||||
mask.create( image->size(), CV_8UC1);
|
||||
reset();
|
||||
}
|
||||
|
||||
void GCApplication::showImage() const
|
||||
{
|
||||
if( image->empty() || winName->empty() )
|
||||
return;
|
||||
|
||||
Mat res;
|
||||
Mat binMask;
|
||||
if( !isInitialized )
|
||||
image->copyTo( res );
|
||||
else
|
||||
{
|
||||
getBinMask( mask, binMask );
|
||||
image->copyTo( res, binMask );
|
||||
}
|
||||
|
||||
vector<Point>::const_iterator it;
|
||||
for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it )
|
||||
circle( res, *it, radius, BLUE, thickness );
|
||||
for( it = fgdPxls.begin(); it != fgdPxls.end(); ++it )
|
||||
circle( res, *it, radius, RED, thickness );
|
||||
for( it = prBgdPxls.begin(); it != prBgdPxls.end(); ++it )
|
||||
circle( res, *it, radius, LIGHTBLUE, thickness );
|
||||
for( it = prFgdPxls.begin(); it != prFgdPxls.end(); ++it )
|
||||
circle( res, *it, radius, PINK, thickness );
|
||||
|
||||
if( rectState == IN_PROCESS || rectState == SET )
|
||||
rectangle( res, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2);
|
||||
|
||||
imshow( *winName, res );
|
||||
}
|
||||
|
||||
void GCApplication::setRectInMask()
|
||||
{
|
||||
assert( !mask.empty() );
|
||||
mask.setTo( GC_BGD );
|
||||
rect.x = max(0, rect.x);
|
||||
rect.y = max(0, rect.y);
|
||||
rect.width = min(rect.width, image->cols-rect.x);
|
||||
rect.height = min(rect.height, image->rows-rect.y);
|
||||
(mask(rect)).setTo( Scalar(GC_PR_FGD) );
|
||||
}
|
||||
|
||||
void GCApplication::setLblsInMask( int flags, Point p, bool isPr )
|
||||
{
|
||||
vector<Point> *bpxls, *fpxls;
|
||||
uchar bvalue, fvalue;
|
||||
if( !isPr )
|
||||
{
|
||||
bpxls = &bgdPxls;
|
||||
fpxls = &fgdPxls;
|
||||
bvalue = GC_BGD;
|
||||
fvalue = GC_FGD;
|
||||
}
|
||||
else
|
||||
{
|
||||
bpxls = &prBgdPxls;
|
||||
fpxls = &prFgdPxls;
|
||||
bvalue = GC_PR_BGD;
|
||||
fvalue = GC_PR_FGD;
|
||||
}
|
||||
if( flags & BGD_KEY )
|
||||
{
|
||||
bpxls->push_back(p);
|
||||
circle( mask, p, radius, bvalue, thickness );
|
||||
}
|
||||
if( flags & FGD_KEY )
|
||||
{
|
||||
fpxls->push_back(p);
|
||||
circle( mask, p, radius, fvalue, thickness );
|
||||
}
|
||||
}
|
||||
|
||||
void GCApplication::mouseClick( int event, int x, int y, int flags, void* )
|
||||
{
|
||||
// TODO add bad args check
|
||||
switch( event )
|
||||
{
|
||||
case CV_EVENT_LBUTTONDOWN: // set rect or GC_BGD(GC_FGD) labels
|
||||
{
|
||||
bool isb = (flags & BGD_KEY) != 0,
|
||||
isf = (flags & FGD_KEY) != 0;
|
||||
if( rectState == NOT_SET && !isb && !isf )
|
||||
{
|
||||
rectState = IN_PROCESS;
|
||||
rect = Rect( x, y, 1, 1 );
|
||||
}
|
||||
if ( (isb || isf) && rectState == SET )
|
||||
lblsState = IN_PROCESS;
|
||||
}
|
||||
break;
|
||||
case CV_EVENT_RBUTTONDOWN: // set GC_PR_BGD(GC_PR_FGD) labels
|
||||
{
|
||||
bool isb = (flags & BGD_KEY) != 0,
|
||||
isf = (flags & FGD_KEY) != 0;
|
||||
if ( (isb || isf) && rectState == SET )
|
||||
prLblsState = IN_PROCESS;
|
||||
}
|
||||
break;
|
||||
case CV_EVENT_LBUTTONUP:
|
||||
if( rectState == IN_PROCESS )
|
||||
{
|
||||
rect = Rect( Point(rect.x, rect.y), Point(x,y) );
|
||||
rectState = SET;
|
||||
setRectInMask();
|
||||
assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
|
||||
showImage();
|
||||
}
|
||||
if( lblsState == IN_PROCESS )
|
||||
{
|
||||
setLblsInMask(flags, Point(x,y), false);
|
||||
lblsState = SET;
|
||||
showImage();
|
||||
}
|
||||
break;
|
||||
case CV_EVENT_RBUTTONUP:
|
||||
if( prLblsState == IN_PROCESS )
|
||||
{
|
||||
setLblsInMask(flags, Point(x,y), true);
|
||||
prLblsState = SET;
|
||||
showImage();
|
||||
}
|
||||
break;
|
||||
case CV_EVENT_MOUSEMOVE:
|
||||
if( rectState == IN_PROCESS )
|
||||
{
|
||||
rect = Rect( Point(rect.x, rect.y), Point(x,y) );
|
||||
assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
|
||||
showImage();
|
||||
}
|
||||
else if( lblsState == IN_PROCESS )
|
||||
{
|
||||
setLblsInMask(flags, Point(x,y), false);
|
||||
showImage();
|
||||
}
|
||||
else if( prLblsState == IN_PROCESS )
|
||||
{
|
||||
setLblsInMask(flags, Point(x,y), true);
|
||||
showImage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int GCApplication::nextIter()
|
||||
{
|
||||
if( isInitialized )
|
||||
grabCut( *image, mask, rect, bgdModel, fgdModel, 1 );
|
||||
else
|
||||
{
|
||||
if( rectState != SET )
|
||||
return iterCount;
|
||||
|
||||
if( lblsState == SET || prLblsState == SET )
|
||||
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK );
|
||||
else
|
||||
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT );
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
iterCount++;
|
||||
|
||||
bgdPxls.clear(); fgdPxls.clear();
|
||||
prBgdPxls.clear(); prFgdPxls.clear();
|
||||
|
||||
return iterCount;
|
||||
}
|
||||
|
||||
GCApplication gcapp;
|
||||
|
||||
void on_mouse( int event, int x, int y, int flags, void* param )
|
||||
{
|
||||
gcapp.mouseClick( event, x, y, flags, param );
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
if( argc==1 )
|
||||
return 1;
|
||||
string filename = argv[1];
|
||||
if( filename.empty() )
|
||||
return 1;
|
||||
Mat image = imread( filename, 1 );
|
||||
if( image.empty() )
|
||||
return 1;
|
||||
|
||||
cout << "First, select the rectangular area\n" <<
|
||||
"Hot keys: \n"
|
||||
"\tESC - quit the program\n"
|
||||
"\tr - restore the original image\n"
|
||||
"\tn - next iteration\n"
|
||||
"\n"
|
||||
"\tleft mouse button - set rectangle\n"
|
||||
"\n"
|
||||
"\tCTRL+left mouse button - set GC_BGD pixels\n"
|
||||
"\tSHIFT+left mouse button - set CG_FGD pixels\n"
|
||||
"\n"
|
||||
"\tCTRL+right mouse button - set GC_PR_BGD pixels\n"
|
||||
"\tSHIFT+right mouse button - set CG_PR_FGD pixels\n";
|
||||
|
||||
const string winName = "image";
|
||||
cvNamedWindow( winName.c_str(), CV_WINDOW_AUTOSIZE );
|
||||
cvSetMouseCallback( winName.c_str(), on_mouse, 0 );
|
||||
|
||||
gcapp.setImageAndWinName( image, winName );
|
||||
gcapp.showImage();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int c = cvWaitKey(0);
|
||||
switch( (char) c )
|
||||
{
|
||||
case '\x1b':
|
||||
cout << "Exiting ..." << endl;
|
||||
goto exit_main;
|
||||
case 'r':
|
||||
cout << endl;
|
||||
gcapp.reset();
|
||||
gcapp.showImage();
|
||||
break;
|
||||
case 'n':
|
||||
int iterCount = gcapp.getIterCount();
|
||||
cout << "<" << iterCount << "... ";
|
||||
int newIterCount = gcapp.nextIter();
|
||||
if( newIterCount > iterCount )
|
||||
{
|
||||
gcapp.showImage();
|
||||
cout << iterCount << ">" << endl;
|
||||
}
|
||||
else
|
||||
cout << "rect must be determined>" << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit_main:
|
||||
cvDestroyWindow( winName.c_str() );
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/core/core.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
const int MAX_CLUSTERS = 5;
|
||||
Scalar colorTab[] =
|
||||
{
|
||||
Scalar(0, 0, 255),
|
||||
Scalar(0,255,0),
|
||||
Scalar(255,100,100),
|
||||
Scalar(255,0,255),
|
||||
Scalar(0,255,255)
|
||||
};
|
||||
|
||||
Mat img(500, 500, CV_8UC3);
|
||||
RNG rng(12345);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int k, clusterCount = rng.uniform(2, MAX_CLUSTERS+1);
|
||||
int i, sampleCount = rng.uniform(1, 1001);
|
||||
Mat points(sampleCount, 1, CV_32FC2), labels;
|
||||
|
||||
clusterCount = MIN(clusterCount, sampleCount);
|
||||
Mat centers(clusterCount, 1, points.type());
|
||||
|
||||
/* generate random sample from multigaussian distribution */
|
||||
for( k = 0; k < clusterCount; k++ )
|
||||
{
|
||||
Point center;
|
||||
center.x = rng.uniform(0, img.cols);
|
||||
center.y = rng.uniform(0, img.rows);
|
||||
Mat pointChunk = points.rowRange(k*sampleCount/clusterCount,
|
||||
k == clusterCount - 1 ? sampleCount :
|
||||
(k+1)*sampleCount/clusterCount);
|
||||
rng.fill(pointChunk, CV_RAND_NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
|
||||
}
|
||||
|
||||
randShuffle(points, 1, &rng);
|
||||
|
||||
kmeans(points, clusterCount, labels,
|
||||
TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
|
||||
3, KMEANS_PP_CENTERS, ¢ers);
|
||||
|
||||
img = Scalar::all(0);
|
||||
|
||||
for( i = 0; i < sampleCount; i++ )
|
||||
{
|
||||
int clusterIdx = labels.at<int>(i);
|
||||
Point ipt = points.at<Point2f>(i);
|
||||
circle( img, ipt, 2, colorTab[clusterIdx], CV_FILLED, CV_AA );
|
||||
}
|
||||
|
||||
imshow("clusters", img);
|
||||
|
||||
char key = (char)waitKey();
|
||||
if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
int sigma = 3;
|
||||
int smoothType = CV_GAUSSIAN;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
VideoCapture cap;
|
||||
|
||||
if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
|
||||
cap.open(argc == 2 ? argv[1][0] - '0' : 0);
|
||||
else if( argc == 2 )
|
||||
cap.open(argv[1]);
|
||||
|
||||
if( !cap.isOpened() )
|
||||
{
|
||||
cout << "Could not initialize capturing...\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
namedWindow( "Laplacian", 0 );
|
||||
createTrackbar( "Sigma", "Laplacian", &sigma, 15, 0 );
|
||||
|
||||
Mat smoothed, laplace, result;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Mat frame;
|
||||
cap >> frame;
|
||||
if( frame.empty() )
|
||||
break;
|
||||
|
||||
int ksize = (sigma*5)|1;
|
||||
if(smoothType == CV_GAUSSIAN)
|
||||
GaussianBlur(frame, smoothed, Size(ksize, ksize), sigma, sigma);
|
||||
else if(smoothType == CV_BLUR)
|
||||
blur(frame, smoothed, Size(ksize, ksize));
|
||||
else
|
||||
medianBlur(frame, smoothed, ksize);
|
||||
|
||||
Laplacian(smoothed, laplace, CV_16S, 5);
|
||||
convertScaleAbs(laplace, result, (sigma+1)*0.25);
|
||||
imshow("Laplacian", result);
|
||||
|
||||
int c = waitKey(30);
|
||||
if( c == ' ' )
|
||||
smoothType = smoothType == CV_GAUSSIAN ? CV_BLUR : smoothType == CV_BLUR ? CV_MEDIAN : CV_GAUSSIAN;
|
||||
if( c == 'q' || c == 'Q' || (c & 255) == 27 )
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,530 @@
|
||||
#include "opencv2/core/core_c.h"
|
||||
#include "opencv2/ml/ml.hpp"
|
||||
|
||||
/*
|
||||
The sample demonstrates how to train Random Trees classifier
|
||||
(or Boosting classifier, or MLP - see main()) using the provided dataset.
|
||||
|
||||
We use the sample database letter-recognition.data
|
||||
from UCI Repository, here is the link:
|
||||
|
||||
Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998).
|
||||
UCI Repository of machine learning databases
|
||||
[http://www.ics.uci.edu/~mlearn/MLRepository.html].
|
||||
Irvine, CA: University of California, Department of Information and Computer Science.
|
||||
|
||||
The dataset consists of 20000 feature vectors along with the
|
||||
responses - capital latin letters A..Z.
|
||||
The first 16000 (10000 for boosting)) samples are used for training
|
||||
and the remaining 4000 (10000 for boosting) - to test the classifier.
|
||||
*/
|
||||
|
||||
// This function reads data and responses from the file <filename>
|
||||
static int
|
||||
read_num_class_data( const char* filename, int var_count,
|
||||
CvMat** data, CvMat** responses )
|
||||
{
|
||||
const int M = 1024;
|
||||
FILE* f = fopen( filename, "rt" );
|
||||
CvMemStorage* storage;
|
||||
CvSeq* seq;
|
||||
char buf[M+2];
|
||||
float* el_ptr;
|
||||
CvSeqReader reader;
|
||||
int i, j;
|
||||
|
||||
if( !f )
|
||||
return 0;
|
||||
|
||||
el_ptr = new float[var_count+1];
|
||||
storage = cvCreateMemStorage();
|
||||
seq = cvCreateSeq( 0, sizeof(*seq), (var_count+1)*sizeof(float), storage );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char* ptr;
|
||||
if( !fgets( buf, M, f ) || !strchr( buf, ',' ) )
|
||||
break;
|
||||
el_ptr[0] = buf[0];
|
||||
ptr = buf+2;
|
||||
for( i = 1; i <= var_count; i++ )
|
||||
{
|
||||
int n = 0;
|
||||
sscanf( ptr, "%f%n", el_ptr + i, &n );
|
||||
ptr += n + 1;
|
||||
}
|
||||
if( i <= var_count )
|
||||
break;
|
||||
cvSeqPush( seq, el_ptr );
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
*data = cvCreateMat( seq->total, var_count, CV_32F );
|
||||
*responses = cvCreateMat( seq->total, 1, CV_32F );
|
||||
|
||||
cvStartReadSeq( seq, &reader );
|
||||
|
||||
for( i = 0; i < seq->total; i++ )
|
||||
{
|
||||
const float* sdata = (float*)reader.ptr + 1;
|
||||
float* ddata = data[0]->data.fl + var_count*i;
|
||||
float* dr = responses[0]->data.fl + i;
|
||||
|
||||
for( j = 0; j < var_count; j++ )
|
||||
ddata[j] = sdata[j];
|
||||
*dr = sdata[-1];
|
||||
CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
|
||||
}
|
||||
|
||||
cvReleaseMemStorage( &storage );
|
||||
delete el_ptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static
|
||||
int build_rtrees_classifier( char* data_filename,
|
||||
char* filename_to_save, char* filename_to_load )
|
||||
{
|
||||
CvMat* data = 0;
|
||||
CvMat* responses = 0;
|
||||
CvMat* var_type = 0;
|
||||
CvMat* sample_idx = 0;
|
||||
|
||||
int ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
int nsamples_all = 0, ntrain_samples = 0;
|
||||
int i = 0;
|
||||
double train_hr = 0, test_hr = 0;
|
||||
CvRTrees forest;
|
||||
CvMat* var_importance = 0;
|
||||
|
||||
if( !ok )
|
||||
{
|
||||
printf( "Could not read the database %s\n", data_filename );
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf( "The database %s is loaded.\n", data_filename );
|
||||
nsamples_all = data->rows;
|
||||
ntrain_samples = (int)(nsamples_all*0.8);
|
||||
|
||||
// Create or load Random Trees classifier
|
||||
if( filename_to_load )
|
||||
{
|
||||
// load classifier from the specified file
|
||||
forest.load( filename_to_load );
|
||||
ntrain_samples = 0;
|
||||
if( forest.get_tree_count() == 0 )
|
||||
{
|
||||
printf( "Could not read the classifier %s\n", filename_to_load );
|
||||
return -1;
|
||||
}
|
||||
printf( "The classifier %s is loaded.\n", data_filename );
|
||||
}
|
||||
else
|
||||
{
|
||||
// create classifier by using <data> and <responses>
|
||||
printf( "Training the classifier ...\n");
|
||||
|
||||
// 1. create type mask
|
||||
var_type = cvCreateMat( data->cols + 1, 1, CV_8U );
|
||||
cvSet( var_type, cvScalarAll(CV_VAR_ORDERED) );
|
||||
cvSetReal1D( var_type, data->cols, CV_VAR_CATEGORICAL );
|
||||
|
||||
// 2. create sample_idx
|
||||
sample_idx = cvCreateMat( 1, nsamples_all, CV_8UC1 );
|
||||
{
|
||||
CvMat mat;
|
||||
cvGetCols( sample_idx, &mat, 0, ntrain_samples );
|
||||
cvSet( &mat, cvRealScalar(1) );
|
||||
|
||||
cvGetCols( sample_idx, &mat, ntrain_samples, nsamples_all );
|
||||
cvSetZero( &mat );
|
||||
}
|
||||
|
||||
// 3. train classifier
|
||||
forest.train( data, CV_ROW_SAMPLE, responses, 0, sample_idx, var_type, 0,
|
||||
CvRTParams(10,10,0,false,15,0,true,4,100,0.01f,CV_TERMCRIT_ITER));
|
||||
printf( "\n");
|
||||
}
|
||||
|
||||
// compute prediction error on train and test data
|
||||
for( i = 0; i < nsamples_all; i++ )
|
||||
{
|
||||
double r;
|
||||
CvMat sample;
|
||||
cvGetRow( data, &sample, i );
|
||||
|
||||
r = forest.predict( &sample );
|
||||
r = fabs((double)r - responses->data.fl[i]) <= FLT_EPSILON ? 1 : 0;
|
||||
|
||||
if( i < ntrain_samples )
|
||||
train_hr += r;
|
||||
else
|
||||
test_hr += r;
|
||||
}
|
||||
|
||||
test_hr /= (double)(nsamples_all-ntrain_samples);
|
||||
train_hr /= (double)ntrain_samples;
|
||||
printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
|
||||
train_hr*100., test_hr*100. );
|
||||
|
||||
printf( "Number of trees: %d\n", forest.get_tree_count() );
|
||||
|
||||
// Print variable importance
|
||||
var_importance = (CvMat*)forest.get_var_importance();
|
||||
if( var_importance )
|
||||
{
|
||||
double rt_imp_sum = cvSum( var_importance ).val[0];
|
||||
printf("var#\timportance (in %%):\n");
|
||||
for( i = 0; i < var_importance->cols; i++ )
|
||||
printf( "%-2d\t%-4.1f\n", i,
|
||||
100.f*var_importance->data.fl[i]/rt_imp_sum);
|
||||
}
|
||||
|
||||
//Print some proximitites
|
||||
printf( "Proximities between some samples corresponding to the letter 'T':\n" );
|
||||
{
|
||||
CvMat sample1, sample2;
|
||||
const int pairs[][2] = {{0,103}, {0,106}, {106,103}, {-1,-1}};
|
||||
|
||||
for( i = 0; pairs[i][0] >= 0; i++ )
|
||||
{
|
||||
cvGetRow( data, &sample1, pairs[i][0] );
|
||||
cvGetRow( data, &sample2, pairs[i][1] );
|
||||
printf( "proximity(%d,%d) = %.1f%%\n", pairs[i][0], pairs[i][1],
|
||||
forest.get_proximity( &sample1, &sample2 )*100. );
|
||||
}
|
||||
}
|
||||
|
||||
// Save Random Trees classifier to file if needed
|
||||
if( filename_to_save )
|
||||
forest.save( filename_to_save );
|
||||
|
||||
cvReleaseMat( &sample_idx );
|
||||
cvReleaseMat( &var_type );
|
||||
cvReleaseMat( &data );
|
||||
cvReleaseMat( &responses );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int build_boost_classifier( char* data_filename,
|
||||
char* filename_to_save, char* filename_to_load )
|
||||
{
|
||||
const int class_count = 26;
|
||||
CvMat* data = 0;
|
||||
CvMat* responses = 0;
|
||||
CvMat* var_type = 0;
|
||||
CvMat* temp_sample = 0;
|
||||
CvMat* weak_responses = 0;
|
||||
|
||||
int ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
int nsamples_all = 0, ntrain_samples = 0;
|
||||
int var_count;
|
||||
int i, j, k;
|
||||
double train_hr = 0, test_hr = 0;
|
||||
CvBoost boost;
|
||||
|
||||
if( !ok )
|
||||
{
|
||||
printf( "Could not read the database %s\n", data_filename );
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf( "The database %s is loaded.\n", data_filename );
|
||||
nsamples_all = data->rows;
|
||||
ntrain_samples = (int)(nsamples_all*0.5);
|
||||
var_count = data->cols;
|
||||
|
||||
// Create or load Boosted Tree classifier
|
||||
if( filename_to_load )
|
||||
{
|
||||
// load classifier from the specified file
|
||||
boost.load( filename_to_load );
|
||||
ntrain_samples = 0;
|
||||
if( !boost.get_weak_predictors() )
|
||||
{
|
||||
printf( "Could not read the classifier %s\n", filename_to_load );
|
||||
return -1;
|
||||
}
|
||||
printf( "The classifier %s is loaded.\n", data_filename );
|
||||
}
|
||||
else
|
||||
{
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
//
|
||||
// As currently boosted tree classifier in MLL can only be trained
|
||||
// for 2-class problems, we transform the training database by
|
||||
// "unrolling" each training sample as many times as the number of
|
||||
// classes (26) that we have.
|
||||
//
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
CvMat* new_data = cvCreateMat( ntrain_samples*class_count, var_count + 1, CV_32F );
|
||||
CvMat* new_responses = cvCreateMat( ntrain_samples*class_count, 1, CV_32S );
|
||||
|
||||
// 1. unroll the database type mask
|
||||
printf( "Unrolling the database...\n");
|
||||
for( i = 0; i < ntrain_samples; i++ )
|
||||
{
|
||||
float* data_row = (float*)(data->data.ptr + data->step*i);
|
||||
for( j = 0; j < class_count; j++ )
|
||||
{
|
||||
float* new_data_row = (float*)(new_data->data.ptr +
|
||||
new_data->step*(i*class_count+j));
|
||||
for( k = 0; k < var_count; k++ )
|
||||
new_data_row[k] = data_row[k];
|
||||
new_data_row[var_count] = (float)j;
|
||||
new_responses->data.i[i*class_count + j] = responses->data.fl[i] == j+'A';
|
||||
}
|
||||
}
|
||||
|
||||
// 2. create type mask
|
||||
var_type = cvCreateMat( var_count + 2, 1, CV_8U );
|
||||
cvSet( var_type, cvScalarAll(CV_VAR_ORDERED) );
|
||||
// the last indicator variable, as well
|
||||
// as the new (binary) response are categorical
|
||||
cvSetReal1D( var_type, var_count, CV_VAR_CATEGORICAL );
|
||||
cvSetReal1D( var_type, var_count+1, CV_VAR_CATEGORICAL );
|
||||
|
||||
// 3. train classifier
|
||||
printf( "Training the classifier (may take a few minutes)...\n");
|
||||
boost.train( new_data, CV_ROW_SAMPLE, new_responses, 0, 0, var_type, 0,
|
||||
CvBoostParams(CvBoost::REAL, 100, 0.95, 5, false, 0 ));
|
||||
cvReleaseMat( &new_data );
|
||||
cvReleaseMat( &new_responses );
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
temp_sample = cvCreateMat( 1, var_count + 1, CV_32F );
|
||||
weak_responses = cvCreateMat( 1, boost.get_weak_predictors()->total, CV_32F );
|
||||
|
||||
// compute prediction error on train and test data
|
||||
for( i = 0; i < nsamples_all; i++ )
|
||||
{
|
||||
int best_class = 0;
|
||||
double max_sum = -DBL_MAX;
|
||||
double r;
|
||||
CvMat sample;
|
||||
cvGetRow( data, &sample, i );
|
||||
for( k = 0; k < var_count; k++ )
|
||||
temp_sample->data.fl[k] = sample.data.fl[k];
|
||||
|
||||
for( j = 0; j < class_count; j++ )
|
||||
{
|
||||
temp_sample->data.fl[var_count] = (float)j;
|
||||
boost.predict( temp_sample, 0, weak_responses );
|
||||
double sum = cvSum( weak_responses ).val[0];
|
||||
if( max_sum < sum )
|
||||
{
|
||||
max_sum = sum;
|
||||
best_class = j + 'A';
|
||||
}
|
||||
}
|
||||
|
||||
r = fabs(best_class - responses->data.fl[i]) < FLT_EPSILON ? 1 : 0;
|
||||
|
||||
if( i < ntrain_samples )
|
||||
train_hr += r;
|
||||
else
|
||||
test_hr += r;
|
||||
}
|
||||
|
||||
test_hr /= (double)(nsamples_all-ntrain_samples);
|
||||
train_hr /= (double)ntrain_samples;
|
||||
printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
|
||||
train_hr*100., test_hr*100. );
|
||||
|
||||
printf( "Number of trees: %d\n", boost.get_weak_predictors()->total );
|
||||
|
||||
// Save classifier to file if needed
|
||||
if( filename_to_save )
|
||||
boost.save( filename_to_save );
|
||||
|
||||
cvReleaseMat( &temp_sample );
|
||||
cvReleaseMat( &weak_responses );
|
||||
cvReleaseMat( &var_type );
|
||||
cvReleaseMat( &data );
|
||||
cvReleaseMat( &responses );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int build_mlp_classifier( char* data_filename,
|
||||
char* filename_to_save, char* filename_to_load )
|
||||
{
|
||||
const int class_count = 26;
|
||||
CvMat* data = 0;
|
||||
CvMat train_data;
|
||||
CvMat* responses = 0;
|
||||
CvMat* mlp_response = 0;
|
||||
|
||||
int ok = read_num_class_data( data_filename, 16, &data, &responses );
|
||||
int nsamples_all = 0, ntrain_samples = 0;
|
||||
int i, j;
|
||||
double train_hr = 0, test_hr = 0;
|
||||
CvANN_MLP mlp;
|
||||
|
||||
if( !ok )
|
||||
{
|
||||
printf( "Could not read the database %s\n", data_filename );
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf( "The database %s is loaded.\n", data_filename );
|
||||
nsamples_all = data->rows;
|
||||
ntrain_samples = (int)(nsamples_all*0.8);
|
||||
|
||||
// Create or load MLP classifier
|
||||
if( filename_to_load )
|
||||
{
|
||||
// load classifier from the specified file
|
||||
mlp.load( filename_to_load );
|
||||
ntrain_samples = 0;
|
||||
if( !mlp.get_layer_count() )
|
||||
{
|
||||
printf( "Could not read the classifier %s\n", filename_to_load );
|
||||
return -1;
|
||||
}
|
||||
printf( "The classifier %s is loaded.\n", data_filename );
|
||||
}
|
||||
else
|
||||
{
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
//
|
||||
// MLP does not support categorical variables by explicitly.
|
||||
// So, instead of the output class label, we will use
|
||||
// a binary vector of <class_count> components for training and,
|
||||
// therefore, MLP will give us a vector of "probabilities" at the
|
||||
// prediction stage
|
||||
//
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
CvMat* new_responses = cvCreateMat( ntrain_samples, class_count, CV_32F );
|
||||
|
||||
// 1. unroll the responses
|
||||
printf( "Unrolling the responses...\n");
|
||||
for( i = 0; i < ntrain_samples; i++ )
|
||||
{
|
||||
int cls_label = cvRound(responses->data.fl[i]) - 'A';
|
||||
float* bit_vec = (float*)(new_responses->data.ptr + i*new_responses->step);
|
||||
for( j = 0; j < class_count; j++ )
|
||||
bit_vec[j] = 0.f;
|
||||
bit_vec[cls_label] = 1.f;
|
||||
}
|
||||
cvGetRows( data, &train_data, 0, ntrain_samples );
|
||||
|
||||
// 2. train classifier
|
||||
int layer_sz[] = { data->cols, 100, 100, class_count };
|
||||
CvMat layer_sizes =
|
||||
cvMat( 1, (int)(sizeof(layer_sz)/sizeof(layer_sz[0])), CV_32S, layer_sz );
|
||||
mlp.create( &layer_sizes );
|
||||
printf( "Training the classifier (may take a few minutes)...\n");
|
||||
mlp.train( &train_data, new_responses, 0, 0,
|
||||
CvANN_MLP_TrainParams(cvTermCriteria(CV_TERMCRIT_ITER,300,0.01),
|
||||
#if 1
|
||||
CvANN_MLP_TrainParams::BACKPROP,0.001));
|
||||
#else
|
||||
CvANN_MLP_TrainParams::RPROP,0.05));
|
||||
#endif
|
||||
cvReleaseMat( &new_responses );
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
mlp_response = cvCreateMat( 1, class_count, CV_32F );
|
||||
|
||||
// compute prediction error on train and test data
|
||||
for( i = 0; i < nsamples_all; i++ )
|
||||
{
|
||||
int best_class;
|
||||
CvMat sample;
|
||||
cvGetRow( data, &sample, i );
|
||||
CvPoint max_loc = {0,0};
|
||||
mlp.predict( &sample, mlp_response );
|
||||
cvMinMaxLoc( mlp_response, 0, 0, 0, &max_loc, 0 );
|
||||
best_class = max_loc.x + 'A';
|
||||
|
||||
int r = fabs((double)best_class - responses->data.fl[i]) < FLT_EPSILON ? 1 : 0;
|
||||
|
||||
if( i < ntrain_samples )
|
||||
train_hr += r;
|
||||
else
|
||||
test_hr += r;
|
||||
}
|
||||
|
||||
test_hr /= (double)(nsamples_all-ntrain_samples);
|
||||
train_hr /= (double)ntrain_samples;
|
||||
printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
|
||||
train_hr*100., test_hr*100. );
|
||||
|
||||
// Save classifier to file if needed
|
||||
if( filename_to_save )
|
||||
mlp.save( filename_to_save );
|
||||
|
||||
cvReleaseMat( &mlp_response );
|
||||
cvReleaseMat( &data );
|
||||
cvReleaseMat( &responses );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
char* filename_to_save = 0;
|
||||
char* filename_to_load = 0;
|
||||
char default_data_filename[] = "./letter-recognition.data";
|
||||
char* data_filename = default_data_filename;
|
||||
int method = 0;
|
||||
|
||||
int i;
|
||||
for( i = 1; i < argc; i++ )
|
||||
{
|
||||
if( strcmp(argv[i],"-data") == 0 ) // flag "-data letter_recognition.xml"
|
||||
{
|
||||
i++;
|
||||
data_filename = argv[i];
|
||||
}
|
||||
else if( strcmp(argv[i],"-save") == 0 ) // flag "-save filename.xml"
|
||||
{
|
||||
i++;
|
||||
filename_to_save = argv[i];
|
||||
}
|
||||
else if( strcmp(argv[i],"-load") == 0) // flag "-load filename.xml"
|
||||
{
|
||||
i++;
|
||||
filename_to_load = argv[i];
|
||||
}
|
||||
else if( strcmp(argv[i],"-boost") == 0)
|
||||
{
|
||||
method = 1;
|
||||
}
|
||||
else if( strcmp(argv[i],"-mlp") == 0 )
|
||||
{
|
||||
method = 2;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if( i < argc ||
|
||||
(method == 0 ?
|
||||
build_rtrees_classifier( data_filename, filename_to_save, filename_to_load ) :
|
||||
method == 1 ?
|
||||
build_boost_classifier( data_filename, filename_to_save, filename_to_load ) :
|
||||
method == 2 ?
|
||||
build_mlp_classifier( data_filename, filename_to_save, filename_to_load ) :
|
||||
-1) < 0)
|
||||
{
|
||||
printf("This is letter recognition sample.\n"
|
||||
"The usage: letter_recog [-data <path to letter-recognition.data>] \\\n"
|
||||
" [-save <output XML file for the classifier>] \\\n"
|
||||
" [-load <XML file with the pre-trained classifier>] \\\n"
|
||||
" [-boost|-mlp] # to use boost/mlp classifier instead of default Random Trees\n" );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
IplImage *image = 0, *grey = 0, *prev_grey = 0, *pyramid = 0, *prev_pyramid = 0, *swap_temp;
|
||||
|
||||
int win_size = 10;
|
||||
const int MAX_COUNT = 500;
|
||||
CvPoint2D32f* points[2] = {0,0}, *swap_points;
|
||||
char* status = 0;
|
||||
int count = 0;
|
||||
int need_to_init = 0;
|
||||
int night_mode = 0;
|
||||
int flags = 0;
|
||||
int add_remove_pt = 0;
|
||||
CvPoint pt;
|
||||
|
||||
|
||||
void on_mouse( int event, int x, int y, int flags, void* param )
|
||||
{
|
||||
if( !image )
|
||||
return;
|
||||
|
||||
if( image->origin )
|
||||
y = image->height - y;
|
||||
|
||||
if( event == CV_EVENT_LBUTTONDOWN )
|
||||
{
|
||||
pt = cvPoint(x,y);
|
||||
add_remove_pt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
CvCapture* capture = 0;
|
||||
|
||||
if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
|
||||
capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
|
||||
else if( argc == 2 )
|
||||
capture = cvCaptureFromAVI( argv[1] );
|
||||
|
||||
if( !capture )
|
||||
{
|
||||
fprintf(stderr,"Could not initialize capturing...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* print a welcome message, and the OpenCV version */
|
||||
printf ("Welcome to lkdemo, using OpenCV version %s (%d.%d.%d)\n",
|
||||
CV_VERSION,
|
||||
CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
|
||||
|
||||
printf( "Hot keys: \n"
|
||||
"\tESC - quit the program\n"
|
||||
"\tr - auto-initialize tracking\n"
|
||||
"\tc - delete all the points\n"
|
||||
"\tn - switch the \"night\" mode on/off\n"
|
||||
"To add/remove a feature point click it\n" );
|
||||
|
||||
cvNamedWindow( "LkDemo", 0 );
|
||||
cvSetMouseCallback( "LkDemo", on_mouse, 0 );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
IplImage* frame = 0;
|
||||
int i, k, c;
|
||||
|
||||
frame = cvQueryFrame( capture );
|
||||
if( !frame )
|
||||
break;
|
||||
|
||||
if( !image )
|
||||
{
|
||||
/* allocate all the buffers */
|
||||
image = cvCreateImage( cvGetSize(frame), 8, 3 );
|
||||
image->origin = frame->origin;
|
||||
grey = cvCreateImage( cvGetSize(frame), 8, 1 );
|
||||
prev_grey = cvCreateImage( cvGetSize(frame), 8, 1 );
|
||||
pyramid = cvCreateImage( cvGetSize(frame), 8, 1 );
|
||||
prev_pyramid = cvCreateImage( cvGetSize(frame), 8, 1 );
|
||||
points[0] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
|
||||
points[1] = (CvPoint2D32f*)cvAlloc(MAX_COUNT*sizeof(points[0][0]));
|
||||
status = (char*)cvAlloc(MAX_COUNT);
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
cvCopy( frame, image, 0 );
|
||||
cvCvtColor( image, grey, CV_BGR2GRAY );
|
||||
|
||||
if( night_mode )
|
||||
cvZero( image );
|
||||
|
||||
if( need_to_init )
|
||||
{
|
||||
/* automatic initialization */
|
||||
IplImage* eig = cvCreateImage( cvGetSize(grey), 32, 1 );
|
||||
IplImage* temp = cvCreateImage( cvGetSize(grey), 32, 1 );
|
||||
double quality = 0.01;
|
||||
double min_distance = 10;
|
||||
|
||||
count = MAX_COUNT;
|
||||
cvGoodFeaturesToTrack( grey, eig, temp, points[1], &count,
|
||||
quality, min_distance, 0, 3, 0, 0.04 );
|
||||
cvFindCornerSubPix( grey, points[1], count,
|
||||
cvSize(win_size,win_size), cvSize(-1,-1),
|
||||
cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
|
||||
cvReleaseImage( &eig );
|
||||
cvReleaseImage( &temp );
|
||||
|
||||
add_remove_pt = 0;
|
||||
}
|
||||
else if( count > 0 )
|
||||
{
|
||||
cvCalcOpticalFlowPyrLK( prev_grey, grey, prev_pyramid, pyramid,
|
||||
points[0], points[1], count, cvSize(win_size,win_size), 3, status, 0,
|
||||
cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03), flags );
|
||||
flags |= CV_LKFLOW_PYR_A_READY;
|
||||
for( i = k = 0; i < count; i++ )
|
||||
{
|
||||
if( add_remove_pt )
|
||||
{
|
||||
double dx = pt.x - points[1][i].x;
|
||||
double dy = pt.y - points[1][i].y;
|
||||
|
||||
if( dx*dx + dy*dy <= 25 )
|
||||
{
|
||||
add_remove_pt = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( !status[i] )
|
||||
continue;
|
||||
|
||||
points[1][k++] = points[1][i];
|
||||
cvCircle( image, cvPointFrom32f(points[1][i]), 3, CV_RGB(0,255,0), -1, 8,0);
|
||||
}
|
||||
count = k;
|
||||
}
|
||||
|
||||
if( add_remove_pt && count < MAX_COUNT )
|
||||
{
|
||||
points[1][count++] = cvPointTo32f(pt);
|
||||
cvFindCornerSubPix( grey, points[1] + count - 1, 1,
|
||||
cvSize(win_size,win_size), cvSize(-1,-1),
|
||||
cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
|
||||
add_remove_pt = 0;
|
||||
}
|
||||
|
||||
CV_SWAP( prev_grey, grey, swap_temp );
|
||||
CV_SWAP( prev_pyramid, pyramid, swap_temp );
|
||||
CV_SWAP( points[0], points[1], swap_points );
|
||||
need_to_init = 0;
|
||||
cvShowImage( "LkDemo", image );
|
||||
|
||||
c = cvWaitKey(10);
|
||||
if( (char)c == 27 )
|
||||
break;
|
||||
switch( (char) c )
|
||||
{
|
||||
case 'r':
|
||||
need_to_init = 1;
|
||||
break;
|
||||
case 'c':
|
||||
count = 0;
|
||||
break;
|
||||
case 'n':
|
||||
night_mode ^= 1;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
cvReleaseCapture( &capture );
|
||||
cvDestroyWindow("LkDemo");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _EiC
|
||||
main(1,"lkdemo.c");
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
Mat img(500, 500, CV_8UC3);
|
||||
RNG& rng = theRNG();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int i, count = rng.uniform(1, 101);
|
||||
vector<Point> points;
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
Point pt;
|
||||
pt.x = rng.uniform(img.cols/4, img.cols*3/4);
|
||||
pt.y = rng.uniform(img.rows/4, img.rows*3/4);
|
||||
|
||||
points.push_back(pt);
|
||||
}
|
||||
|
||||
RotatedRect box = minAreaRect(Mat(points));
|
||||
Point2f center, vtx[4];
|
||||
float radius = 0;
|
||||
minEnclosingCircle(Mat(points), center, radius);
|
||||
box.points(vtx);
|
||||
|
||||
img = Scalar::all(0);
|
||||
for( i = 0; i < count; i++ )
|
||||
circle( img, points[i], 3, Scalar(0, 0, 255), CV_FILLED, CV_AA );
|
||||
|
||||
for( i = 0; i < 4; i++ )
|
||||
line(img, vtx[i], vtx[(i+1)%4], Scalar(0, 255, 0), 1, CV_AA);
|
||||
|
||||
circle(img, center, cvRound(radius), Scalar(0, 255, 255), 1, CV_AA);
|
||||
|
||||
imshow( "rect & circle", img );
|
||||
|
||||
char key = (char)cvWaitKey();
|
||||
if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
#include "opencv2/objdetect/objdetect.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Mat img;
|
||||
FILE* f = 0;
|
||||
char _filename[1024];
|
||||
|
||||
if( argc == 1 )
|
||||
{
|
||||
printf("Usage: peopledetect (<image_filename> | <image_list>.txt)\n");
|
||||
return 0;
|
||||
}
|
||||
img = imread(argv[1]);
|
||||
|
||||
if( img.data )
|
||||
{
|
||||
strcpy(_filename, argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
f = fopen(argv[1], "rt");
|
||||
if(!f)
|
||||
{
|
||||
fprintf( stderr, "ERROR: the specified file could not be loaded\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
HOGDescriptor hog;
|
||||
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
|
||||
namedWindow("people detector", 1);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char* filename = _filename;
|
||||
if(f)
|
||||
{
|
||||
if(!fgets(filename, (int)sizeof(_filename)-2, f))
|
||||
break;
|
||||
//while(*filename && isspace(*filename))
|
||||
// ++filename;
|
||||
if(filename[0] == '#')
|
||||
continue;
|
||||
int l = strlen(filename);
|
||||
while(l > 0 && isspace(filename[l-1]))
|
||||
--l;
|
||||
filename[l] = '\0';
|
||||
img = imread(filename);
|
||||
}
|
||||
printf("%s:\n", filename);
|
||||
if(!img.data)
|
||||
continue;
|
||||
|
||||
fflush(stdout);
|
||||
vector<Rect> found, found_filtered;
|
||||
double t = (double)getTickCount();
|
||||
// run the detector with default parameters. to get a higher hit-rate
|
||||
// (and more false alarms, respectively), decrease the hitThreshold and
|
||||
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
|
||||
hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2);
|
||||
t = (double)getTickCount() - t;
|
||||
printf("tdetection time = %gms\n", t*1000./cv::getTickFrequency());
|
||||
size_t i, j;
|
||||
for( i = 0; i < found.size(); i++ )
|
||||
{
|
||||
Rect r = found[i];
|
||||
for( j = 0; j < found.size(); j++ )
|
||||
if( j != i && (r & found[j]) == r)
|
||||
break;
|
||||
if( j == found.size() )
|
||||
found_filtered.push_back(r);
|
||||
}
|
||||
for( i = 0; i < found_filtered.size(); i++ )
|
||||
{
|
||||
Rect r = found_filtered[i];
|
||||
// the HOG detector returns slightly larger rectangles than the real objects.
|
||||
// so we slightly shrink the rectangles to get a nicer output.
|
||||
r.x += cvRound(r.width*0.1);
|
||||
r.width = cvRound(r.width*0.8);
|
||||
r.y += cvRound(r.height*0.07);
|
||||
r.height = cvRound(r.height*0.8);
|
||||
rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
|
||||
}
|
||||
imshow("people detector", img);
|
||||
int c = waitKey(0) & 255;
|
||||
if( c == 'q' || c == 'Q' || !f)
|
||||
break;
|
||||
}
|
||||
if(f)
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,154 @@
|
||||
// The "Square Detector" program.
|
||||
// It loads several images subsequentally and tries to find squares in
|
||||
// each image
|
||||
|
||||
#include "opencv2/core/core.hpp"
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
int thresh = 50, N = 11;
|
||||
const char* wndname = "Square Detection Demo";
|
||||
|
||||
// helper function:
|
||||
// finds a cosine of angle between vectors
|
||||
// from pt0->pt1 and from pt0->pt2
|
||||
double angle( Point pt1, Point pt2, Point pt0 )
|
||||
{
|
||||
double dx1 = pt1.x - pt0.x;
|
||||
double dy1 = pt1.y - pt0.y;
|
||||
double dx2 = pt2.x - pt0.x;
|
||||
double dy2 = pt2.y - pt0.y;
|
||||
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
|
||||
}
|
||||
|
||||
// returns sequence of squares detected on the image.
|
||||
// the sequence is stored in the specified memory storage
|
||||
void findSquares( const Mat& image, vector<vector<Point> >& squares )
|
||||
{
|
||||
squares.clear();
|
||||
|
||||
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
|
||||
|
||||
// down-scale and upscale the image to filter out the noise
|
||||
pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
|
||||
pyrUp(pyr, timg, image.size());
|
||||
vector<vector<Point> > contours;
|
||||
|
||||
// find squares in every color plane of the image
|
||||
for( int c = 0; c < 3; c++ )
|
||||
{
|
||||
int ch[] = {c, 0};
|
||||
mixChannels(&timg, 1, &gray0, 1, ch, 1);
|
||||
|
||||
// try several threshold levels
|
||||
for( int l = 0; l < N; l++ )
|
||||
{
|
||||
// hack: use Canny instead of zero threshold level.
|
||||
// Canny helps to catch squares with gradient shading
|
||||
if( l == 0 )
|
||||
{
|
||||
// apply Canny. Take the upper threshold from slider
|
||||
// and set the lower to 0 (which forces edges merging)
|
||||
Canny(gray0, gray, 0, thresh, 5);
|
||||
// dilate canny output to remove potential
|
||||
// holes between edge segments
|
||||
dilate(gray, gray, Mat(), Point(-1,-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// apply threshold if l!=0:
|
||||
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
|
||||
gray = gray0 >= (l+1)*255/N;
|
||||
}
|
||||
|
||||
// find contours and store them all as a list
|
||||
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
|
||||
|
||||
vector<Point> approx;
|
||||
|
||||
// test each contour
|
||||
for( size_t i = 0; i < contours.size(); i++ )
|
||||
{
|
||||
// approximate contour with accuracy proportional
|
||||
// to the contour perimeter
|
||||
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);
|
||||
|
||||
// square contours should have 4 vertices after approximation
|
||||
// relatively large area (to filter out noisy contours)
|
||||
// and be convex.
|
||||
// Note: absolute value of an area is used because
|
||||
// area may be positive or negative - in accordance with the
|
||||
// contour orientation
|
||||
if( approx.size() == 4 &&
|
||||
fabs(contourArea(Mat(approx))) > 1000 &&
|
||||
isContourConvex(Mat(approx)) )
|
||||
{
|
||||
double maxCosine = 0;
|
||||
|
||||
for( int j = 2; j < 5; j++ )
|
||||
{
|
||||
// find the maximum cosine of the angle between joint edges
|
||||
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
|
||||
maxCosine = MAX(maxCosine, cosine);
|
||||
}
|
||||
|
||||
// if cosines of all angles are small
|
||||
// (all angles are ~90 degree) then write quandrange
|
||||
// vertices to resultant sequence
|
||||
if( maxCosine < 0.3 )
|
||||
squares.push_back(approx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the function draws all the squares in the image
|
||||
void drawSquares( Mat& image, const vector<vector<Point> >& squares )
|
||||
{
|
||||
for( size_t i = 0; i < squares.size(); i++ )
|
||||
{
|
||||
const Point* p = &squares[i][0];
|
||||
int n = (int)squares[i].size();
|
||||
polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);
|
||||
}
|
||||
|
||||
imshow(wndname, image);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
static const char* names[] = { "pic1.png", "pic2.png", "pic3.png",
|
||||
"pic4.png", "pic5.png", "pic6.png", 0 };
|
||||
|
||||
namedWindow( wndname, 1 );
|
||||
vector<vector<Point> > squares;
|
||||
|
||||
for( int i = 0; names[i] != 0; i++ )
|
||||
{
|
||||
Mat image = imread(names[i], 1);
|
||||
if( image.empty() )
|
||||
{
|
||||
cout << "Couldn't load " << names[i] << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
findSquares(image, squares);
|
||||
drawSquares(image, squares);
|
||||
|
||||
int c = waitKey();
|
||||
if( (char)c == 27 )
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
/* This is sample from the OpenCV book. The copyright notice is below */
|
||||
|
||||
/* *************** License:**************************
|
||||
Oct. 3, 2008
|
||||
Right to use this code in any way you want without warrenty, support or any guarentee of it working.
|
||||
|
||||
BOOK: It would be nice if you cited it:
|
||||
Learning OpenCV: Computer Vision with the OpenCV Library
|
||||
by Gary Bradski and Adrian Kaehler
|
||||
Published by O'Reilly Media, October 3, 2008
|
||||
|
||||
AVAILABLE AT:
|
||||
http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134
|
||||
Or: http://oreilly.com/catalog/9780596516130/
|
||||
ISBN-10: 0596516134 or: ISBN-13: 978-0596516130
|
||||
|
||||
OTHER OPENCV SITES:
|
||||
* The source code is on sourceforge at:
|
||||
http://sourceforge.net/projects/opencvlibrary/
|
||||
* The OpenCV wiki page (As of Oct 1, 2008 this is down for changing over servers, but should come back):
|
||||
http://opencvlibrary.sourceforge.net/
|
||||
* An active user group is at:
|
||||
http://tech.groups.yahoo.com/group/OpenCV/
|
||||
* The minutes of weekly OpenCV development meetings are at:
|
||||
http://pr.willowgarage.com/wiki/OpenCV
|
||||
************************************************** */
|
||||
|
||||
#include "opencv2/calib3d/calib3d.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/imgproc/imgproc_c.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//
|
||||
// Given a list of chessboard images, the number of corners (nx, ny)
|
||||
// on the chessboards, and a flag: useCalibrated for calibrated (0) or
|
||||
// uncalibrated (1: use cvStereoCalibrate(), 2: compute fundamental
|
||||
// matrix separately) stereo. Calibrate the cameras and display the
|
||||
// rectified results along with the computed disparity images.
|
||||
//
|
||||
static void
|
||||
StereoCalib(const char* path, const char* imageList, int useUncalibrated)
|
||||
{
|
||||
CvRect roi1, roi2;
|
||||
int nx = 0, ny = 0;
|
||||
int displayCorners = 1;
|
||||
int showUndistorted = 1;
|
||||
bool isVerticalStereo = false;//OpenCV can handle left-right
|
||||
//or up-down camera arrangements
|
||||
const int maxScale = 1;
|
||||
const float squareSize = 1.f; //Set this to your actual square size
|
||||
FILE* f = fopen(imageList, "rt");
|
||||
int i, j, lr, nframes = 0, n, N = 0;
|
||||
vector<string> imageNames[2];
|
||||
vector<CvPoint3D32f> objectPoints;
|
||||
vector<CvPoint2D32f> points[2];
|
||||
vector<CvPoint2D32f> temp_points[2];
|
||||
vector<int> npoints;
|
||||
// vector<uchar> active[2];
|
||||
int is_found[2] = {0, 0};
|
||||
vector<CvPoint2D32f> temp;
|
||||
CvSize imageSize = {0,0};
|
||||
// ARRAY AND VECTOR STORAGE:
|
||||
double M1[3][3], M2[3][3], D1[5], D2[5];
|
||||
double R[3][3], T[3], E[3][3], F[3][3];
|
||||
double Q[4][4];
|
||||
CvMat _M1 = cvMat(3, 3, CV_64F, M1 );
|
||||
CvMat _M2 = cvMat(3, 3, CV_64F, M2 );
|
||||
CvMat _D1 = cvMat(1, 5, CV_64F, D1 );
|
||||
CvMat _D2 = cvMat(1, 5, CV_64F, D2 );
|
||||
CvMat matR = cvMat(3, 3, CV_64F, R );
|
||||
CvMat matT = cvMat(3, 1, CV_64F, T );
|
||||
CvMat matE = cvMat(3, 3, CV_64F, E );
|
||||
CvMat matF = cvMat(3, 3, CV_64F, F );
|
||||
|
||||
CvMat matQ = cvMat(4, 4, CV_64FC1, Q);
|
||||
|
||||
char buf[1024];
|
||||
|
||||
if( displayCorners )
|
||||
cvNamedWindow( "corners", 1 );
|
||||
// READ IN THE LIST OF CHESSBOARDS:
|
||||
if( !f )
|
||||
{
|
||||
fprintf(stderr, "can not open file %s\n", imageList );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !fgets(buf, sizeof(buf)-3, f) || sscanf(buf, "%d%d", &nx, &ny) != 2 )
|
||||
return;
|
||||
n = nx*ny;
|
||||
temp.resize(n);
|
||||
temp_points[0].resize(n);
|
||||
temp_points[1].resize(n);
|
||||
|
||||
for(i=0;;i++)
|
||||
{
|
||||
int count = 0, result=0;
|
||||
lr = i % 2;
|
||||
vector<CvPoint2D32f>& pts = temp_points[lr];//points[lr];
|
||||
if( !fgets( buf, sizeof(buf)-3, f ))
|
||||
break;
|
||||
size_t len = strlen(buf);
|
||||
while( len > 0 && isspace(buf[len-1]))
|
||||
buf[--len] = '\0';
|
||||
if( buf[0] == '#')
|
||||
continue;
|
||||
char fullpath[1024];
|
||||
sprintf(fullpath, "%s/%s", path, buf);
|
||||
IplImage* img = cvLoadImage( fullpath, 0 );
|
||||
if( !img )
|
||||
{
|
||||
printf("Cannot read file %s\n", fullpath);
|
||||
return;
|
||||
}
|
||||
imageSize = cvGetSize(img);
|
||||
imageNames[lr].push_back(buf);
|
||||
//FIND CHESSBOARDS AND CORNERS THEREIN:
|
||||
for( int s = 1; s <= maxScale; s++ )
|
||||
{
|
||||
IplImage* timg = img;
|
||||
if( s > 1 )
|
||||
{
|
||||
timg = cvCreateImage(cvSize(img->width*s,img->height*s),
|
||||
img->depth, img->nChannels );
|
||||
cvResize( img, timg, CV_INTER_CUBIC );
|
||||
}
|
||||
result = cvFindChessboardCorners( timg, cvSize(nx, ny),
|
||||
&temp[0], &count,
|
||||
CV_CALIB_CB_ADAPTIVE_THRESH |
|
||||
CV_CALIB_CB_NORMALIZE_IMAGE);
|
||||
if( timg != img )
|
||||
cvReleaseImage( &timg );
|
||||
if( result || s == maxScale )
|
||||
for( j = 0; j < count; j++ )
|
||||
{
|
||||
temp[j].x /= s;
|
||||
temp[j].y /= s;
|
||||
}
|
||||
if( result )
|
||||
break;
|
||||
}
|
||||
if( displayCorners )
|
||||
{
|
||||
printf("%s\n", buf);
|
||||
IplImage* cimg = cvCreateImage( imageSize, 8, 3 );
|
||||
cvCvtColor( img, cimg, CV_GRAY2BGR );
|
||||
cvDrawChessboardCorners( cimg, cvSize(nx, ny), &temp[0],
|
||||
count, result );
|
||||
IplImage* cimg1 = cvCreateImage(cvSize(640, 480), IPL_DEPTH_8U, 3);
|
||||
cvResize(cimg, cimg1);
|
||||
cvShowImage( "corners", cimg1 );
|
||||
cvReleaseImage( &cimg );
|
||||
cvReleaseImage( &cimg1 );
|
||||
int c = cvWaitKey(1000);
|
||||
if( c == 27 || c == 'q' || c == 'Q' ) //Allow ESC to quit
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
putchar('.');
|
||||
//N = pts.size();
|
||||
//pts.resize(N + n, cvPoint2D32f(0,0));
|
||||
//active[lr].push_back((uchar)result);
|
||||
is_found[lr] = result > 0 ? 1 : 0;
|
||||
//assert( result != 0 );
|
||||
if( result )
|
||||
{
|
||||
//Calibration will suffer without subpixel interpolation
|
||||
cvFindCornerSubPix( img, &temp[0], count,
|
||||
cvSize(11, 11), cvSize(-1,-1),
|
||||
cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,
|
||||
30, 0.01) );
|
||||
copy( temp.begin(), temp.end(), pts.begin() );
|
||||
}
|
||||
cvReleaseImage( &img );
|
||||
|
||||
if(lr)
|
||||
{
|
||||
if(is_found[0] == 1 && is_found[1] == 1)
|
||||
{
|
||||
assert(temp_points[0].size() == temp_points[1].size());
|
||||
int current_size = points[0].size();
|
||||
|
||||
points[0].resize(current_size + temp_points[0].size(), cvPoint2D32f(0.0, 0.0));
|
||||
points[1].resize(current_size + temp_points[1].size(), cvPoint2D32f(0.0, 0.0));
|
||||
|
||||
copy(temp_points[0].begin(), temp_points[0].end(), points[0].begin() + current_size);
|
||||
copy(temp_points[1].begin(), temp_points[1].end(), points[1].begin() + current_size);
|
||||
|
||||
nframes++;
|
||||
|
||||
printf("Pair successfully detected...\n");
|
||||
}
|
||||
|
||||
is_found[0] = 0;
|
||||
is_found[1] = 0;
|
||||
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
printf("\n");
|
||||
// HARVEST CHESSBOARD 3D OBJECT POINT LIST:
|
||||
objectPoints.resize(nframes*n);
|
||||
for( i = 0; i < ny; i++ )
|
||||
for( j = 0; j < nx; j++ )
|
||||
objectPoints[i*nx + j] =
|
||||
cvPoint3D32f(i*squareSize, j*squareSize, 0);
|
||||
for( i = 1; i < nframes; i++ )
|
||||
copy( objectPoints.begin(), objectPoints.begin() + n,
|
||||
objectPoints.begin() + i*n );
|
||||
npoints.resize(nframes,n);
|
||||
N = nframes*n;
|
||||
CvMat _objectPoints = cvMat(1, N, CV_32FC3, &objectPoints[0] );
|
||||
CvMat _imagePoints1 = cvMat(1, N, CV_32FC2, &points[0][0] );
|
||||
CvMat _imagePoints2 = cvMat(1, N, CV_32FC2, &points[1][0] );
|
||||
CvMat _npoints = cvMat(1, npoints.size(), CV_32S, &npoints[0] );
|
||||
cvSetIdentity(&_M1);
|
||||
cvSetIdentity(&_M2);
|
||||
cvZero(&_D1);
|
||||
cvZero(&_D2);
|
||||
|
||||
// CALIBRATE THE STEREO CAMERAS
|
||||
printf("Running stereo calibration ...");
|
||||
fflush(stdout);
|
||||
cvStereoCalibrate( &_objectPoints, &_imagePoints1,
|
||||
&_imagePoints2, &_npoints,
|
||||
&_M1, &_D1, &_M2, &_D2,
|
||||
imageSize, &matR, &matT, &matE, &matF,
|
||||
cvTermCriteria(CV_TERMCRIT_ITER+
|
||||
CV_TERMCRIT_EPS, 100, 1e-5),
|
||||
CV_CALIB_FIX_ASPECT_RATIO +
|
||||
CV_CALIB_ZERO_TANGENT_DIST +
|
||||
CV_CALIB_SAME_FOCAL_LENGTH +
|
||||
CV_CALIB_FIX_K3);
|
||||
printf(" done\n");
|
||||
|
||||
// CALIBRATION QUALITY CHECK
|
||||
// because the output fundamental matrix implicitly
|
||||
// includes all the output information,
|
||||
// we can check the quality of calibration using the
|
||||
// epipolar geometry constraint: m2^t*F*m1=0
|
||||
vector<CvPoint3D32f> lines[2];
|
||||
points[0].resize(N);
|
||||
points[1].resize(N);
|
||||
_imagePoints1 = cvMat(1, N, CV_32FC2, &points[0][0] );
|
||||
_imagePoints2 = cvMat(1, N, CV_32FC2, &points[1][0] );
|
||||
lines[0].resize(N);
|
||||
lines[1].resize(N);
|
||||
CvMat _L1 = cvMat(1, N, CV_32FC3, &lines[0][0]);
|
||||
CvMat _L2 = cvMat(1, N, CV_32FC3, &lines[1][0]);
|
||||
//Always work in undistorted space
|
||||
cvUndistortPoints( &_imagePoints1, &_imagePoints1,
|
||||
&_M1, &_D1, 0, &_M1 );
|
||||
cvUndistortPoints( &_imagePoints2, &_imagePoints2,
|
||||
&_M2, &_D2, 0, &_M2 );
|
||||
cvComputeCorrespondEpilines( &_imagePoints1, 1, &matF, &_L1 );
|
||||
cvComputeCorrespondEpilines( &_imagePoints2, 2, &matF, &_L2 );
|
||||
double avgErr = 0;
|
||||
for( i = 0; i < N; i++ )
|
||||
{
|
||||
double err = fabs(points[0][i].x*lines[1][i].x +
|
||||
points[0][i].y*lines[1][i].y + lines[1][i].z)
|
||||
+ fabs(points[1][i].x*lines[0][i].x +
|
||||
points[1][i].y*lines[0][i].y + lines[0][i].z);
|
||||
avgErr += err;
|
||||
}
|
||||
printf( "avg err = %g\n", avgErr/(nframes*n) );
|
||||
|
||||
// save intrinsic parameters
|
||||
CvFileStorage* fstorage = cvOpenFileStorage("intrinsics.yml", NULL, CV_STORAGE_WRITE);
|
||||
cvWrite(fstorage, "M1", &_M1);
|
||||
cvWrite(fstorage, "D1", &_D1);
|
||||
cvWrite(fstorage, "M2", &_M2);
|
||||
cvWrite(fstorage, "D2", &_D2);
|
||||
cvReleaseFileStorage(&fstorage);
|
||||
|
||||
//COMPUTE AND DISPLAY RECTIFICATION
|
||||
if( showUndistorted )
|
||||
{
|
||||
CvMat* mx1 = cvCreateMat( imageSize.height,
|
||||
imageSize.width, CV_32F );
|
||||
CvMat* my1 = cvCreateMat( imageSize.height,
|
||||
imageSize.width, CV_32F );
|
||||
CvMat* mx2 = cvCreateMat( imageSize.height,
|
||||
imageSize.width, CV_32F );
|
||||
CvMat* my2 = cvCreateMat( imageSize.height,
|
||||
imageSize.width, CV_32F );
|
||||
CvMat* img1r = cvCreateMat( imageSize.height,
|
||||
imageSize.width, CV_8U );
|
||||
CvMat* img2r = cvCreateMat( imageSize.height,
|
||||
imageSize.width, CV_8U );
|
||||
CvMat* disp = cvCreateMat( imageSize.height,
|
||||
imageSize.width, CV_16S );
|
||||
double R1[3][3], R2[3][3], P1[3][4], P2[3][4];
|
||||
CvMat _R1 = cvMat(3, 3, CV_64F, R1);
|
||||
CvMat _R2 = cvMat(3, 3, CV_64F, R2);
|
||||
// IF BY CALIBRATED (BOUGUET'S METHOD)
|
||||
if( useUncalibrated == 0 )
|
||||
{
|
||||
CvMat _P1 = cvMat(3, 4, CV_64F, P1);
|
||||
CvMat _P2 = cvMat(3, 4, CV_64F, P2);
|
||||
|
||||
cvStereoRectify( &_M1, &_M2, &_D1, &_D2, imageSize,
|
||||
&matR, &matT,
|
||||
&_R1, &_R2, &_P1, &_P2, &matQ,
|
||||
CV_CALIB_ZERO_DISPARITY,
|
||||
1, imageSize, &roi1, &roi2);
|
||||
|
||||
CvFileStorage* file = cvOpenFileStorage("extrinsics.yml", NULL, CV_STORAGE_WRITE);
|
||||
cvWrite(file, "R", &matR);
|
||||
cvWrite(file, "T", &matT);
|
||||
cvWrite(file, "R1", &_R1);
|
||||
cvWrite(file, "R2", &_R2);
|
||||
cvWrite(file, "P1", &_P1);
|
||||
cvWrite(file, "P2", &_P2);
|
||||
cvWrite(file, "Q", &matQ);
|
||||
cvReleaseFileStorage(&file);
|
||||
|
||||
isVerticalStereo = fabs(P2[1][3]) > fabs(P2[0][3]);
|
||||
if(!isVerticalStereo)
|
||||
roi2.x += imageSize.width;
|
||||
else
|
||||
roi2.y += imageSize.height;
|
||||
//Precompute maps for cvRemap()
|
||||
cvInitUndistortRectifyMap(&_M1,&_D1,&_R1,&_P1,mx1,my1);
|
||||
cvInitUndistortRectifyMap(&_M2,&_D2,&_R2,&_P2,mx2,my2);
|
||||
}
|
||||
//OR ELSE HARTLEY'S METHOD
|
||||
else if( useUncalibrated == 1 || useUncalibrated == 2 )
|
||||
// use intrinsic parameters of each camera, but
|
||||
// compute the rectification transformation directly
|
||||
// from the fundamental matrix
|
||||
{
|
||||
double H1[3][3], H2[3][3], iM[3][3];
|
||||
CvMat _H1 = cvMat(3, 3, CV_64F, H1);
|
||||
CvMat _H2 = cvMat(3, 3, CV_64F, H2);
|
||||
CvMat _iM = cvMat(3, 3, CV_64F, iM);
|
||||
//Just to show you could have independently used F
|
||||
if( useUncalibrated == 2 )
|
||||
cvFindFundamentalMat( &_imagePoints1,
|
||||
&_imagePoints2, &matF);
|
||||
cvStereoRectifyUncalibrated( &_imagePoints1,
|
||||
&_imagePoints2, &matF,
|
||||
imageSize,
|
||||
&_H1, &_H2, 3);
|
||||
cvInvert(&_M1, &_iM);
|
||||
cvMatMul(&_H1, &_M1, &_R1);
|
||||
cvMatMul(&_iM, &_R1, &_R1);
|
||||
cvInvert(&_M2, &_iM);
|
||||
cvMatMul(&_H2, &_M2, &_R2);
|
||||
cvMatMul(&_iM, &_R2, &_R2);
|
||||
//Precompute map for cvRemap()
|
||||
cvInitUndistortRectifyMap(&_M1,&_D1,&_R1,&_M1,mx1,my1);
|
||||
|
||||
cvInitUndistortRectifyMap(&_M2,&_D1,&_R2,&_M2,mx2,my2);
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
|
||||
cvReleaseMat( &mx1 );
|
||||
cvReleaseMat( &my1 );
|
||||
cvReleaseMat( &mx2 );
|
||||
cvReleaseMat( &my2 );
|
||||
cvReleaseMat( &img1r );
|
||||
cvReleaseMat( &img2r );
|
||||
cvReleaseMat( &disp );
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if(argc > 1 && !strcmp(argv[1], "--help"))
|
||||
{
|
||||
printf("Usage:\n ./stereo_calib <path to images> <file wtih image list>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
StereoCalib(argc > 1 ? argv[1] : ".", argc > 2 ? argv[2] : "stereo_calib.txt", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
9 6
|
||||
left01.jpg
|
||||
right01.jpg
|
||||
left02.jpg
|
||||
right02.jpg
|
||||
left03.jpg
|
||||
right03.jpg
|
||||
left04.jpg
|
||||
right04.jpg
|
||||
left05.jpg
|
||||
right05.jpg
|
||||
left06.jpg
|
||||
right06.jpg
|
||||
left07.jpg
|
||||
right07.jpg
|
||||
left08.jpg
|
||||
right08.jpg
|
||||
left09.jpg
|
||||
right09.jpg
|
||||
left11.jpg
|
||||
right11.jpg
|
||||
left12.jpg
|
||||
right12.jpg
|
||||
left13.jpg
|
||||
right13.jpg
|
||||
left14.jpg
|
||||
right14.jpg
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* stereo_match.cpp
|
||||
* calibration
|
||||
*
|
||||
* Created by Victor Eruhimov on 1/18/10.
|
||||
* Copyright 2010 Argus Corp. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opencv2/calib3d/calib3d.hpp"
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
void saveXYZ(const char* filename, const Mat& mat)
|
||||
{
|
||||
const double max_z = 1.0e4;
|
||||
FILE* fp = fopen(filename, "wt");
|
||||
for(int y = 0; y < mat.rows; y++)
|
||||
{
|
||||
for(int x = 0; x < mat.cols; x++)
|
||||
{
|
||||
Vec3f point = mat.at<Vec3f>(y, x);
|
||||
if(fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue;
|
||||
fprintf(fp, "%f %f %f\n", point[0], point[1], point[2]);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void print_help()
|
||||
{
|
||||
printf("Usage: stereo_match <left_image> <right_image> [--algorithm=bm|sgbm|hh] [--blocksize=<block_size>]\n"
|
||||
"[--max-disparity=<max_disparity>] [-i <intrinsic_filename>] [-e <extrinsic_filename>]\n"
|
||||
"[--no-display] [-o <disparity_image>] [-p <point_cloud_file>]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* algorithm_opt = "--algorithm=";
|
||||
const char* maxdisp_opt = "--max-disparity=";
|
||||
const char* blocksize_opt = "--blocksize=";
|
||||
const char* nodisplay_opt = "--no-display=";
|
||||
|
||||
if(argc < 3)
|
||||
{
|
||||
print_help();
|
||||
return 0;
|
||||
}
|
||||
const char* img1_filename = 0;
|
||||
const char* img2_filename = 0;
|
||||
const char* intrinsic_filename = 0;
|
||||
const char* extrinsic_filename = 0;
|
||||
const char* disparity_filename = 0;
|
||||
const char* point_cloud_filename = 0;
|
||||
|
||||
enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2 };
|
||||
int alg = STEREO_SGBM;
|
||||
int SADWindowSize = 0, numberOfDisparities = 0;
|
||||
bool no_display = false;
|
||||
|
||||
StereoBM bm;
|
||||
StereoSGBM sgbm;
|
||||
|
||||
for( int i = 1; i < argc; i++ )
|
||||
{
|
||||
if( argv[i][0] != '-' )
|
||||
{
|
||||
if( !img1_filename )
|
||||
img1_filename = argv[i];
|
||||
else
|
||||
img2_filename = argv[i];
|
||||
}
|
||||
else if( strncmp(argv[i], algorithm_opt, strlen(algorithm_opt)) == 0 )
|
||||
{
|
||||
char* _alg = argv[i] + strlen(algorithm_opt);
|
||||
alg = strcmp(_alg, "bm") == 0 ? STEREO_BM :
|
||||
strcmp(_alg, "sgbm") == 0 ? STEREO_SGBM :
|
||||
strcmp(_alg, "hh") == 0 ? STEREO_HH : -1;
|
||||
if( alg < 0 )
|
||||
{
|
||||
printf("Command-line parameter error: Unknown stereo algorithm\n\n");
|
||||
print_help();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( strncmp(argv[i], maxdisp_opt, strlen(maxdisp_opt)) == 0 )
|
||||
{
|
||||
if( sscanf( argv[i] + strlen(maxdisp_opt), "%d", &numberOfDisparities ) != 1 ||
|
||||
numberOfDisparities < 1 || numberOfDisparities % 16 != 0 )
|
||||
{
|
||||
printf("Command-line parameter error: The max disparity (--maxdisparity=<...>) must be a positive integer divisible by 16\n");
|
||||
print_help();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( strncmp(argv[i], blocksize_opt, strlen(blocksize_opt)) == 0 )
|
||||
{
|
||||
if( sscanf( argv[i] + strlen(blocksize_opt), "%d", &SADWindowSize ) != 1 ||
|
||||
SADWindowSize < 1 || SADWindowSize % 2 != 1 )
|
||||
{
|
||||
printf("Command-line parameter error: The block size (--blocksize=<...>) must be a positive odd number\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( strcmp(argv[i], nodisplay_opt) == 0 )
|
||||
no_display = true;
|
||||
else if( strcmp(argv[i], "-i" ) == 0 )
|
||||
intrinsic_filename = argv[++i];
|
||||
else if( strcmp(argv[i], "-e" ) == 0 )
|
||||
extrinsic_filename = argv[++i];
|
||||
else if( strcmp(argv[i], "-o" ) == 0 )
|
||||
disparity_filename = argv[++i];
|
||||
else if( strcmp(argv[i], "-p" ) == 0 )
|
||||
point_cloud_filename = argv[++i];
|
||||
else
|
||||
{
|
||||
printf("Command-line parameter error: unknown option %s\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if( !img1_filename || !img2_filename )
|
||||
{
|
||||
printf("Command-line parameter error: both left and right images must be specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( (intrinsic_filename != 0) ^ (extrinsic_filename != 0) )
|
||||
{
|
||||
printf("Command-line parameter error: either both intrinsic and extrinsic parameters must be specified, or none of them (when the stereo pair is already rectified)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( extrinsic_filename == 0 && point_cloud_filename )
|
||||
{
|
||||
printf("Command-line parameter error: extrinsic and intrinsic parameters must be specified to compute the point cloud\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int color_mode = alg == STEREO_BM ? 0 : -1;
|
||||
Mat img1 = imread(img1_filename, color_mode);
|
||||
Mat img2 = imread(img2_filename, color_mode);
|
||||
Size img_size = img1.size();
|
||||
|
||||
Rect roi1, roi2;
|
||||
Mat Q;
|
||||
|
||||
if( intrinsic_filename )
|
||||
{
|
||||
// reading intrinsic parameters
|
||||
FileStorage fs(intrinsic_filename, CV_STORAGE_READ);
|
||||
if(!fs.isOpened())
|
||||
{
|
||||
printf("Failed to open file %s\n", intrinsic_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat M1, D1, M2, D2;
|
||||
fs["M1"] >> M1;
|
||||
fs["D1"] >> D1;
|
||||
fs["M2"] >> M2;
|
||||
fs["D2"] >> D2;
|
||||
|
||||
fs.open(extrinsic_filename, CV_STORAGE_READ);
|
||||
if(!fs.isOpened())
|
||||
{
|
||||
printf("Failed to open file %s\n", extrinsic_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat R, T, R1, P1, R2, P2;
|
||||
fs["R"] >> R;
|
||||
fs["T"] >> T;
|
||||
|
||||
stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, -1, img_size, &roi1, &roi2 );
|
||||
|
||||
Mat map11, map12, map21, map22;
|
||||
initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);
|
||||
initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);
|
||||
|
||||
Mat img1r, img2r;
|
||||
remap(img1, img1r, map11, map12, INTER_LINEAR);
|
||||
remap(img2, img2r, map21, map22, INTER_LINEAR);
|
||||
|
||||
img1 = img1r;
|
||||
img2 = img2r;
|
||||
}
|
||||
|
||||
numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : img_size.width/8;
|
||||
|
||||
bm.state->roi1 = roi1;
|
||||
bm.state->roi2 = roi2;
|
||||
bm.state->preFilterCap = 31;
|
||||
bm.state->SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 9;
|
||||
bm.state->minDisparity = 0;
|
||||
bm.state->numberOfDisparities = numberOfDisparities;
|
||||
bm.state->textureThreshold = 10;
|
||||
bm.state->uniquenessRatio = 15;
|
||||
bm.state->speckleWindowSize = 100;
|
||||
bm.state->speckleRange = 32;
|
||||
bm.state->disp12MaxDiff = 1;
|
||||
|
||||
sgbm.preFilterCap = 63;
|
||||
sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;
|
||||
|
||||
int cn = img1.channels();
|
||||
|
||||
sgbm.P1 = 8*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
|
||||
sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
|
||||
sgbm.minDisparity = 0;
|
||||
sgbm.numberOfDisparities = numberOfDisparities;
|
||||
sgbm.uniquenessRatio = 10;
|
||||
sgbm.speckleWindowSize = bm.state->speckleWindowSize;
|
||||
sgbm.speckleRange = bm.state->speckleRange;
|
||||
sgbm.disp12MaxDiff = 1;
|
||||
sgbm.fullDP = alg == STEREO_HH;
|
||||
|
||||
Mat disp, disp8;
|
||||
//Mat img1p, img2p, dispp;
|
||||
//copyMakeBorder(img1, img1p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
|
||||
//copyMakeBorder(img2, img2p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
|
||||
|
||||
int64 t = getTickCount();
|
||||
if( alg == STEREO_BM )
|
||||
bm(img1, img2, disp);
|
||||
else
|
||||
sgbm(img1, img2, disp);
|
||||
t = getTickCount() - t;
|
||||
printf("Time elapsed: %fms\n", t*1000/getTickFrequency());
|
||||
|
||||
//disp = dispp.colRange(numberOfDisparities, img1p.cols);
|
||||
disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
|
||||
if( !no_display )
|
||||
{
|
||||
namedWindow("left", 1);
|
||||
imshow("left", img1);
|
||||
namedWindow("right", 1);
|
||||
imshow("right", img2);
|
||||
namedWindow("disparity", 0);
|
||||
imshow("disparity", disp8);
|
||||
printf("press any key to continue...");
|
||||
fflush(stdout);
|
||||
waitKey();
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if(disparity_filename)
|
||||
imwrite(disparity_filename, disp8);
|
||||
|
||||
if(point_cloud_filename)
|
||||
{
|
||||
printf("storing the point cloud...");
|
||||
fflush(stdout);
|
||||
Mat xyz;
|
||||
reprojectImageTo3D(disp, xyz, Q, true);
|
||||
saveXYZ(point_cloud_filename, xyz);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,127 @@
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
Mat markerMask, img;
|
||||
Point prevPt(-1, -1);
|
||||
|
||||
void onMouse( int event, int x, int y, int flags, void* )
|
||||
{
|
||||
if( x < 0 || x >= img.cols || y < 0 || y >= img.rows )
|
||||
return;
|
||||
if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )
|
||||
prevPt = Point(-1,-1);
|
||||
else if( event == CV_EVENT_LBUTTONDOWN )
|
||||
prevPt = Point(x,y);
|
||||
else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) )
|
||||
{
|
||||
Point pt(x, y);
|
||||
if( prevPt.x < 0 )
|
||||
prevPt = pt;
|
||||
line( markerMask, prevPt, pt, Scalar::all(255), 5, 8, 0 );
|
||||
line( img, prevPt, pt, Scalar::all(255), 5, 8, 0 );
|
||||
prevPt = pt;
|
||||
imshow("image", img);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
char* filename = argc >= 2 ? argv[1] : (char*)"fruits.jpg";
|
||||
Mat img0 = imread(filename, 1), imgGray;
|
||||
|
||||
if( img0.empty() )
|
||||
{
|
||||
cout << "Usage: watershed <image_name>\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
cout << "Hot keys: \n"
|
||||
"\tESC - quit the program\n"
|
||||
"\tr - restore the original image\n"
|
||||
"\tw or SPACE - run watershed algorithm\n"
|
||||
"\t\t(before running it, roughly mark the areas on the image)\n"
|
||||
"\t (before that, roughly outline several markers on the image)\n";
|
||||
|
||||
namedWindow( "image", 1 );
|
||||
|
||||
img0.copyTo(img);
|
||||
cvtColor(img, markerMask, CV_BGR2GRAY);
|
||||
cvtColor(markerMask, imgGray, CV_GRAY2BGR);
|
||||
markerMask = Scalar::all(0);
|
||||
imshow( "image", img );
|
||||
setMouseCallback( "image", onMouse, 0 );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int c = waitKey(0);
|
||||
|
||||
if( (char)c == 27 )
|
||||
break;
|
||||
|
||||
if( (char)c == 'r' )
|
||||
{
|
||||
markerMask = Scalar::all(0);
|
||||
img0.copyTo(img);
|
||||
imshow( "image", img );
|
||||
}
|
||||
|
||||
if( (char)c == 'w' || (char)c == ' ' )
|
||||
{
|
||||
int i, j, compCount = 0;
|
||||
vector<vector<Point> > contours;
|
||||
vector<Vec4i> hierarchy;
|
||||
|
||||
findContours(markerMask, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
|
||||
|
||||
Mat markers(markerMask.size(), CV_32S);
|
||||
markers = Scalar::all(0);
|
||||
int idx = 0;
|
||||
for( ; idx >= 0; idx = hierarchy[idx][0], compCount++ )
|
||||
drawContours(markers, contours, idx, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX);
|
||||
|
||||
if( compCount == 0 )
|
||||
continue;
|
||||
|
||||
vector<Vec3b> colorTab;
|
||||
for( i = 0; i < compCount; i++ )
|
||||
{
|
||||
int b = theRNG().uniform(180, 230);
|
||||
int g = theRNG().uniform(180, 230);
|
||||
int r = theRNG().uniform(180, 230);
|
||||
|
||||
colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
|
||||
}
|
||||
|
||||
double t = (double)getTickCount();
|
||||
watershed( img0, markers );
|
||||
t = (double)getTickCount() - t;
|
||||
printf( "execution time = %gms\n", t*1000./getTickFrequency() );
|
||||
|
||||
Mat wshed(markers.size(), CV_8UC3);
|
||||
|
||||
// paint the watershed image
|
||||
for( i = 0; i < markers.rows; i++ )
|
||||
for( j = 0; j < markers.cols; j++ )
|
||||
{
|
||||
int idx = markers.at<int>(i,j);
|
||||
if( idx == -1 )
|
||||
wshed.at<Vec3b>(i,j) = Vec3b(255,255,255);
|
||||
else if( idx <= 0 || idx > compCount )
|
||||
wshed.at<Vec3b>(i,j) = Vec3b(0,0,0);
|
||||
else
|
||||
wshed.at<Vec3b>(i,j) = colorTab[idx - 1];
|
||||
}
|
||||
|
||||
wshed = wshed*0.5 + imgGray*0.5;
|
||||
imshow( "watershed transform", wshed );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||