mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge pull request #25252 from gursimarsingh:cpp_samples_cleanup
Move API focused C++ samples to snippets #25252 Clean Samples #25006 This PR removes 39 outdated C++ samples from the project, as part of an effort to keep the codebase clean and focused on current best practices.
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <ctype.h>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
Mat image;
|
||||
|
||||
bool backprojMode = false;
|
||||
bool selectObject = false;
|
||||
int trackObject = 0;
|
||||
bool showHist = true;
|
||||
Point origin;
|
||||
Rect selection;
|
||||
int vmin = 10, vmax = 256, smin = 30;
|
||||
|
||||
// User draws box around object to track. This triggers CAMShift to start tracking
|
||||
static void onMouse( int event, int x, int y, int, void* )
|
||||
{
|
||||
if( selectObject )
|
||||
{
|
||||
selection.x = MIN(x, origin.x);
|
||||
selection.y = MIN(y, origin.y);
|
||||
selection.width = std::abs(x - origin.x);
|
||||
selection.height = std::abs(y - origin.y);
|
||||
|
||||
selection &= Rect(0, 0, image.cols, image.rows);
|
||||
}
|
||||
|
||||
switch( event )
|
||||
{
|
||||
case EVENT_LBUTTONDOWN:
|
||||
origin = Point(x,y);
|
||||
selection = Rect(x,y,0,0);
|
||||
selectObject = true;
|
||||
break;
|
||||
case EVENT_LBUTTONUP:
|
||||
selectObject = false;
|
||||
if( selection.width > 0 && selection.height > 0 )
|
||||
trackObject = -1; // Set up CAMShift properties in main() loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string hot_keys =
|
||||
"\n\nHot 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"
|
||||
"\tp - pause video\n"
|
||||
"To initialize tracking, select the object with mouse\n";
|
||||
|
||||
static void help(const char** argv)
|
||||
{
|
||||
cout << "\nThis is a demo that shows mean-shift based tracking\n"
|
||||
"You select a color objects such as your face and it tracks it.\n"
|
||||
"This reads from video camera (0 by default, or the camera number the user enters\n"
|
||||
"Usage: \n\t";
|
||||
cout << argv[0] << " [camera number]\n";
|
||||
cout << hot_keys;
|
||||
}
|
||||
|
||||
const char* keys =
|
||||
{
|
||||
"{help h | | show help message}{@camera_number| 0 | camera number}"
|
||||
};
|
||||
|
||||
int main( int argc, const char** argv )
|
||||
{
|
||||
VideoCapture cap;
|
||||
Rect trackWindow;
|
||||
int hsize = 16;
|
||||
float hranges[] = {0,180};
|
||||
const float* phranges = hranges;
|
||||
CommandLineParser parser(argc, argv, keys);
|
||||
if (parser.has("help"))
|
||||
{
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
int camNum = parser.get<int>(0);
|
||||
cap.open(camNum);
|
||||
|
||||
if( !cap.isOpened() )
|
||||
{
|
||||
help(argv);
|
||||
cout << "***Could not initialize capturing...***\n";
|
||||
cout << "Current parameter's value: \n";
|
||||
parser.printMessage();
|
||||
return -1;
|
||||
}
|
||||
cout << hot_keys;
|
||||
namedWindow( "Histogram", 0 );
|
||||
namedWindow( "CamShift Demo", 0 );
|
||||
setMouseCallback( "CamShift Demo", onMouse, 0 );
|
||||
createTrackbar( "Vmin", "CamShift Demo", &vmin, 256, 0 );
|
||||
createTrackbar( "Vmax", "CamShift Demo", &vmax, 256, 0 );
|
||||
createTrackbar( "Smin", "CamShift Demo", &smin, 256, 0 );
|
||||
|
||||
Mat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
|
||||
bool paused = false;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if( !paused )
|
||||
{
|
||||
cap >> frame;
|
||||
if( frame.empty() )
|
||||
break;
|
||||
}
|
||||
|
||||
frame.copyTo(image);
|
||||
|
||||
if( !paused )
|
||||
{
|
||||
cvtColor(image, hsv, COLOR_BGR2HSV);
|
||||
|
||||
if( trackObject )
|
||||
{
|
||||
int _vmin = vmin, _vmax = vmax;
|
||||
|
||||
inRange(hsv, Scalar(0, smin, MIN(_vmin,_vmax)),
|
||||
Scalar(180, 256, MAX(_vmin, _vmax)), mask);
|
||||
int ch[] = {0, 0};
|
||||
hue.create(hsv.size(), hsv.depth());
|
||||
mixChannels(&hsv, 1, &hue, 1, ch, 1);
|
||||
|
||||
if( trackObject < 0 )
|
||||
{
|
||||
// Object has been selected by user, set up CAMShift search properties once
|
||||
Mat roi(hue, selection), maskroi(mask, selection);
|
||||
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
|
||||
normalize(hist, hist, 0, 255, NORM_MINMAX);
|
||||
|
||||
trackWindow = selection;
|
||||
trackObject = 1; // Don't set up again, unless user selects new ROI
|
||||
|
||||
histimg = Scalar::all(0);
|
||||
int binW = histimg.cols / hsize;
|
||||
Mat buf(1, hsize, CV_8UC3);
|
||||
for( int i = 0; i < hsize; i++ )
|
||||
buf.at<Vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180./hsize), 255, 255);
|
||||
cvtColor(buf, buf, COLOR_HSV2BGR);
|
||||
|
||||
for( int i = 0; i < hsize; i++ )
|
||||
{
|
||||
int val = saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);
|
||||
rectangle( histimg, Point(i*binW,histimg.rows),
|
||||
Point((i+1)*binW,histimg.rows - val),
|
||||
Scalar(buf.at<Vec3b>(i)), -1, 8 );
|
||||
}
|
||||
}
|
||||
|
||||
// Perform CAMShift
|
||||
calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
|
||||
backproj &= mask;
|
||||
RotatedRect trackBox = CamShift(backproj, trackWindow,
|
||||
TermCriteria( TermCriteria::EPS | TermCriteria::COUNT, 10, 1 ));
|
||||
if( trackWindow.area() <= 1 )
|
||||
{
|
||||
int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
|
||||
trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
|
||||
trackWindow.x + r, trackWindow.y + r) &
|
||||
Rect(0, 0, cols, rows);
|
||||
}
|
||||
|
||||
if( backprojMode )
|
||||
cvtColor( backproj, image, COLOR_GRAY2BGR );
|
||||
ellipse( image, trackBox, Scalar(0,0,255), 3, LINE_AA );
|
||||
}
|
||||
}
|
||||
else if( trackObject < 0 )
|
||||
paused = false;
|
||||
|
||||
if( selectObject && selection.width > 0 && selection.height > 0 )
|
||||
{
|
||||
Mat roi(image, selection);
|
||||
bitwise_not(roi, roi);
|
||||
}
|
||||
|
||||
imshow( "CamShift Demo", image );
|
||||
imshow( "Histogram", histimg );
|
||||
|
||||
char c = (char)waitKey(10);
|
||||
if( c == 27 )
|
||||
break;
|
||||
switch(c)
|
||||
{
|
||||
case 'b':
|
||||
backprojMode = !backprojMode;
|
||||
break;
|
||||
case 'c':
|
||||
trackObject = 0;
|
||||
histimg = Scalar::all(0);
|
||||
break;
|
||||
case 'h':
|
||||
showHist = !showHist;
|
||||
if( !showHist )
|
||||
destroyWindow( "Histogram" );
|
||||
else
|
||||
namedWindow( "Histogram", 1 );
|
||||
break;
|
||||
case 'p':
|
||||
paused = !paused;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* cloning_demo.cpp
|
||||
*
|
||||
* Author:
|
||||
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
|
||||
*
|
||||
* This tutorial demonstrates how to use OpenCV seamless cloning
|
||||
* module without GUI.
|
||||
*
|
||||
* 1- Normal Cloning
|
||||
* 2- Mixed Cloning
|
||||
* 3- Monochrome Transfer
|
||||
* 4- Color Change
|
||||
* 5- Illumination change
|
||||
* 6- Texture Flattening
|
||||
|
||||
* The program takes as input a source and a destination image (for 1-3 methods)
|
||||
* and outputs the cloned image.
|
||||
*
|
||||
* Download test images from opencv_extra repository.
|
||||
*/
|
||||
|
||||
#include "opencv2/photo.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main()
|
||||
{
|
||||
cout << endl;
|
||||
cout << "Note: specify OPENCV_SAMPLES_DATA_PATH_HINT=<opencv_extra>/testdata/cv" << endl << endl;
|
||||
cout << "Cloning Module" << endl;
|
||||
cout << "---------------" << endl;
|
||||
cout << "Options: " << endl;
|
||||
cout << endl;
|
||||
cout << "1) Normal Cloning " << endl;
|
||||
cout << "2) Mixed Cloning " << endl;
|
||||
cout << "3) Monochrome Transfer " << endl;
|
||||
cout << "4) Local Color Change " << endl;
|
||||
cout << "5) Local Illumination Change " << endl;
|
||||
cout << "6) Texture Flattening " << endl;
|
||||
cout << endl;
|
||||
cout << "Press number 1-6 to choose from above techniques: ";
|
||||
int num = 1;
|
||||
cin >> num;
|
||||
cout << endl;
|
||||
|
||||
if(num == 1)
|
||||
{
|
||||
string folder = "cloning/Normal_Cloning/";
|
||||
string original_path1 = samples::findFile(folder + "source1.png");
|
||||
string original_path2 = samples::findFile(folder + "destination1.png");
|
||||
string original_path3 = samples::findFile(folder + "mask.png");
|
||||
|
||||
Mat source = imread(original_path1, IMREAD_COLOR);
|
||||
Mat destination = imread(original_path2, IMREAD_COLOR);
|
||||
Mat mask = imread(original_path3, IMREAD_COLOR);
|
||||
|
||||
if(source.empty())
|
||||
{
|
||||
cout << "Could not load source image " << original_path1 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(destination.empty())
|
||||
{
|
||||
cout << "Could not load destination image " << original_path2 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(mask.empty())
|
||||
{
|
||||
cout << "Could not load mask image " << original_path3 << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Mat result;
|
||||
Point p;
|
||||
p.x = 400;
|
||||
p.y = 100;
|
||||
|
||||
seamlessClone(source, destination, mask, p, result, 1);
|
||||
|
||||
imshow("Output",result);
|
||||
imwrite("cloned.png", result);
|
||||
}
|
||||
else if(num == 2)
|
||||
{
|
||||
string folder = "cloning/Mixed_Cloning/";
|
||||
string original_path1 = samples::findFile(folder + "source1.png");
|
||||
string original_path2 = samples::findFile(folder + "destination1.png");
|
||||
string original_path3 = samples::findFile(folder + "mask.png");
|
||||
|
||||
Mat source = imread(original_path1, IMREAD_COLOR);
|
||||
Mat destination = imread(original_path2, IMREAD_COLOR);
|
||||
Mat mask = imread(original_path3, IMREAD_COLOR);
|
||||
|
||||
if(source.empty())
|
||||
{
|
||||
cout << "Could not load source image " << original_path1 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(destination.empty())
|
||||
{
|
||||
cout << "Could not load destination image " << original_path2 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(mask.empty())
|
||||
{
|
||||
cout << "Could not load mask image " << original_path3 << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Mat result;
|
||||
Point p;
|
||||
p.x = destination.size().width/2;
|
||||
p.y = destination.size().height/2;
|
||||
|
||||
seamlessClone(source, destination, mask, p, result, 2);
|
||||
|
||||
imshow("Output",result);
|
||||
imwrite("cloned.png", result);
|
||||
}
|
||||
else if(num == 3)
|
||||
{
|
||||
string folder = "cloning/Monochrome_Transfer/";
|
||||
string original_path1 = samples::findFile(folder + "source1.png");
|
||||
string original_path2 = samples::findFile(folder + "destination1.png");
|
||||
string original_path3 = samples::findFile(folder + "mask.png");
|
||||
|
||||
Mat source = imread(original_path1, IMREAD_COLOR);
|
||||
Mat destination = imread(original_path2, IMREAD_COLOR);
|
||||
Mat mask = imread(original_path3, IMREAD_COLOR);
|
||||
|
||||
if(source.empty())
|
||||
{
|
||||
cout << "Could not load source image " << original_path1 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(destination.empty())
|
||||
{
|
||||
cout << "Could not load destination image " << original_path2 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(mask.empty())
|
||||
{
|
||||
cout << "Could not load mask image " << original_path3 << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Mat result;
|
||||
Point p;
|
||||
p.x = destination.size().width/2;
|
||||
p.y = destination.size().height/2;
|
||||
|
||||
seamlessClone(source, destination, mask, p, result, 3);
|
||||
|
||||
imshow("Output",result);
|
||||
imwrite("cloned.png", result);
|
||||
}
|
||||
else if(num == 4)
|
||||
{
|
||||
string folder = "cloning/color_change/";
|
||||
string original_path1 = samples::findFile(folder + "source1.png");
|
||||
string original_path2 = samples::findFile(folder + "mask.png");
|
||||
|
||||
Mat source = imread(original_path1, IMREAD_COLOR);
|
||||
Mat mask = imread(original_path2, IMREAD_COLOR);
|
||||
|
||||
if(source.empty())
|
||||
{
|
||||
cout << "Could not load source image " << original_path1 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(mask.empty())
|
||||
{
|
||||
cout << "Could not load mask image " << original_path2 << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Mat result;
|
||||
|
||||
colorChange(source, mask, result, 1.5, .5, .5);
|
||||
|
||||
imshow("Output",result);
|
||||
imwrite("cloned.png", result);
|
||||
}
|
||||
else if(num == 5)
|
||||
{
|
||||
string folder = "cloning/Illumination_Change/";
|
||||
string original_path1 = samples::findFile(folder + "source1.png");
|
||||
string original_path2 = samples::findFile(folder + "mask.png");
|
||||
|
||||
Mat source = imread(original_path1, IMREAD_COLOR);
|
||||
Mat mask = imread(original_path2, IMREAD_COLOR);
|
||||
|
||||
if(source.empty())
|
||||
{
|
||||
cout << "Could not load source image " << original_path1 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(mask.empty())
|
||||
{
|
||||
cout << "Could not load mask image " << original_path2 << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Mat result;
|
||||
|
||||
illuminationChange(source, mask, result, 0.2f, 0.4f);
|
||||
|
||||
imshow("Output",result);
|
||||
imwrite("cloned.png", result);
|
||||
}
|
||||
else if(num == 6)
|
||||
{
|
||||
string folder = "cloning/Texture_Flattening/";
|
||||
string original_path1 = samples::findFile(folder + "source1.png");
|
||||
string original_path2 = samples::findFile(folder + "mask.png");
|
||||
|
||||
Mat source = imread(original_path1, IMREAD_COLOR);
|
||||
Mat mask = imread(original_path2, IMREAD_COLOR);
|
||||
|
||||
if(source.empty())
|
||||
{
|
||||
cout << "Could not load source image " << original_path1 << endl;
|
||||
exit(0);
|
||||
}
|
||||
if(mask.empty())
|
||||
{
|
||||
cout << "Could not load mask image " << original_path2 << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Mat result;
|
||||
|
||||
textureFlattening(source, mask, result, 30, 45, 3);
|
||||
|
||||
imshow("Output",result);
|
||||
imwrite("cloned.png", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "Invalid selection: " << num << endl;
|
||||
exit(1);
|
||||
}
|
||||
waitKey(0);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* create_mask.cpp
|
||||
*
|
||||
* Author:
|
||||
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
|
||||
*
|
||||
* This tutorial demonstrates how to make mask image (black and white).
|
||||
* The program takes as input a source image and outputs its corresponding
|
||||
* mask image.
|
||||
*/
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
Mat src, img1, mask, final;
|
||||
|
||||
Point point;
|
||||
vector<Point> pts;
|
||||
int drag = 0;
|
||||
int var = 0;
|
||||
int flag = 0;
|
||||
|
||||
void mouseHandler(int, int, int, int, void*);
|
||||
|
||||
void mouseHandler(int event, int x, int y, int, void*)
|
||||
{
|
||||
|
||||
if (event == EVENT_LBUTTONDOWN && !drag)
|
||||
{
|
||||
if (flag == 0)
|
||||
{
|
||||
if (var == 0)
|
||||
img1 = src.clone();
|
||||
point = Point(x, y);
|
||||
circle(img1, point, 2, Scalar(0, 0, 255), -1, 8, 0);
|
||||
pts.push_back(point);
|
||||
var++;
|
||||
drag = 1;
|
||||
|
||||
if (var > 1)
|
||||
line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0);
|
||||
|
||||
imshow("Source", img1);
|
||||
}
|
||||
}
|
||||
|
||||
if (event == EVENT_LBUTTONUP && drag)
|
||||
{
|
||||
imshow("Source", img1);
|
||||
drag = 0;
|
||||
}
|
||||
|
||||
if (event == EVENT_RBUTTONDOWN)
|
||||
{
|
||||
flag = 1;
|
||||
img1 = src.clone();
|
||||
|
||||
if (var != 0)
|
||||
{
|
||||
polylines( img1, pts, 1, Scalar(0,0,0), 2, 8, 0);
|
||||
}
|
||||
|
||||
imshow("Source", img1);
|
||||
}
|
||||
|
||||
if (event == EVENT_RBUTTONUP)
|
||||
{
|
||||
flag = var;
|
||||
final = Mat::zeros(src.size(), CV_8UC3);
|
||||
mask = Mat::zeros(src.size(), CV_8UC1);
|
||||
|
||||
fillPoly(mask, pts, Scalar(255, 255, 255), 8, 0);
|
||||
bitwise_and(src, src, final, mask);
|
||||
imshow("Mask", mask);
|
||||
imshow("Result", final);
|
||||
imshow("Source", img1);
|
||||
}
|
||||
|
||||
if (event == EVENT_MBUTTONDOWN)
|
||||
{
|
||||
pts.clear();
|
||||
var = 0;
|
||||
drag = 0;
|
||||
flag = 0;
|
||||
imshow("Source", src);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CommandLineParser parser(argc, argv, "{@input | lena.jpg | input image}");
|
||||
parser.about("This program demonstrates using mouse events\n");
|
||||
parser.printMessage();
|
||||
cout << "\n\tleft mouse button - set a point to create mask shape\n"
|
||||
"\tright mouse button - create mask from points\n"
|
||||
"\tmiddle mouse button - reset\n";
|
||||
String input_image = parser.get<String>("@input");
|
||||
|
||||
src = imread(samples::findFile(input_image));
|
||||
|
||||
if (src.empty())
|
||||
{
|
||||
printf("Error opening image: %s\n", input_image.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
namedWindow("Source", WINDOW_AUTOSIZE);
|
||||
setMouseCallback("Source", mouseHandler, NULL);
|
||||
imshow("Source", src);
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/features2d.hpp>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
cout << "\n This program demonstrates how to use BLOB to detect and filter region \n"
|
||||
<< "Usage: \n"
|
||||
<< argv[0]
|
||||
<< " <image1(detect_blob.png as default)>\n"
|
||||
<< "Press a key when image window is active to change descriptor";
|
||||
}
|
||||
|
||||
|
||||
static String Legende(SimpleBlobDetector::Params &pAct)
|
||||
{
|
||||
String s = "";
|
||||
if (pAct.filterByArea)
|
||||
{
|
||||
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minArea).str();
|
||||
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxArea).str();
|
||||
s = " Area range [" + inf + " to " + sup + "]";
|
||||
}
|
||||
if (pAct.filterByCircularity)
|
||||
{
|
||||
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minCircularity).str();
|
||||
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxCircularity).str();
|
||||
if (s.length() == 0)
|
||||
s = " Circularity range [" + inf + " to " + sup + "]";
|
||||
else
|
||||
s += " AND Circularity range [" + inf + " to " + sup + "]";
|
||||
}
|
||||
if (pAct.filterByColor)
|
||||
{
|
||||
String inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.blobColor).str();
|
||||
if (s.length() == 0)
|
||||
s = " Blob color " + inf;
|
||||
else
|
||||
s += " AND Blob color " + inf;
|
||||
}
|
||||
if (pAct.filterByConvexity)
|
||||
{
|
||||
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minConvexity).str();
|
||||
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxConvexity).str();
|
||||
if (s.length() == 0)
|
||||
s = " Convexity range[" + inf + " to " + sup + "]";
|
||||
else
|
||||
s += " AND Convexity range[" + inf + " to " + sup + "]";
|
||||
}
|
||||
if (pAct.filterByInertia)
|
||||
{
|
||||
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minInertiaRatio).str();
|
||||
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxInertiaRatio).str();
|
||||
if (s.length() == 0)
|
||||
s = " Inertia ratio range [" + inf + " to " + sup + "]";
|
||||
else
|
||||
s += " AND Inertia ratio range [" + inf + " to " + sup + "]";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
String fileName;
|
||||
cv::CommandLineParser parser(argc, argv, "{@input |detect_blob.png| }{h help | | }");
|
||||
if (parser.has("h"))
|
||||
{
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
fileName = parser.get<string>("@input");
|
||||
Mat img = imread(samples::findFile(fileName), IMREAD_COLOR);
|
||||
if (img.empty())
|
||||
{
|
||||
cout << "Image " << fileName << " is empty or cannot be found\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
SimpleBlobDetector::Params pDefaultBLOB;
|
||||
// This is default parameters for SimpleBlobDetector
|
||||
pDefaultBLOB.thresholdStep = 10;
|
||||
pDefaultBLOB.minThreshold = 10;
|
||||
pDefaultBLOB.maxThreshold = 220;
|
||||
pDefaultBLOB.minRepeatability = 2;
|
||||
pDefaultBLOB.minDistBetweenBlobs = 10;
|
||||
pDefaultBLOB.filterByColor = false;
|
||||
pDefaultBLOB.blobColor = 0;
|
||||
pDefaultBLOB.filterByArea = false;
|
||||
pDefaultBLOB.minArea = 25;
|
||||
pDefaultBLOB.maxArea = 5000;
|
||||
pDefaultBLOB.filterByCircularity = false;
|
||||
pDefaultBLOB.minCircularity = 0.9f;
|
||||
pDefaultBLOB.maxCircularity = (float)1e37;
|
||||
pDefaultBLOB.filterByInertia = false;
|
||||
pDefaultBLOB.minInertiaRatio = 0.1f;
|
||||
pDefaultBLOB.maxInertiaRatio = (float)1e37;
|
||||
pDefaultBLOB.filterByConvexity = false;
|
||||
pDefaultBLOB.minConvexity = 0.95f;
|
||||
pDefaultBLOB.maxConvexity = (float)1e37;
|
||||
// Descriptor array for BLOB
|
||||
vector<String> typeDesc;
|
||||
// Param array for BLOB
|
||||
vector<SimpleBlobDetector::Params> pBLOB;
|
||||
vector<SimpleBlobDetector::Params>::iterator itBLOB;
|
||||
// Color palette
|
||||
vector< Vec3b > palette;
|
||||
for (int i = 0; i<65536; i++)
|
||||
{
|
||||
uchar c1 = (uchar)rand();
|
||||
uchar c2 = (uchar)rand();
|
||||
uchar c3 = (uchar)rand();
|
||||
palette.push_back(Vec3b(c1, c2, c3));
|
||||
}
|
||||
help(argv);
|
||||
|
||||
|
||||
// These descriptors are going to be detecting and computing BLOBS with 6 different params
|
||||
// Param for first BLOB detector we want all
|
||||
typeDesc.push_back("BLOB"); // see http://docs.opencv.org/5.x/d0/d7a/classcv_1_1SimpleBlobDetector.html
|
||||
pBLOB.push_back(pDefaultBLOB);
|
||||
pBLOB.back().filterByArea = true;
|
||||
pBLOB.back().minArea = 1;
|
||||
pBLOB.back().maxArea = float(img.rows*img.cols);
|
||||
// Param for second BLOB detector we want area between 500 and 2900 pixels
|
||||
typeDesc.push_back("BLOB");
|
||||
pBLOB.push_back(pDefaultBLOB);
|
||||
pBLOB.back().filterByArea = true;
|
||||
pBLOB.back().minArea = 500;
|
||||
pBLOB.back().maxArea = 2900;
|
||||
// Param for third BLOB detector we want only circular object
|
||||
typeDesc.push_back("BLOB");
|
||||
pBLOB.push_back(pDefaultBLOB);
|
||||
pBLOB.back().filterByCircularity = true;
|
||||
// Param for Fourth BLOB detector we want ratio inertia
|
||||
typeDesc.push_back("BLOB");
|
||||
pBLOB.push_back(pDefaultBLOB);
|
||||
pBLOB.back().filterByInertia = true;
|
||||
pBLOB.back().minInertiaRatio = 0;
|
||||
pBLOB.back().maxInertiaRatio = (float)0.2;
|
||||
// Param for fifth BLOB detector we want ratio inertia
|
||||
typeDesc.push_back("BLOB");
|
||||
pBLOB.push_back(pDefaultBLOB);
|
||||
pBLOB.back().filterByConvexity = true;
|
||||
pBLOB.back().minConvexity = 0.;
|
||||
pBLOB.back().maxConvexity = (float)0.9;
|
||||
// Param for six BLOB detector we want blob with gravity center color equal to 0
|
||||
typeDesc.push_back("BLOB");
|
||||
pBLOB.push_back(pDefaultBLOB);
|
||||
pBLOB.back().filterByColor = true;
|
||||
pBLOB.back().blobColor = 0;
|
||||
|
||||
itBLOB = pBLOB.begin();
|
||||
vector<double> desMethCmp;
|
||||
Ptr<Feature2D> b;
|
||||
String label;
|
||||
// Descriptor loop
|
||||
vector<String>::iterator itDesc;
|
||||
for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
|
||||
{
|
||||
vector<KeyPoint> keyImg1;
|
||||
if (*itDesc == "BLOB")
|
||||
{
|
||||
b = SimpleBlobDetector::create(*itBLOB);
|
||||
label = Legende(*itBLOB);
|
||||
++itBLOB;
|
||||
}
|
||||
try
|
||||
{
|
||||
// We can detect keypoint with detect method
|
||||
vector<KeyPoint> keyImg;
|
||||
vector<Rect> zone;
|
||||
vector<vector <Point> > region;
|
||||
Mat desc, result(img.rows, img.cols, CV_8UC3);
|
||||
if (b.dynamicCast<SimpleBlobDetector>().get())
|
||||
{
|
||||
Ptr<SimpleBlobDetector> sbd = b.dynamicCast<SimpleBlobDetector>();
|
||||
sbd->detect(img, keyImg, Mat());
|
||||
drawKeypoints(img, keyImg, result);
|
||||
int i = 0;
|
||||
for (vector<KeyPoint>::iterator k = keyImg.begin(); k != keyImg.end(); ++k, ++i)
|
||||
circle(result, k->pt, (int)k->size, palette[i % 65536]);
|
||||
}
|
||||
namedWindow(*itDesc + label, WINDOW_AUTOSIZE);
|
||||
imshow(*itDesc + label, result);
|
||||
imshow("Original", img);
|
||||
waitKey();
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
cout << "Feature : " << *itDesc << "\n";
|
||||
cout << e.msg << endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
static void convolveDFT(InputArray A, InputArray B, OutputArray C) {
|
||||
// Calculate the size of the output array
|
||||
int outputRows = A.rows() + B.rows() - 1;
|
||||
int outputCols = A.cols() + B.cols() - 1;
|
||||
|
||||
// Reallocate the output array if needed
|
||||
C.create(outputRows, outputCols, A.type());
|
||||
|
||||
Size dftSize;
|
||||
// Calculate the size of DFT transform
|
||||
dftSize.width = getOptimalDFTSize(A.cols() + B.cols() - 1);
|
||||
dftSize.height = getOptimalDFTSize(A.rows() + B.rows() - 1);
|
||||
|
||||
// Allocate temporary buffers and initialize them with 0's
|
||||
Mat tempA(dftSize, A.type(), Scalar::all(0));
|
||||
Mat tempB(dftSize, B.type(), Scalar::all(0));
|
||||
|
||||
// Copy A and B to the top-left corners of tempA and tempB, respectively
|
||||
Mat roiA(tempA, Rect(0, 0, A.cols(), A.rows()));
|
||||
A.copyTo(roiA);
|
||||
Mat roiB(tempB, Rect(0, 0, B.cols(), B.rows()));
|
||||
B.copyTo(roiB);
|
||||
|
||||
// Now transform the padded A & B in-place;
|
||||
// use "nonzeroRows" hint for faster processing
|
||||
dft(tempA, tempA, 0, A.rows());
|
||||
dft(tempB, tempB, 0, B.rows());
|
||||
|
||||
// Multiply the spectrums;
|
||||
// the function handles packed spectrum representations well
|
||||
mulSpectrums(tempA, tempB, tempA, 0);
|
||||
|
||||
// Transform the product back from the frequency domain.
|
||||
// Even though all the result rows will be non-zero,
|
||||
// you need only the first C.rows of them, and thus you
|
||||
// pass nonzeroRows == C.rows
|
||||
dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows());
|
||||
|
||||
// Now copy the result back to C.
|
||||
tempA(Rect(0, 0, C.cols(), C.rows())).copyTo(C);
|
||||
|
||||
// All the temporary buffers will be deallocated automatically
|
||||
}
|
||||
static void help(const char ** argv)
|
||||
{
|
||||
printf("\nThis program demonstrates the use of convolution using discrete Fourier transform (DFT)\n"
|
||||
"An image is convolved with kernel filter using DFT.\n"
|
||||
"Usage:\n %s [input -- default lena.jpg]\n", argv[0]);
|
||||
}
|
||||
|
||||
const char* keys =
|
||||
{
|
||||
"{help h||}{@input|lena.jpg|input image file}"
|
||||
};
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
// Load the image in grayscale
|
||||
help(argv);
|
||||
CommandLineParser parser(argc, argv, keys);
|
||||
if (parser.has("help"))
|
||||
{
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
string filename = parser.get<string>(0);
|
||||
Mat img = imread(samples::findFile(filename), IMREAD_GRAYSCALE);
|
||||
|
||||
// Check if the image is loaded successfully
|
||||
if (img.empty()) {
|
||||
std::cerr << "Error: Image not loaded!" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert the image to CV_32F
|
||||
Mat img_32f;
|
||||
img.convertTo(img_32f, CV_32F);
|
||||
|
||||
float kernelData[9] = { 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9 }; // example of blur filter, can be changed to other filter as well.
|
||||
Mat kernel(3, 3, CV_32F, kernelData);
|
||||
|
||||
// Perform convolution of the image with the sharpening kernel
|
||||
Mat result;
|
||||
convolveDFT(img_32f, kernel, result);
|
||||
|
||||
// Normalize the result for better visualization
|
||||
normalize(result, result, 0, 255, NORM_MINMAX);
|
||||
|
||||
// Convert result back to 8-bit for display
|
||||
Mat result_8u;
|
||||
result.convertTo(result_8u, CV_8U);
|
||||
|
||||
// Display the images
|
||||
imshow("Original Image", img);
|
||||
imshow("Output Image", result_8u);
|
||||
|
||||
waitKey(0); // Wait for a key press to close the windows
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/video.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CommandLineParser parser(argc, argv, "{ @video | vtest.avi | use video as input }");
|
||||
string filename = samples::findFileOrKeep(parser.get<string>("@video"));
|
||||
|
||||
VideoCapture cap;
|
||||
cap.open(filename);
|
||||
|
||||
if(!cap.isOpened())
|
||||
{
|
||||
printf("ERROR: Cannot open file %s\n", filename.c_str());
|
||||
parser.printMessage();
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat prevgray, gray, rgb, frame;
|
||||
Mat flow, flow_uv[2];
|
||||
Mat mag, ang;
|
||||
Mat hsv_split[3], hsv;
|
||||
char ret;
|
||||
|
||||
Ptr<DenseOpticalFlow> algorithm = DISOpticalFlow::create(DISOpticalFlow::PRESET_MEDIUM);
|
||||
|
||||
while(true)
|
||||
{
|
||||
cap >> frame;
|
||||
if (frame.empty())
|
||||
break;
|
||||
|
||||
cvtColor(frame, gray, COLOR_BGR2GRAY);
|
||||
|
||||
if (!prevgray.empty())
|
||||
{
|
||||
algorithm->calc(prevgray, gray, flow);
|
||||
split(flow, flow_uv);
|
||||
multiply(flow_uv[1], -1, flow_uv[1]);
|
||||
cartToPolar(flow_uv[0], flow_uv[1], mag, ang, true);
|
||||
normalize(mag, mag, 0, 1, NORM_MINMAX);
|
||||
hsv_split[0] = ang;
|
||||
hsv_split[1] = mag;
|
||||
hsv_split[2] = Mat::ones(ang.size(), ang.type());
|
||||
merge(hsv_split, 3, hsv);
|
||||
cvtColor(hsv, rgb, COLOR_HSV2BGR);
|
||||
imshow("flow", rgb);
|
||||
imshow("orig", frame);
|
||||
}
|
||||
|
||||
if ((ret = (char)waitKey(20)) > 0)
|
||||
break;
|
||||
std::swap(prevgray, gray);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int maskSize0 = DIST_MASK_5;
|
||||
int voronoiType = -1;
|
||||
int edgeThresh = 100;
|
||||
int distType0 = DIST_L1;
|
||||
|
||||
// The output and temporary images
|
||||
Mat gray;
|
||||
|
||||
// threshold trackbar callback
|
||||
static 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 = voronoiType >= 0 ? DIST_MASK_5 : maskSize0;
|
||||
int distType = voronoiType >= 0 ? DIST_L2 : distType0;
|
||||
|
||||
Mat edge = gray >= edgeThresh, dist, labels, dist8u;
|
||||
|
||||
if( voronoiType < 0 )
|
||||
distanceTransform( edge, dist, distType, maskSize );
|
||||
else
|
||||
distanceTransform( edge, dist, labels, distType, maskSize, voronoiType );
|
||||
|
||||
if( voronoiType < 0 )
|
||||
{
|
||||
// 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;
|
||||
float scale = 1.f/(1 + dd[j]*dd[j]*0.0004f);
|
||||
int b = cvRound(colors[idx][0]*scale);
|
||||
int g = cvRound(colors[idx][1]*scale);
|
||||
int r = cvRound(colors[idx][2]*scale);
|
||||
d[j*3] = (uchar)b;
|
||||
d[j*3+1] = (uchar)g;
|
||||
d[j*3+2] = (uchar)r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
imshow("Distance Map", dist8u );
|
||||
}
|
||||
|
||||
static void help(const char** argv)
|
||||
{
|
||||
printf("\nProgram to demonstrate the use of the distance transform function between edge images.\n"
|
||||
"Usage:\n"
|
||||
"%s [image_name -- default image is stuff.jpg]\n"
|
||||
"\nHot 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 to Voronoi diagram mode\n"
|
||||
"\tp - switch to pixel-based Voronoi diagram mode\n"
|
||||
"\tSPACE - loop through all the modes\n\n", argv[0]);
|
||||
}
|
||||
|
||||
const char* keys =
|
||||
{
|
||||
"{help h||}{@image |stuff.jpg|input image file}"
|
||||
};
|
||||
|
||||
int main( int argc, const char** argv )
|
||||
{
|
||||
CommandLineParser parser(argc, argv, keys);
|
||||
help(argv);
|
||||
if (parser.has("help"))
|
||||
return 0;
|
||||
string filename = parser.get<string>(0);
|
||||
gray = imread(samples::findFile(filename), 0);
|
||||
if(gray.empty())
|
||||
{
|
||||
printf("Cannot read image file: %s\n", filename.c_str());
|
||||
help(argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
namedWindow("Distance Map", 1);
|
||||
createTrackbar("Brightness Threshold", "Distance Map", &edgeThresh, 255, onTrackbar, 0);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Call to update the view
|
||||
onTrackbar(0, 0);
|
||||
|
||||
char c = (char)waitKey(0);
|
||||
|
||||
if( c == 27 )
|
||||
break;
|
||||
|
||||
if( c == 'c' || c == 'C' || c == '1' || c == '2' ||
|
||||
c == '3' || c == '5' || c == '0' )
|
||||
voronoiType = -1;
|
||||
|
||||
if( c == 'c' || c == 'C' )
|
||||
distType0 = DIST_C;
|
||||
else if( c == '1' )
|
||||
distType0 = DIST_L1;
|
||||
else if( c == '2' )
|
||||
distType0 = DIST_L2;
|
||||
else if( c == '3' )
|
||||
maskSize0 = DIST_MASK_3;
|
||||
else if( c == '5' )
|
||||
maskSize0 = DIST_MASK_5;
|
||||
else if( c == '0' )
|
||||
maskSize0 = DIST_MASK_PRECISE;
|
||||
else if( c == 'v' )
|
||||
voronoiType = 0;
|
||||
else if( c == 'p' )
|
||||
voronoiType = 1;
|
||||
else if( c == ' ' )
|
||||
{
|
||||
if( voronoiType == 0 )
|
||||
voronoiType = 1;
|
||||
else if( voronoiType == 1 )
|
||||
{
|
||||
voronoiType = -1;
|
||||
maskSize0 = DIST_MASK_3;
|
||||
distType0 = DIST_C;
|
||||
}
|
||||
else if( distType0 == DIST_C )
|
||||
distType0 = DIST_L1;
|
||||
else if( distType0 == DIST_L1 )
|
||||
distType0 = DIST_L2;
|
||||
else if( maskSize0 == DIST_MASK_3 )
|
||||
maskSize0 = DIST_MASK_5;
|
||||
else if( maskSize0 == DIST_MASK_5 )
|
||||
maskSize0 = DIST_MASK_PRECISE;
|
||||
else if( maskSize0 == DIST_MASK_PRECISE )
|
||||
voronoiType = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html
|
||||
|
||||
#include "opencv2/3d.hpp"
|
||||
#include "opencv2/features2d.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
int main(int args, char** argv) {
|
||||
std::string img_name1, img_name2;
|
||||
if (args < 3) {
|
||||
CV_Error(Error::StsBadArg,
|
||||
"Path to two images \nFor example: "
|
||||
"./epipolar_lines img1.jpg img2.jpg");
|
||||
} else {
|
||||
img_name1 = argv[1];
|
||||
img_name2 = argv[2];
|
||||
}
|
||||
|
||||
Mat image1 = imread(img_name1);
|
||||
Mat image2 = imread(img_name2);
|
||||
Mat descriptors1, descriptors2;
|
||||
std::vector<KeyPoint> keypoints1, keypoints2;
|
||||
|
||||
Ptr<SIFT> detector = SIFT::create();
|
||||
detector->detect(image1, keypoints1);
|
||||
detector->detect(image2, keypoints2);
|
||||
detector->compute(image1, keypoints1, descriptors1);
|
||||
detector->compute(image2, keypoints2, descriptors2);
|
||||
|
||||
FlannBasedMatcher matcher(makePtr<flann::KDTreeIndexParams>(5), makePtr<flann::SearchParams>(32));
|
||||
|
||||
// get k=2 best match that we can apply ratio test explained by D.Lowe
|
||||
std::vector<std::vector<DMatch>> matches_vector;
|
||||
matcher.knnMatch(descriptors1, descriptors2, matches_vector, 2);
|
||||
|
||||
std::vector<Point2d> pts1, pts2;
|
||||
pts1.reserve(matches_vector.size()); pts2.reserve(matches_vector.size());
|
||||
for (const auto &m : matches_vector) {
|
||||
// compare best and second match using Lowe ratio test
|
||||
if (m[0].distance / m[1].distance < 0.75) {
|
||||
pts1.emplace_back(keypoints1[m[0].queryIdx].pt);
|
||||
pts2.emplace_back(keypoints2[m[0].trainIdx].pt);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Number of points " << pts1.size() << '\n';
|
||||
|
||||
Mat inliers;
|
||||
const auto begin_time = std::chrono::steady_clock::now();
|
||||
const Mat F = findFundamentalMat(pts1, pts2, RANSAC, 1., 0.99, 2000, inliers);
|
||||
std::cout << "RANSAC fundamental matrix time " << static_cast<int>(std::chrono::duration_cast<std::chrono::microseconds>
|
||||
(std::chrono::steady_clock::now() - begin_time).count()) << "\n";
|
||||
|
||||
Mat points1 = Mat((int)pts1.size(), 2, CV_64F, pts1.data());
|
||||
Mat points2 = Mat((int)pts2.size(), 2, CV_64F, pts2.data());
|
||||
vconcat(points1.t(), Mat::ones(1, points1.rows, points1.type()), points1);
|
||||
vconcat(points2.t(), Mat::ones(1, points2.rows, points2.type()), points2);
|
||||
|
||||
RNG rng;
|
||||
const int circle_sz = 3, line_sz = 1, max_lines = 300;
|
||||
std::vector<int> pts_shuffle (points1.cols);
|
||||
for (int i = 0; i < points1.cols; i++)
|
||||
pts_shuffle[i] = i;
|
||||
randShuffle(pts_shuffle);
|
||||
int plot_lines = 0, num_inliers = 0;
|
||||
double mean_err = 0;
|
||||
for (int pt : pts_shuffle) {
|
||||
if (inliers.at<uchar>(pt)) {
|
||||
const Scalar col (rng.uniform(0,256), rng.uniform(0,256), rng.uniform(0,256));
|
||||
const Mat l2 = F * points1.col(pt);
|
||||
const Mat l1 = F.t() * points2.col(pt);
|
||||
double a1 = l1.at<double>(0), b1 = l1.at<double>(1), c1 = l1.at<double>(2);
|
||||
double a2 = l2.at<double>(0), b2 = l2.at<double>(1), c2 = l2.at<double>(2);
|
||||
const double mag1 = sqrt(a1*a1 + b1*b1), mag2 = (a2*a2 + b2*b2);
|
||||
a1 /= mag1; b1 /= mag1; c1 /= mag1; a2 /= mag2; b2 /= mag2; c2 /= mag2;
|
||||
if (plot_lines++ < max_lines) {
|
||||
line(image1, Point2d(0, -c1/b1),
|
||||
Point2d((double)image1.cols, -(a1*image1.cols+c1)/b1), col, line_sz);
|
||||
line(image2, Point2d(0, -c2/b2),
|
||||
Point2d((double)image2.cols, -(a2*image2.cols+c2)/b2), col, line_sz);
|
||||
}
|
||||
circle (image1, pts1[pt], circle_sz, col, -1);
|
||||
circle (image2, pts2[pt], circle_sz, col, -1);
|
||||
mean_err += (fabs(points1.col(pt).dot(l2)) / mag2 + fabs(points2.col(pt).dot(l1) / mag1)) / 2;
|
||||
num_inliers++;
|
||||
}
|
||||
}
|
||||
std::cout << "Mean distance from tentative inliers to epipolar lines " << mean_err/num_inliers
|
||||
<< " number of inliers " << num_inliers << "\n";
|
||||
// concatenate two images
|
||||
hconcat(image1, image2, image1);
|
||||
const int new_img_size = 1200 * 800; // for example
|
||||
// resize with the same aspect ratio
|
||||
resize(image1, image1, Size((int) sqrt ((double) image1.cols * new_img_size / image1.rows),
|
||||
(int)sqrt ((double) image1.rows * new_img_size / image1.cols)));
|
||||
|
||||
imshow("epipolar lines, image 1, 2", image1);
|
||||
imwrite("epipolar_lines.png", image1);
|
||||
waitKey(0);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
enum MyShape{MyCIRCLE=0,MyRECTANGLE,MyELLIPSE};
|
||||
|
||||
struct ParamColorMap {
|
||||
int iColormap;
|
||||
Mat img;
|
||||
};
|
||||
|
||||
String winName="False color";
|
||||
static const String ColorMaps[] = { "Autumn", "Bone", "Jet", "Winter", "Rainbow", "Ocean", "Summer", "Spring",
|
||||
"Cool", "HSV", "Pink", "Hot", "Parula", "Magma", "Inferno", "Plasma", "Viridis",
|
||||
"Cividis", "Twilight", "Twilight Shifted", "Turbo", "Deep Green", "User defined (random)" };
|
||||
|
||||
static void TrackColorMap(int x, void *r)
|
||||
{
|
||||
ParamColorMap *p = (ParamColorMap*)r;
|
||||
Mat dst;
|
||||
p->iColormap= x;
|
||||
if (x == COLORMAP_DEEPGREEN + 1)
|
||||
{
|
||||
Mat lutRND(256, 1, CV_8UC3);
|
||||
randu(lutRND, Scalar(0, 0, 0), Scalar(255, 255, 255));
|
||||
applyColorMap(p->img, dst, lutRND);
|
||||
}
|
||||
else
|
||||
applyColorMap(p->img,dst,p->iColormap);
|
||||
|
||||
putText(dst, "Colormap : "+ColorMaps[p->iColormap], Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(255, 255, 255),2);
|
||||
imshow(winName, dst);
|
||||
}
|
||||
|
||||
|
||||
static Mat DrawMyImage(int thickness,int nbShape)
|
||||
{
|
||||
Mat img=Mat::zeros(500,256*thickness+100,CV_8UC1);
|
||||
int offsetx = 50, offsety = 25;
|
||||
int lineLength = 50;
|
||||
|
||||
for (int i=0;i<256;i++)
|
||||
line(img,Point(thickness*i+ offsetx, offsety),Point(thickness*i+ offsetx, offsety+ lineLength),Scalar(i), thickness);
|
||||
RNG r;
|
||||
Point center;
|
||||
int radius;
|
||||
int width,height;
|
||||
int angle;
|
||||
Rect rc;
|
||||
|
||||
for (int i=1;i<=nbShape;i++)
|
||||
{
|
||||
int typeShape = r.uniform(MyCIRCLE, MyELLIPSE+1);
|
||||
switch (typeShape) {
|
||||
case MyCIRCLE:
|
||||
center = Point(r.uniform(offsetx,img.cols- offsetx), r.uniform(offsety + lineLength, img.rows - offsety));
|
||||
radius = r.uniform(1, min(offsetx, offsety));
|
||||
circle(img,center,radius,Scalar(i),-1);
|
||||
break;
|
||||
case MyRECTANGLE:
|
||||
center = Point(r.uniform(offsetx, img.cols - offsetx), r.uniform(offsety + lineLength, img.rows - offsety));
|
||||
width = r.uniform(1, min(offsetx, offsety));
|
||||
height = r.uniform(1, min(offsetx, offsety));
|
||||
rc = Rect(center-Point(width ,height )/2, center + Point(width , height )/2);
|
||||
rectangle(img,rc, Scalar(i), -1);
|
||||
break;
|
||||
case MyELLIPSE:
|
||||
center = Point(r.uniform(offsetx, img.cols - offsetx), r.uniform(offsety + lineLength, img.rows - offsety));
|
||||
width = r.uniform(1, min(offsetx, offsety));
|
||||
height = r.uniform(1, min(offsetx, offsety));
|
||||
angle = r.uniform(0, 180);
|
||||
ellipse(img, center,Size(width/2,height/2),angle,0,360, Scalar(i), -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
cout << "This program demonstrates the use of applyColorMap function.\n\n";
|
||||
|
||||
ParamColorMap p;
|
||||
Mat img;
|
||||
|
||||
if (argc > 1)
|
||||
img = imread(samples::findFile(argv[1]), IMREAD_GRAYSCALE);
|
||||
else
|
||||
img = DrawMyImage(2,256);
|
||||
|
||||
p.img=img;
|
||||
p.iColormap=0;
|
||||
|
||||
imshow("Gray image",img);
|
||||
namedWindow(winName);
|
||||
createTrackbar("colormap", winName, NULL, COLORMAP_DEEPGREEN + 1, TrackColorMap, (void*)&p);
|
||||
setTrackbarMin("colormap", winName, COLORMAP_AUTUMN);
|
||||
setTrackbarMax("colormap", winName, COLORMAP_DEEPGREEN + 1);
|
||||
setTrackbarPos("colormap", winName, COLORMAP_AUTUMN);
|
||||
|
||||
TrackColorMap(0, (void*)&p);
|
||||
|
||||
cout << "Press a key to exit" << endl;
|
||||
waitKey(0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Author: Steve Nicholson
|
||||
*
|
||||
* A program that illustrates intersectConvexConvex in various scenarios
|
||||
*/
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
// Create a vector of points describing a rectangle with the given corners
|
||||
static vector<Point> makeRectangle(Point topLeft, Point bottomRight)
|
||||
{
|
||||
vector<Point> rectangle;
|
||||
rectangle.push_back(topLeft);
|
||||
rectangle.push_back(Point(bottomRight.x, topLeft.y));
|
||||
rectangle.push_back(bottomRight);
|
||||
rectangle.push_back(Point(topLeft.x, bottomRight.y));
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
static vector<Point> makeTriangle(Point point1, Point point2, Point point3)
|
||||
{
|
||||
vector<Point> triangle;
|
||||
triangle.push_back(point1);
|
||||
triangle.push_back(point2);
|
||||
triangle.push_back(point3);
|
||||
return triangle;
|
||||
}
|
||||
|
||||
// Run intersectConvexConvex on two polygons then draw the polygons and their intersection (if there is one)
|
||||
// Return the area of the intersection
|
||||
static float drawIntersection(Mat &image, vector<Point> polygon1, vector<Point> polygon2, bool handleNested = true)
|
||||
{
|
||||
vector<Point> intersectionPolygon;
|
||||
|
||||
vector<vector<Point> > polygons;
|
||||
polygons.push_back(polygon1);
|
||||
polygons.push_back(polygon2);
|
||||
|
||||
float intersectArea = intersectConvexConvex(polygon1, polygon2, intersectionPolygon, handleNested);
|
||||
|
||||
if (intersectArea > 0)
|
||||
{
|
||||
Scalar fillColor(200, 200, 200);
|
||||
// If the input is invalid, draw the intersection in red
|
||||
if (!isContourConvex(polygon1) || !isContourConvex(polygon2))
|
||||
{
|
||||
fillColor = Scalar(0, 0, 255);
|
||||
}
|
||||
fillPoly(image, intersectionPolygon, fillColor);
|
||||
}
|
||||
polylines(image, polygons, true, Scalar(0, 0, 0));
|
||||
|
||||
return intersectArea;
|
||||
}
|
||||
|
||||
static void drawDescription(Mat &image, int intersectionArea, string description, Point origin)
|
||||
{
|
||||
const size_t bufSize=1024;
|
||||
char caption[bufSize];
|
||||
snprintf(caption, bufSize, "Intersection area: %d%s", intersectionArea, description.c_str());
|
||||
putText(image, caption, origin, FONT_HERSHEY_SIMPLEX, 0.6, Scalar(0, 0, 0));
|
||||
}
|
||||
|
||||
static void intersectConvexExample()
|
||||
{
|
||||
Mat image(610, 550, CV_8UC3, Scalar(255, 255, 255));
|
||||
float intersectionArea;
|
||||
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 10), Point(50, 50)),
|
||||
makeRectangle(Point(20, 20), Point(60, 60)));
|
||||
|
||||
drawDescription(image, (int)intersectionArea, "", Point(70, 40));
|
||||
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 70), Point(35, 95)),
|
||||
makeRectangle(Point(35, 95), Point(60, 120)));
|
||||
|
||||
drawDescription(image, (int)intersectionArea, "", Point(70, 100));
|
||||
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 130), Point(60, 180)),
|
||||
makeRectangle(Point(20, 140), Point(50, 170)),
|
||||
true);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, " (handleNested true)", Point(70, 160));
|
||||
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 190), Point(60, 240)),
|
||||
makeRectangle(Point(20, 200), Point(50, 230)),
|
||||
false);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, " (handleNested false)", Point(70, 220));
|
||||
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 250), Point(60, 300)),
|
||||
makeRectangle(Point(20, 250), Point(50, 290)),
|
||||
true);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, " (handleNested true)", Point(70, 280));
|
||||
|
||||
// These rectangles share an edge so handleNested can be false and an intersection is still found
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 310), Point(60, 360)),
|
||||
makeRectangle(Point(20, 310), Point(50, 350)),
|
||||
false);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, " (handleNested false)", Point(70, 340));
|
||||
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 370), Point(60, 420)),
|
||||
makeRectangle(Point(20, 371), Point(50, 410)),
|
||||
false);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, " (handleNested false)", Point(70, 400));
|
||||
|
||||
// A vertex of the triangle lies on an edge of the rectangle so handleNested can be false and an intersection is still found
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 430), Point(60, 480)),
|
||||
makeTriangle(Point(35, 430), Point(20, 470), Point(50, 470)),
|
||||
false);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, " (handleNested false)", Point(70, 460));
|
||||
|
||||
// Show intersection of overlapping rectangle and triangle
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 490), Point(40, 540)),
|
||||
makeTriangle(Point(25, 500), Point(25, 530), Point(60, 515)),
|
||||
false);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, "", Point(70, 520));
|
||||
|
||||
// This concave polygon is invalid input to intersectConvexConvex so it returns an invalid intersection
|
||||
vector<Point> notConvex;
|
||||
notConvex.push_back(Point(25, 560));
|
||||
notConvex.push_back(Point(25, 590));
|
||||
notConvex.push_back(Point(45, 580));
|
||||
notConvex.push_back(Point(60, 600));
|
||||
notConvex.push_back(Point(60, 550));
|
||||
notConvex.push_back(Point(45, 570));
|
||||
intersectionArea = drawIntersection(image,
|
||||
makeRectangle(Point(10, 550), Point(50, 600)),
|
||||
notConvex,
|
||||
false);
|
||||
|
||||
drawDescription(image, (int)intersectionArea, " (invalid input: not convex)", Point(70, 580));
|
||||
|
||||
imshow("Intersections", image);
|
||||
waitKey(0);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
intersectConvexExample();
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/core/cvdef.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
static inline Point calcPoint(Point2f center, double R, double angle)
|
||||
{
|
||||
return center + Point2f((float)cos(angle), (float)-sin(angle))*(float)R;
|
||||
}
|
||||
|
||||
static void help()
|
||||
{
|
||||
printf( "\nExample of c calls to OpenCV's Kalman filter.\n"
|
||||
" Tracking of rotating point.\n"
|
||||
" Point moves in a circle and is characterized by a 1D state.\n"
|
||||
" state_k+1 = state_k + speed + process_noise N(0, 1e-5)\n"
|
||||
" The speed is constant.\n"
|
||||
" Both state and measurements vectors are 1D (a point angle),\n"
|
||||
" Measurement is the real state + gaussian noise N(0, 1e-1).\n"
|
||||
" The real and the measured points are connected with red line segment,\n"
|
||||
" the real and the estimated points are connected with yellow line segment,\n"
|
||||
" the real and the corrected estimated points are connected with green line segment.\n"
|
||||
" (if Kalman filter works correctly,\n"
|
||||
" the yellow segment should be shorter than the red one and\n"
|
||||
" the green segment should be shorter than the yellow one)."
|
||||
"\n"
|
||||
" Pressing any key (except ESC) will reset the tracking.\n"
|
||||
" Pressing ESC will stop the program.\n"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
help();
|
||||
Mat img(500, 500, CV_8UC3);
|
||||
KalmanFilter KF(2, 1, 0);
|
||||
Mat state(2, 1, CV_32F); /* (phi, delta_phi) */
|
||||
Mat processNoise(2, 1, CV_32F);
|
||||
Mat measurement = Mat::zeros(1, 1, CV_32F);
|
||||
char code = (char)-1;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
img = Scalar::all(0);
|
||||
state.at<float>(0) = 0.0f;
|
||||
state.at<float>(1) = 2.f * (float)CV_PI / 6;
|
||||
KF.transitionMatrix = (Mat_<float>(2, 2) << 1, 1, 0, 1);
|
||||
|
||||
setIdentity(KF.measurementMatrix);
|
||||
setIdentity(KF.processNoiseCov, Scalar::all(1e-5));
|
||||
setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));
|
||||
setIdentity(KF.errorCovPost, Scalar::all(1));
|
||||
|
||||
randn(KF.statePost, Scalar::all(0), Scalar::all(0.1));
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Point2f center(img.cols*0.5f, img.rows*0.5f);
|
||||
float R = img.cols/3.f;
|
||||
double stateAngle = state.at<float>(0);
|
||||
Point statePt = calcPoint(center, R, stateAngle);
|
||||
|
||||
Mat prediction = KF.predict();
|
||||
double predictAngle = prediction.at<float>(0);
|
||||
Point predictPt = calcPoint(center, R, predictAngle);
|
||||
|
||||
// generate measurement
|
||||
randn( measurement, Scalar::all(0), Scalar::all(KF.measurementNoiseCov.at<float>(0)));
|
||||
measurement += KF.measurementMatrix*state;
|
||||
|
||||
double measAngle = measurement.at<float>(0);
|
||||
Point measPt = calcPoint(center, R, measAngle);
|
||||
|
||||
// correct the state estimates based on measurements
|
||||
// updates statePost & errorCovPost
|
||||
KF.correct(measurement);
|
||||
double improvedAngle = KF.statePost.at<float>(0);
|
||||
Point improvedPt = calcPoint(center, R, improvedAngle);
|
||||
|
||||
// plot points
|
||||
img = img * 0.2;
|
||||
drawMarker(img, measPt, Scalar(0, 0, 255), cv::MARKER_SQUARE, 5, 2);
|
||||
drawMarker(img, predictPt, Scalar(0, 255, 255), cv::MARKER_SQUARE, 5, 2);
|
||||
drawMarker(img, improvedPt, Scalar(0, 255, 0), cv::MARKER_SQUARE, 5, 2);
|
||||
drawMarker(img, statePt, Scalar(255, 255, 255), cv::MARKER_STAR, 10, 1);
|
||||
// forecast one step
|
||||
Mat test = Mat(KF.transitionMatrix*KF.statePost);
|
||||
drawMarker(img, calcPoint(center, R, Mat(KF.transitionMatrix*KF.statePost).at<float>(0)),
|
||||
Scalar(255, 255, 0), cv::MARKER_SQUARE, 12, 1);
|
||||
|
||||
line( img, statePt, measPt, Scalar(0,0,255), 1, LINE_AA, 0 );
|
||||
line( img, statePt, predictPt, Scalar(0,255,255), 1, LINE_AA, 0 );
|
||||
line( img, statePt, improvedPt, Scalar(0,255,0), 1, LINE_AA, 0 );
|
||||
|
||||
|
||||
randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));
|
||||
state = KF.transitionMatrix*state + processNoise;
|
||||
|
||||
imshow( "Kalman", img );
|
||||
code = (char)waitKey(1000);
|
||||
|
||||
if( code > 0 )
|
||||
break;
|
||||
}
|
||||
if( code == 27 || code == 'q' || code == 'Q' )
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
// static void help()
|
||||
// {
|
||||
// cout << "\nThis program demonstrates kmeans clustering.\n"
|
||||
// "It generates an image with random points, then assigns a random number of cluster\n"
|
||||
// "centers and uses kmeans to move those cluster centers to their representitive location\n"
|
||||
// "Call\n"
|
||||
// "./kmeans\n" << endl;
|
||||
// }
|
||||
|
||||
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);
|
||||
std::vector<Point2f> centers;
|
||||
|
||||
/* 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, RNG::NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
|
||||
}
|
||||
|
||||
randShuffle(points, 1, &rng);
|
||||
|
||||
double compactness = kmeans(points, clusterCount, labels,
|
||||
TermCriteria( TermCriteria::EPS+TermCriteria::COUNT, 10, 1.0),
|
||||
3, KMEANS_PP_CENTERS, centers);
|
||||
|
||||
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], FILLED, LINE_AA );
|
||||
}
|
||||
for (i = 0; i < (int)centers.size(); ++i)
|
||||
{
|
||||
Point2f c = centers[i];
|
||||
circle( img, c, 40, colorTab[i], 1, LINE_AA );
|
||||
}
|
||||
cout << "Compactness: " << compactness << endl;
|
||||
|
||||
imshow("clusters", img);
|
||||
|
||||
char key = (char)waitKey();
|
||||
if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
cout <<
|
||||
"\nThis program demonstrates Laplace point/edge detection using OpenCV function Laplacian()\n"
|
||||
"It captures from the camera of your choice: 0, 1, ... default 0\n"
|
||||
"Call:\n"
|
||||
<< argv[0] << " -c=<camera #, default 0> -p=<index of the frame to be decoded/captured next>\n" << endl;
|
||||
}
|
||||
|
||||
enum {GAUSSIAN, BLUR, MEDIAN};
|
||||
|
||||
int sigma = 3;
|
||||
int smoothType = GAUSSIAN;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
cv::CommandLineParser parser(argc, argv, "{ c | 0 | }{ p | | }");
|
||||
help(argv);
|
||||
|
||||
VideoCapture cap;
|
||||
string camera = parser.get<string>("c");
|
||||
if (camera.size() == 1 && isdigit(camera[0]))
|
||||
cap.open(parser.get<int>("c"));
|
||||
else
|
||||
cap.open(samples::findFileOrKeep(camera));
|
||||
if (!cap.isOpened())
|
||||
{
|
||||
cerr << "Can't open camera/video stream: " << camera << endl;
|
||||
return 1;
|
||||
}
|
||||
cout << "Video " << parser.get<string>("c") <<
|
||||
": width=" << cap.get(CAP_PROP_FRAME_WIDTH) <<
|
||||
", height=" << cap.get(CAP_PROP_FRAME_HEIGHT) <<
|
||||
", nframes=" << cap.get(CAP_PROP_FRAME_COUNT) << endl;
|
||||
int pos = 0;
|
||||
if (parser.has("p"))
|
||||
{
|
||||
pos = parser.get<int>("p");
|
||||
}
|
||||
if (!parser.check())
|
||||
{
|
||||
parser.printErrors();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pos != 0)
|
||||
{
|
||||
cout << "seeking to frame #" << pos << endl;
|
||||
if (!cap.set(CAP_PROP_POS_FRAMES, pos))
|
||||
{
|
||||
cerr << "ERROR: seekeing is not supported" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
namedWindow("Laplacian", WINDOW_AUTOSIZE);
|
||||
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 == GAUSSIAN)
|
||||
GaussianBlur(frame, smoothed, Size(ksize, ksize), sigma, sigma);
|
||||
else if(smoothType == 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);
|
||||
|
||||
char c = (char)waitKey(30);
|
||||
if( c == ' ' )
|
||||
smoothType = smoothType == GAUSSIAN ? BLUR : smoothType == BLUR ? MEDIAN : GAUSSIAN;
|
||||
if( c == 'q' || c == 'Q' || c == 27 )
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
cv::CommandLineParser parser(argc, argv,
|
||||
"{input i|building.jpg|input image}"
|
||||
"{refine r|false|if true use LSD_REFINE_STD method, if false use LSD_REFINE_NONE method}"
|
||||
"{canny c|false|use Canny edge detector}"
|
||||
"{overlay o|false|show result on input image}"
|
||||
"{help h|false|show help message}");
|
||||
|
||||
if (parser.get<bool>("help"))
|
||||
{
|
||||
parser.printMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
parser.printMessage();
|
||||
|
||||
String filename = samples::findFile(parser.get<String>("input"));
|
||||
bool useRefine = parser.get<bool>("refine");
|
||||
bool useCanny = parser.get<bool>("canny");
|
||||
bool overlay = parser.get<bool>("overlay");
|
||||
|
||||
Mat image = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if( image.empty() )
|
||||
{
|
||||
cout << "Unable to load " << filename;
|
||||
return 1;
|
||||
}
|
||||
|
||||
imshow("Source Image", image);
|
||||
|
||||
if (useCanny)
|
||||
{
|
||||
Canny(image, image, 50, 200, 3); // Apply Canny edge detector
|
||||
}
|
||||
|
||||
// Create and LSD detector with standard or no refinement.
|
||||
Ptr<LineSegmentDetector> ls = useRefine ? createLineSegmentDetector(LSD_REFINE_STD) : createLineSegmentDetector(LSD_REFINE_NONE);
|
||||
|
||||
double start = double(getTickCount());
|
||||
vector<Vec4f> lines_std;
|
||||
|
||||
// Detect the lines
|
||||
ls->detect(image, lines_std);
|
||||
|
||||
double duration_ms = (double(getTickCount()) - start) * 1000 / getTickFrequency();
|
||||
std::cout << "It took " << duration_ms << " ms." << std::endl;
|
||||
|
||||
// Show found lines
|
||||
if (!overlay || useCanny)
|
||||
{
|
||||
image = Scalar(0, 0, 0);
|
||||
}
|
||||
|
||||
ls->drawSegments(image, lines_std);
|
||||
|
||||
String window_name = useRefine ? "Result - standard refinement" : "Result - no refinement";
|
||||
window_name += useCanny ? " - Canny edge detector used" : "";
|
||||
|
||||
imshow(window_name, image);
|
||||
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main( int argc, const char** argv )
|
||||
{
|
||||
CommandLineParser parser(argc, argv,
|
||||
"{ i | lena_tmpl.jpg |image name }"
|
||||
"{ t | tmpl.png |template name }"
|
||||
"{ m | mask.png |mask name }"
|
||||
"{ cm| 3 |comparison method }");
|
||||
|
||||
cout << "This program demonstrates the use of template matching with mask." << endl
|
||||
<< endl
|
||||
<< "Available methods: https://docs.opencv.org/5.x/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d" << endl
|
||||
<< " TM_SQDIFF = " << (int)TM_SQDIFF << endl
|
||||
<< " TM_SQDIFF_NORMED = " << (int)TM_SQDIFF_NORMED << endl
|
||||
<< " TM_CCORR = " << (int)TM_CCORR << endl
|
||||
<< " TM_CCORR_NORMED = " << (int)TM_CCORR_NORMED << endl
|
||||
<< " TM_CCOEFF = " << (int)TM_CCOEFF << endl
|
||||
<< " TM_CCOEFF_NORMED = " << (int)TM_CCOEFF_NORMED << endl
|
||||
<< endl;
|
||||
|
||||
parser.printMessage();
|
||||
|
||||
string filename = samples::findFile(parser.get<string>("i"));
|
||||
string tmplname = samples::findFile(parser.get<string>("t"));
|
||||
string maskname = samples::findFile(parser.get<string>("m"));
|
||||
Mat img = imread(filename);
|
||||
Mat tmpl = imread(tmplname);
|
||||
Mat mask = imread(maskname);
|
||||
Mat res;
|
||||
|
||||
if(img.empty())
|
||||
{
|
||||
cout << "can not open " << filename << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(tmpl.empty())
|
||||
{
|
||||
cout << "can not open " << tmplname << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(mask.empty())
|
||||
{
|
||||
cout << "can not open " << maskname << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int method = parser.get<int>("cm"); // default 3 (cv::TM_CCORR_NORMED)
|
||||
matchTemplate(img, tmpl, res, method, mask);
|
||||
|
||||
double minVal, maxVal;
|
||||
Point minLoc, maxLoc;
|
||||
Rect rect;
|
||||
minMaxLoc(res, &minVal, &maxVal, &minLoc, &maxLoc);
|
||||
|
||||
if(method == TM_SQDIFF || method == TM_SQDIFF_NORMED)
|
||||
rect = Rect(minLoc, tmpl.size());
|
||||
else
|
||||
rect = Rect(maxLoc, tmpl.size());
|
||||
|
||||
rectangle(img, rect, Scalar(0, 255, 0), 2);
|
||||
|
||||
imshow("detected template", img);
|
||||
waitKey();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
using namespace cv;
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
VideoCapture video(0);
|
||||
Mat frame, curr, prev, curr64f, prev64f, hann;
|
||||
char key;
|
||||
|
||||
do
|
||||
{
|
||||
video >> frame;
|
||||
cvtColor(frame, curr, COLOR_RGB2GRAY);
|
||||
|
||||
if(prev.empty())
|
||||
{
|
||||
prev = curr.clone();
|
||||
createHanningWindow(hann, curr.size(), CV_64F);
|
||||
}
|
||||
|
||||
prev.convertTo(prev64f, CV_64F);
|
||||
curr.convertTo(curr64f, CV_64F);
|
||||
|
||||
Point2d shift = phaseCorrelate(prev64f, curr64f, hann);
|
||||
double radius = std::sqrt(shift.x*shift.x + shift.y*shift.y);
|
||||
|
||||
if(radius > 5)
|
||||
{
|
||||
// draw a circle and line indicating the shift direction...
|
||||
Point center(curr.cols >> 1, curr.rows >> 1);
|
||||
circle(frame, center, (int)radius, Scalar(0, 255, 0), 3, LINE_AA);
|
||||
line(frame, center, Point(center.x + (int)shift.x, center.y + (int)shift.y), Scalar(0, 255, 0), 3, LINE_AA);
|
||||
}
|
||||
|
||||
imshow("phase shift", frame);
|
||||
key = (char)waitKey(2);
|
||||
|
||||
prev = curr.clone();
|
||||
} while(key != 27); // Esc to exit...
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
VideoCapture capture;
|
||||
Mat log_polar_img, lin_polar_img, recovered_log_polar, recovered_lin_polar_img;
|
||||
|
||||
CommandLineParser parser(argc, argv, "{@input|0| camera device number or video file path}");
|
||||
parser.about("\nThis program illustrates usage of Linear-Polar and Log-Polar image transforms\n");
|
||||
parser.printMessage();
|
||||
std::string arg = parser.get<std::string>("@input");
|
||||
|
||||
if( arg.size() == 1 && isdigit(arg[0]) )
|
||||
capture.open( arg[0] - '0' );
|
||||
else
|
||||
capture.open(samples::findFileOrKeep(arg));
|
||||
|
||||
if( !capture.isOpened() )
|
||||
{
|
||||
fprintf(stderr,"Could not initialize capturing...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
namedWindow( "Linear-Polar", WINDOW_AUTOSIZE );
|
||||
namedWindow( "Log-Polar", WINDOW_AUTOSIZE);
|
||||
namedWindow( "Recovered Linear-Polar", WINDOW_AUTOSIZE);
|
||||
namedWindow( "Recovered Log-Polar", WINDOW_AUTOSIZE);
|
||||
|
||||
moveWindow( "Linear-Polar", 20,20 );
|
||||
moveWindow( "Log-Polar", 700,20 );
|
||||
moveWindow( "Recovered Linear-Polar", 20, 350 );
|
||||
moveWindow( "Recovered Log-Polar", 700, 350 );
|
||||
int flags = INTER_LINEAR + WARP_FILL_OUTLIERS;
|
||||
Mat src;
|
||||
for(;;)
|
||||
{
|
||||
capture >> src;
|
||||
|
||||
if(src.empty() )
|
||||
break;
|
||||
|
||||
Point2f center( (float)src.cols / 2, (float)src.rows / 2 );
|
||||
double maxRadius = 0.7*min(center.y, center.x);
|
||||
|
||||
#if 0 //deprecated
|
||||
double M = frame.cols / log(maxRadius);
|
||||
logPolar(frame, log_polar_img, center, M, flags);
|
||||
linearPolar(frame, lin_polar_img, center, maxRadius, flags);
|
||||
|
||||
logPolar(log_polar_img, recovered_log_polar, center, M, flags + WARP_INVERSE_MAP);
|
||||
linearPolar(lin_polar_img, recovered_lin_polar_img, center, maxRadius, flags + WARP_INVERSE_MAP);
|
||||
#endif
|
||||
//! [InverseMap]
|
||||
// direct transform
|
||||
warpPolar(src, lin_polar_img, Size(),center, maxRadius, flags); // linear Polar
|
||||
warpPolar(src, log_polar_img, Size(),center, maxRadius, flags + WARP_POLAR_LOG); // semilog Polar
|
||||
// inverse transform
|
||||
warpPolar(lin_polar_img, recovered_lin_polar_img, src.size(), center, maxRadius, flags + WARP_INVERSE_MAP);
|
||||
warpPolar(log_polar_img, recovered_log_polar, src.size(), center, maxRadius, flags + WARP_POLAR_LOG + WARP_INVERSE_MAP);
|
||||
//! [InverseMap]
|
||||
|
||||
// Below is the reverse transformation for (rho, phi)->(x, y) :
|
||||
Mat dst;
|
||||
if (flags & WARP_POLAR_LOG)
|
||||
dst = log_polar_img;
|
||||
else
|
||||
dst = lin_polar_img;
|
||||
//get a point from the polar image
|
||||
int rho = cvRound(dst.cols * 0.75);
|
||||
int phi = cvRound(dst.rows / 2.0);
|
||||
|
||||
//! [InverseCoordinate]
|
||||
double angleRad, magnitude;
|
||||
double Kangle = dst.rows / CV_2PI;
|
||||
angleRad = phi / Kangle;
|
||||
if (flags & WARP_POLAR_LOG)
|
||||
{
|
||||
double Klog = dst.cols / std::log(maxRadius);
|
||||
magnitude = std::exp(rho / Klog);
|
||||
}
|
||||
else
|
||||
{
|
||||
double Klin = dst.cols / maxRadius;
|
||||
magnitude = rho / Klin;
|
||||
}
|
||||
int x = cvRound(center.x + magnitude * cos(angleRad));
|
||||
int y = cvRound(center.y + magnitude * sin(angleRad));
|
||||
//! [InverseCoordinate]
|
||||
drawMarker(src, Point(x, y), Scalar(0, 255, 0));
|
||||
drawMarker(dst, Point(rho, phi), Scalar(0, 255, 0));
|
||||
|
||||
imshow("Src frame", src);
|
||||
imshow("Log-Polar", log_polar_img);
|
||||
imshow("Linear-Polar", lin_polar_img);
|
||||
imshow("Recovered Linear-Polar", recovered_lin_polar_img );
|
||||
imshow("Recovered Log-Polar", recovered_log_polar );
|
||||
|
||||
if( waitKey(10) >= 0 )
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/videoio.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/video/background_segm.hpp"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
printf("\n"
|
||||
"This program demonstrated a simple method of connected components clean up of background subtraction\n"
|
||||
"When the program starts, it begins learning the background.\n"
|
||||
"You can toggle background learning on and off by hitting the space bar.\n"
|
||||
"Call\n"
|
||||
"%s [video file, else it reads camera 0]\n\n", argv[0]);
|
||||
}
|
||||
|
||||
static void refineSegments(const Mat& img, Mat& mask, Mat& dst)
|
||||
{
|
||||
int niters = 3;
|
||||
|
||||
vector<vector<Point> > contours;
|
||||
vector<Vec4i> hierarchy;
|
||||
|
||||
Mat temp;
|
||||
|
||||
dilate(mask, temp, Mat(), Point(-1,-1), niters);
|
||||
erode(temp, temp, Mat(), Point(-1,-1), niters*2);
|
||||
dilate(temp, temp, Mat(), Point(-1,-1), niters);
|
||||
|
||||
findContours( temp, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE );
|
||||
|
||||
dst = Mat::zeros(img.size(), CV_8UC3);
|
||||
|
||||
if( contours.size() == 0 )
|
||||
return;
|
||||
|
||||
// iterate through all the top-level contours,
|
||||
// draw each connected component with its own random color
|
||||
int idx = 0, largestComp = 0;
|
||||
double maxArea = 0;
|
||||
|
||||
for( ; idx >= 0; idx = hierarchy[idx][0] )
|
||||
{
|
||||
const vector<Point>& c = contours[idx];
|
||||
double area = fabs(contourArea(Mat(c)));
|
||||
if( area > maxArea )
|
||||
{
|
||||
maxArea = area;
|
||||
largestComp = idx;
|
||||
}
|
||||
}
|
||||
Scalar color( 0, 0, 255 );
|
||||
drawContours( dst, contours, largestComp, color, FILLED, LINE_8, hierarchy );
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
VideoCapture cap;
|
||||
bool update_bg_model = true;
|
||||
|
||||
CommandLineParser parser(argc, argv, "{help h||}{@input||}");
|
||||
if (parser.has("help"))
|
||||
{
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
string input = parser.get<std::string>("@input");
|
||||
if (input.empty())
|
||||
cap.open(0);
|
||||
else
|
||||
cap.open(samples::findFileOrKeep(input));
|
||||
|
||||
if( !cap.isOpened() )
|
||||
{
|
||||
printf("\nCan not open camera or video file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Mat tmp_frame, bgmask, out_frame;
|
||||
|
||||
cap >> tmp_frame;
|
||||
if(tmp_frame.empty())
|
||||
{
|
||||
printf("can not read data from the video source\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
namedWindow("video", 1);
|
||||
namedWindow("segmented", 1);
|
||||
|
||||
Ptr<BackgroundSubtractorMOG2> bgsubtractor=createBackgroundSubtractorMOG2();
|
||||
bgsubtractor->setVarThreshold(10);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
cap >> tmp_frame;
|
||||
if( tmp_frame.empty() )
|
||||
break;
|
||||
bgsubtractor->apply(tmp_frame, bgmask, update_bg_model ? -1 : 0);
|
||||
refineSegments(tmp_frame, bgmask, out_frame);
|
||||
imshow("video", tmp_frame);
|
||||
imshow("segmented", out_frame);
|
||||
char keycode = (char)waitKey(30);
|
||||
if( keycode == 27 )
|
||||
break;
|
||||
if( keycode == ' ' )
|
||||
{
|
||||
update_bg_model = !update_bg_model;
|
||||
printf("Learn background is in state = %d\n",update_bg_model);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
|
||||
// The "Square Detector" program.
|
||||
// It loads several images sequentially and tries to find squares in
|
||||
// each image
|
||||
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
static void help(const char* programName)
|
||||
{
|
||||
cout <<
|
||||
"\nA program using pyramid scaling, Canny, contours and contour simplification\n"
|
||||
"to find squares in a list of images (pic1-6.png)\n"
|
||||
"Returns sequence of squares detected on the image.\n"
|
||||
"Call:\n"
|
||||
"./" << programName << " [file_name (optional)]\n"
|
||||
"Using OpenCV version " << CV_VERSION << "\n" << endl;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
static 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.
|
||||
static 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, RETR_LIST, 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(contours[i], approx, arcLength(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(approx)) > 1000 &&
|
||||
isContourConvex(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* names[] = { "pic1.png", "pic2.png", "pic3.png",
|
||||
"pic4.png", "pic5.png", "pic6.png", 0 };
|
||||
help(argv[0]);
|
||||
|
||||
if( argc > 1)
|
||||
{
|
||||
names[0] = argv[1];
|
||||
names[1] = 0;
|
||||
}
|
||||
|
||||
for( int i = 0; names[i] != 0; i++ )
|
||||
{
|
||||
string filename = samples::findFile(names[i]);
|
||||
Mat image = imread(filename, IMREAD_COLOR);
|
||||
if( image.empty() )
|
||||
{
|
||||
cout << "Couldn't load " << filename << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
vector<vector<Point> > squares;
|
||||
findSquares(image, squares);
|
||||
|
||||
polylines(image, squares, true, Scalar(0, 255, 0), 3, LINE_AA);
|
||||
imshow(wndname, image);
|
||||
|
||||
int c = waitKey();
|
||||
if( c == 27 )
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/stitching.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
bool divide_images = false;
|
||||
Stitcher::Mode mode = Stitcher::PANORAMA;
|
||||
vector<Mat> imgs;
|
||||
string result_name = "result.jpg";
|
||||
|
||||
void printUsage(char** argv);
|
||||
int parseCmdArgs(int argc, char** argv);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int retval = parseCmdArgs(argc, argv);
|
||||
if (retval) return EXIT_FAILURE;
|
||||
|
||||
//![stitching]
|
||||
Mat pano;
|
||||
Ptr<Stitcher> stitcher = Stitcher::create(mode);
|
||||
Stitcher::Status status = stitcher->stitch(imgs, pano);
|
||||
|
||||
if (status != Stitcher::OK)
|
||||
{
|
||||
cout << "Can't stitch images, error code = " << int(status) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
//![stitching]
|
||||
|
||||
imwrite(result_name, pano);
|
||||
cout << "stitching completed successfully\n" << result_name << " saved!";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void printUsage(char** argv)
|
||||
{
|
||||
cout <<
|
||||
"Images stitcher.\n\n" << "Usage :\n" << argv[0] <<" [Flags] img1 img2 [...imgN]\n\n"
|
||||
"Flags:\n"
|
||||
" --d3\n"
|
||||
" internally creates three chunks of each image to increase stitching success\n"
|
||||
" --mode (panorama|scans)\n"
|
||||
" Determines configuration of stitcher. The default is 'panorama',\n"
|
||||
" mode suitable for creating photo panoramas. Option 'scans' is suitable\n"
|
||||
" for stitching materials under affine transformation, such as scans.\n"
|
||||
" --output <result_img>\n"
|
||||
" The default is 'result.jpg'.\n\n"
|
||||
"Example usage :\n" << argv[0] << " --d3 --mode scans img1.jpg img2.jpg\n";
|
||||
}
|
||||
|
||||
|
||||
int parseCmdArgs(int argc, char** argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
printUsage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (string(argv[i]) == "--help" || string(argv[i]) == "/?")
|
||||
{
|
||||
printUsage(argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (string(argv[i]) == "--d3")
|
||||
{
|
||||
divide_images = true;
|
||||
}
|
||||
else if (string(argv[i]) == "--output")
|
||||
{
|
||||
result_name = argv[i + 1];
|
||||
i++;
|
||||
}
|
||||
else if (string(argv[i]) == "--mode")
|
||||
{
|
||||
if (string(argv[i + 1]) == "panorama")
|
||||
mode = Stitcher::PANORAMA;
|
||||
else if (string(argv[i + 1]) == "scans")
|
||||
mode = Stitcher::SCANS;
|
||||
else
|
||||
{
|
||||
cout << "Bad --mode flag value\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat img = imread(samples::findFile(argv[i]));
|
||||
if (img.empty())
|
||||
{
|
||||
cout << "Can't read image '" << argv[i] << "'\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (divide_images)
|
||||
{
|
||||
Rect rect(0, 0, img.cols / 2, img.rows);
|
||||
imgs.push_back(img(rect).clone());
|
||||
rect.x = img.cols / 3;
|
||||
imgs.push_back(img(rect).clone());
|
||||
rect.x = img.cols / 2;
|
||||
imgs.push_back(img(rect).clone());
|
||||
}
|
||||
else
|
||||
imgs.push_back(img);
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
@file warpPerspective_demo.cpp
|
||||
@brief a demo program shows how perspective transformation applied on an image
|
||||
@based on a sample code http://study.marearts.com/2015/03/image-warping-using-opencv.html
|
||||
@modified by Suleyman TURKMEN
|
||||
*/
|
||||
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
// print a welcome message, and the OpenCV version
|
||||
cout << "\nThis is a demo program shows how perspective transformation applied on an image, \n"
|
||||
"Using OpenCV version " << CV_VERSION << endl;
|
||||
|
||||
cout << "\nUsage:\n" << argv[0] << " [image_name -- Default right.jpg]\n" << endl;
|
||||
|
||||
cout << "\nHot keys: \n"
|
||||
"\tESC, q - quit the program\n"
|
||||
"\tr - change order of points to rotate transformation\n"
|
||||
"\tc - delete selected points\n"
|
||||
"\ti - change order of points to inverse transformation \n"
|
||||
"\nUse your mouse to select a point and move it to see transformation changes" << endl;
|
||||
}
|
||||
|
||||
static void onMouse(int event, int x, int y, int, void*);
|
||||
Mat warping(Mat image, Size warped_image_size, vector< Point2f> srcPoints, vector< Point2f> dstPoints);
|
||||
|
||||
String windowTitle = "Perspective Transformation Demo";
|
||||
String labels[4] = { "TL","TR","BR","BL" };
|
||||
vector< Point2f> roi_corners;
|
||||
vector< Point2f> midpoints(4);
|
||||
vector< Point2f> dst_corners(4);
|
||||
int roiIndex = 0;
|
||||
bool dragging;
|
||||
int selected_corner_index = 0;
|
||||
bool validation_needed = true;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
help(argv);
|
||||
CommandLineParser parser(argc, argv, "{@input| right.jpg |}");
|
||||
|
||||
string filename = samples::findFile(parser.get<string>("@input"));
|
||||
Mat original_image = imread( filename );
|
||||
Mat image;
|
||||
|
||||
float original_image_cols = (float)original_image.cols;
|
||||
float original_image_rows = (float)original_image.rows;
|
||||
roi_corners.push_back(Point2f( (float)(original_image_cols / 1.70), (float)(original_image_rows / 4.20) ));
|
||||
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.15), (float)(original_image.rows / 3.32) ));
|
||||
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.33), (float)(original_image.rows / 1.10) ));
|
||||
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.93), (float)(original_image.rows / 1.36) ));
|
||||
|
||||
namedWindow(windowTitle, WINDOW_NORMAL);
|
||||
namedWindow("Warped Image", WINDOW_AUTOSIZE);
|
||||
moveWindow("Warped Image", 20, 20);
|
||||
moveWindow(windowTitle, 330, 20);
|
||||
|
||||
setMouseCallback(windowTitle, onMouse, 0);
|
||||
|
||||
bool endProgram = false;
|
||||
while (!endProgram)
|
||||
{
|
||||
if ( validation_needed & (roi_corners.size() < 4) )
|
||||
{
|
||||
validation_needed = false;
|
||||
image = original_image.clone();
|
||||
|
||||
for (size_t i = 0; i < roi_corners.size(); ++i)
|
||||
{
|
||||
circle( image, roi_corners[i], 5, Scalar(0, 255, 0), 3 );
|
||||
|
||||
if( i > 0 )
|
||||
{
|
||||
line(image, roi_corners[i-1], roi_corners[(i)], Scalar(0, 0, 255), 2);
|
||||
circle(image, roi_corners[i], 5, Scalar(0, 255, 0), 3);
|
||||
putText(image, labels[i].c_str(), roi_corners[i], FONT_HERSHEY_SIMPLEX, 0.8, Scalar(255, 0, 0), 2);
|
||||
}
|
||||
}
|
||||
imshow( windowTitle, image );
|
||||
}
|
||||
|
||||
if ( validation_needed & ( roi_corners.size() == 4 ))
|
||||
{
|
||||
image = original_image.clone();
|
||||
for ( int i = 0; i < 4; ++i )
|
||||
{
|
||||
line(image, roi_corners[i], roi_corners[(i + 1) % 4], Scalar(0, 0, 255), 2);
|
||||
circle(image, roi_corners[i], 5, Scalar(0, 255, 0), 3);
|
||||
putText(image, labels[i].c_str(), roi_corners[i], FONT_HERSHEY_SIMPLEX, 0.8, Scalar(255, 0, 0), 2);
|
||||
}
|
||||
|
||||
imshow( windowTitle, image );
|
||||
|
||||
midpoints[0] = (roi_corners[0] + roi_corners[1]) / 2;
|
||||
midpoints[1] = (roi_corners[1] + roi_corners[2]) / 2;
|
||||
midpoints[2] = (roi_corners[2] + roi_corners[3]) / 2;
|
||||
midpoints[3] = (roi_corners[3] + roi_corners[0]) / 2;
|
||||
|
||||
dst_corners[0].x = 0;
|
||||
dst_corners[0].y = 0;
|
||||
dst_corners[1].x = (float)norm(midpoints[1] - midpoints[3]);
|
||||
dst_corners[1].y = 0;
|
||||
dst_corners[2].x = dst_corners[1].x;
|
||||
dst_corners[2].y = (float)norm(midpoints[0] - midpoints[2]);
|
||||
dst_corners[3].x = 0;
|
||||
dst_corners[3].y = dst_corners[2].y;
|
||||
|
||||
Size warped_image_size = Size(cvRound(dst_corners[2].x), cvRound(dst_corners[2].y));
|
||||
|
||||
Mat M = getPerspectiveTransform(roi_corners, dst_corners);
|
||||
|
||||
Mat warped_image;
|
||||
warpPerspective(original_image, warped_image, M, warped_image_size); // do perspective transformation
|
||||
|
||||
imshow("Warped Image", warped_image);
|
||||
}
|
||||
|
||||
char c = (char)waitKey( 10 );
|
||||
|
||||
if ((c == 'q') | (c == 'Q') | (c == 27))
|
||||
{
|
||||
endProgram = true;
|
||||
}
|
||||
|
||||
if ((c == 'c') | (c == 'C'))
|
||||
{
|
||||
roi_corners.clear();
|
||||
}
|
||||
|
||||
if ((c == 'r') | (c == 'R'))
|
||||
{
|
||||
roi_corners.push_back(roi_corners[0]);
|
||||
roi_corners.erase(roi_corners.begin());
|
||||
}
|
||||
|
||||
if ((c == 'i') | (c == 'I'))
|
||||
{
|
||||
swap(roi_corners[0], roi_corners[1]);
|
||||
swap(roi_corners[2], roi_corners[3]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void onMouse(int event, int x, int y, int, void*)
|
||||
{
|
||||
// Action when left button is pressed
|
||||
if (roi_corners.size() == 4)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if ((event == EVENT_LBUTTONDOWN) && ((abs(roi_corners[i].x - x) < 10)) && (abs(roi_corners[i].y - y) < 10))
|
||||
{
|
||||
selected_corner_index = i;
|
||||
dragging = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( event == EVENT_LBUTTONDOWN )
|
||||
{
|
||||
roi_corners.push_back( Point2f( (float) x, (float) y ) );
|
||||
validation_needed = true;
|
||||
}
|
||||
|
||||
// Action when left button is released
|
||||
if (event == EVENT_LBUTTONUP)
|
||||
{
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
// Action when left button is pressed and mouse has moved over the window
|
||||
if ((event == EVENT_MOUSEMOVE) && dragging)
|
||||
{
|
||||
roi_corners[selected_corner_index].x = (float) x;
|
||||
roi_corners[selected_corner_index].y = (float) y;
|
||||
validation_needed = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
static void help(char** argv)
|
||||
{
|
||||
cout << "\nThis program demonstrates the famous watershed segmentation algorithm in OpenCV: watershed()\n"
|
||||
"Usage:\n" << argv[0] <<" [image_name -- default is fruits.jpg]\n" << endl;
|
||||
|
||||
|
||||
cout << "Hot keys: \n"
|
||||
"\tESC - quit the program\n"
|
||||
"\tr - restore the original image\n"
|
||||
"\tw or SPACE - run watershed segmentation algorithm\n"
|
||||
"\t\t(before running it, *roughly* mark the areas to segment on the image)\n"
|
||||
"\t (before that, roughly outline several markers on the image)\n";
|
||||
}
|
||||
Mat markerMask, img;
|
||||
Point prevPt(-1, -1);
|
||||
|
||||
static 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 == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON) )
|
||||
prevPt = Point(-1,-1);
|
||||
else if( event == EVENT_LBUTTONDOWN )
|
||||
prevPt = Point(x,y);
|
||||
else if( event == EVENT_MOUSEMOVE && (flags & 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 )
|
||||
{
|
||||
cv::CommandLineParser parser(argc, argv, "{help h | | }{ @input | fruits.jpg | }");
|
||||
if (parser.has("help"))
|
||||
{
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
string filename = samples::findFile(parser.get<string>("@input"));
|
||||
Mat img0 = imread(filename, IMREAD_COLOR), imgGray;
|
||||
|
||||
if( img0.empty() )
|
||||
{
|
||||
cout << "Couldn't open image ";
|
||||
help(argv);
|
||||
return 0;
|
||||
}
|
||||
help(argv);
|
||||
namedWindow( "image", 1 );
|
||||
|
||||
img0.copyTo(img);
|
||||
cvtColor(img, markerMask, COLOR_BGR2GRAY);
|
||||
cvtColor(markerMask, imgGray, COLOR_GRAY2BGR);
|
||||
markerMask = Scalar::all(0);
|
||||
imshow( "image", img );
|
||||
setMouseCallback( "image", onMouse, 0 );
|
||||
|
||||
for(;;)
|
||||
{
|
||||
char c = (char)waitKey(0);
|
||||
|
||||
if( c == 27 )
|
||||
break;
|
||||
|
||||
if( c == 'r' )
|
||||
{
|
||||
markerMask = Scalar::all(0);
|
||||
img0.copyTo(img);
|
||||
imshow( "image", img );
|
||||
}
|
||||
|
||||
if( c == 'w' || c == ' ' )
|
||||
{
|
||||
int i, j, compCount = 0;
|
||||
vector<vector<Point> > contours;
|
||||
vector<Vec4i> hierarchy;
|
||||
|
||||
findContours(markerMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
|
||||
|
||||
if( contours.empty() )
|
||||
continue;
|
||||
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(0, 255);
|
||||
int g = theRNG().uniform(0, 255);
|
||||
int r = theRNG().uniform(0, 255);
|
||||
|
||||
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 index = markers.at<int>(i,j);
|
||||
if( index == -1 )
|
||||
wshed.at<Vec3b>(i,j) = Vec3b(255,255,255);
|
||||
else if( index <= 0 || index > compCount )
|
||||
wshed.at<Vec3b>(i,j) = Vec3b(0,0,0);
|
||||
else
|
||||
wshed.at<Vec3b>(i,j) = colorTab[index - 1];
|
||||
}
|
||||
|
||||
wshed = wshed*0.5 + imgGray*0.5;
|
||||
imshow( "watershed transform", wshed );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user