feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

View File

@ -0,0 +1,360 @@
/*
* 3calibration.cpp -- Calibrate 3 cameras in a horizontal line together.
*/
#include "opencv2/calib3d.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/utility.hpp"
#include <stdio.h>
#include <string.h>
#include <time.h>
using namespace cv;
using namespace std;
enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
static void help(char** argv)
{
printf( "\nThis is a camera calibration sample that calibrates 3 horizontally placed cameras together.\n"
"Usage: %s\n"
" -w=<board_width> # the number of inner corners per one of board dimension\n"
" -h=<board_height> # the number of inner corners per another board dimension\n"
" [-s=<squareSize>] # square size in some user-defined units (1 by default)\n"
" [-o=<out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters\n"
" [-zt] # assume zero tangential distortion\n"
" [-a=<aspectRatio>] # fix aspect ratio (fx/fy)\n"
" [-p] # fix the principal point at the center\n"
" [input_data] # input data - text file with a list of the images of the board\n"
"\n", argv[0] );
}
static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners)
{
corners.resize(0);
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float(j*squareSize),
float(i*squareSize), 0));
}
static bool run3Calibration(vector<vector<Point2f> > imagePoints1,
vector<vector<Point2f> > imagePoints2,
vector<vector<Point2f> > imagePoints3,
Size imageSize, Size boardSize,
float squareSize, float aspectRatio,
int flags,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Mat& cameraMatrix3, Mat& distCoeffs3,
Mat& R12, Mat& T12, Mat& R13, Mat& T13)
{
int c, i;
// step 1: calibrate each camera individually
vector<vector<Point3f> > objpt(1);
vector<vector<Point2f> > imgpt;
calcChessboardCorners(boardSize, squareSize, objpt[0]);
vector<Mat> rvecs, tvecs;
for( c = 1; c <= 3; c++ )
{
const vector<vector<Point2f> >& imgpt0 = c == 1 ? imagePoints1 : c == 2 ? imagePoints2 : imagePoints3;
imgpt.clear();
int N = 0;
for( i = 0; i < (int)imgpt0.size(); i++ )
if( !imgpt0[i].empty() )
{
imgpt.push_back(imgpt0[i]);
N += (int)imgpt0[i].size();
}
if( imgpt.size() < 3 )
{
printf("Error: not enough views for camera %d\n", c);
return false;
}
objpt.resize(imgpt.size(),objpt[0]);
Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
if( flags & CALIB_FIX_ASPECT_RATIO )
cameraMatrix.at<double>(0,0) = aspectRatio;
Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
double err = calibrateCamera(objpt, imgpt, imageSize, cameraMatrix,
distCoeffs, rvecs, tvecs,
flags|CALIB_FIX_K3/*|CALIB_FIX_K4|CALIB_FIX_K5|CALIB_FIX_K6*/);
bool ok = checkRange(cameraMatrix) && checkRange(distCoeffs);
if(!ok)
{
printf("Error: camera %d was not calibrated\n", c);
return false;
}
printf("Camera %d calibration reprojection error = %g\n", c, sqrt(err/N));
if( c == 1 )
cameraMatrix1 = cameraMatrix, distCoeffs1 = distCoeffs;
else if( c == 2 )
cameraMatrix2 = cameraMatrix, distCoeffs2 = distCoeffs;
else
cameraMatrix3 = cameraMatrix, distCoeffs3 = distCoeffs;
}
vector<vector<Point2f> > imgpt_right;
// step 2: calibrate (1,2) and (3,2) pairs
for( c = 2; c <= 3; c++ )
{
const vector<vector<Point2f> >& imgpt0 = c == 2 ? imagePoints2 : imagePoints3;
imgpt.clear();
imgpt_right.clear();
int N = 0;
for( i = 0; i < (int)std::min(imagePoints1.size(), imgpt0.size()); i++ )
if( !imagePoints1.empty() && !imgpt0[i].empty() )
{
imgpt.push_back(imagePoints1[i]);
imgpt_right.push_back(imgpt0[i]);
N += (int)imgpt0[i].size();
}
if( imgpt.size() < 3 )
{
printf("Error: not enough shared views for cameras 1 and %d\n", c);
return false;
}
objpt.resize(imgpt.size(),objpt[0]);
Mat cameraMatrix = c == 2 ? cameraMatrix2 : cameraMatrix3;
Mat distCoeffs = c == 2 ? distCoeffs2 : distCoeffs3;
Mat R, T, E, F;
double err = stereoCalibrate(objpt, imgpt, imgpt_right, cameraMatrix1, distCoeffs1,
cameraMatrix, distCoeffs,
imageSize, R, T, E, F,
CALIB_FIX_INTRINSIC,
TermCriteria(TermCriteria::COUNT, 30, 0));
printf("Pair (1,%d) calibration reprojection error = %g\n", c, sqrt(err/(N*2)));
if( c == 2 )
{
cameraMatrix2 = cameraMatrix;
distCoeffs2 = distCoeffs;
R12 = R; T12 = T;
}
else
{
R13 = R; T13 = T;
}
}
return true;
}
static bool readStringList( const string& filename, vector<string>& l )
{
l.resize(0);
FileStorage fs(filename, FileStorage::READ);
if( !fs.isOpened() )
return false;
FileNode n = fs.getFirstTopLevelNode();
if( n.type() != FileNode::SEQ )
return false;
FileNodeIterator it = n.begin(), it_end = n.end();
for( ; it != it_end; ++it )
l.push_back((string)*it);
return true;
}
int main( int argc, char** argv )
{
int i, k;
int flags = 0;
Size boardSize, imageSize;
float squareSize, aspectRatio;
string outputFilename;
string inputFilename = "";
vector<vector<Point2f> > imgpt[3];
vector<string> imageList;
cv::CommandLineParser parser(argc, argv,
"{help ||}{w||}{h||}{s|1|}{o|out_camera_data.yml|}"
"{zt||}{a|1|}{p||}{@input||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
boardSize.width = parser.get<int>("w");
boardSize.height = parser.get<int>("h");
squareSize = parser.get<float>("s");
aspectRatio = parser.get<float>("a");
if (parser.has("a"))
flags |= CALIB_FIX_ASPECT_RATIO;
if (parser.has("zt"))
flags |= CALIB_ZERO_TANGENT_DIST;
if (parser.has("p"))
flags |= CALIB_FIX_PRINCIPAL_POINT;
outputFilename = parser.get<string>("o");
inputFilename = parser.get<string>("@input");
if (!parser.check())
{
help(argv);
parser.printErrors();
return -1;
}
if (boardSize.width <= 0)
return fprintf( stderr, "Invalid board width\n" ), -1;
if (boardSize.height <= 0)
return fprintf( stderr, "Invalid board height\n" ), -1;
if (squareSize <= 0)
return fprintf( stderr, "Invalid board square width\n" ), -1;
if (aspectRatio <= 0)
return printf("Invalid aspect ratio\n" ), -1;
if( inputFilename.empty() ||
!readStringList(inputFilename, imageList) ||
imageList.size() == 0 || imageList.size() % 3 != 0 )
{
printf("Error: the input image list is not specified, or can not be read, or the number of files is not divisible by 3\n");
return -1;
}
Mat view, viewGray;
Mat cameraMatrix[3], distCoeffs[3], R[3], P[3], R12, T12;
for( k = 0; k < 3; k++ )
{
cameraMatrix[k] = Mat_<double>::eye(3,3);
cameraMatrix[k].at<double>(0,0) = aspectRatio;
cameraMatrix[k].at<double>(1,1) = 1;
distCoeffs[k] = Mat_<double>::zeros(5,1);
}
Mat R13=Mat_<double>::eye(3,3), T13=Mat_<double>::zeros(3,1);
FileStorage fs;
namedWindow( "Image View", 0 );
for( k = 0; k < 3; k++ )
imgpt[k].resize(imageList.size()/3);
for( i = 0; i < (int)(imageList.size()/3); i++ )
{
for( k = 0; k < 3; k++ )
{
int k1 = k == 0 ? 2 : k == 1 ? 0 : 1;
printf("%s\n", imageList[i*3+k].c_str());
view = imread(imageList[i*3+k], 1);
if(!view.empty())
{
vector<Point2f> ptvec;
imageSize = view.size();
cvtColor(view, viewGray, COLOR_BGR2GRAY);
bool found = findChessboardCorners( view, boardSize, ptvec, CALIB_CB_ADAPTIVE_THRESH );
drawChessboardCorners( view, boardSize, Mat(ptvec), found );
if( found )
{
imgpt[k1][i].resize(ptvec.size());
std::copy(ptvec.begin(), ptvec.end(), imgpt[k1][i].begin());
}
//imshow("view", view);
//int c = waitKey(0) & 255;
//if( c == 27 || c == 'q' || c == 'Q' )
// return -1;
}
}
}
printf("Running calibration ...\n");
run3Calibration(imgpt[0], imgpt[1], imgpt[2], imageSize,
boardSize, squareSize, aspectRatio, flags|CALIB_FIX_K4|CALIB_FIX_K5,
cameraMatrix[0], distCoeffs[0],
cameraMatrix[1], distCoeffs[1],
cameraMatrix[2], distCoeffs[2],
R12, T12, R13, T13);
fs.open(outputFilename, FileStorage::WRITE);
fs << "cameraMatrix1" << cameraMatrix[0];
fs << "cameraMatrix2" << cameraMatrix[1];
fs << "cameraMatrix3" << cameraMatrix[2];
fs << "distCoeffs1" << distCoeffs[0];
fs << "distCoeffs2" << distCoeffs[1];
fs << "distCoeffs3" << distCoeffs[2];
fs << "R12" << R12;
fs << "T12" << T12;
fs << "R13" << R13;
fs << "T13" << T13;
fs << "imageWidth" << imageSize.width;
fs << "imageHeight" << imageSize.height;
Mat Q;
// step 3: find rectification transforms
double ratio = rectify3Collinear(cameraMatrix[0], distCoeffs[0], cameraMatrix[1],
distCoeffs[1], cameraMatrix[2], distCoeffs[2],
imgpt[0], imgpt[2],
imageSize, R12, T12, R13, T13,
R[0], R[1], R[2], P[0], P[1], P[2], Q, -1.,
imageSize, 0, 0, CALIB_ZERO_DISPARITY);
Mat map1[3], map2[3];
fs << "R1" << R[0];
fs << "R2" << R[1];
fs << "R3" << R[2];
fs << "P1" << P[0];
fs << "P2" << P[1];
fs << "P3" << P[2];
fs << "disparityRatio" << ratio;
fs.release();
printf("Disparity ratio = %g\n", ratio);
for( k = 0; k < 3; k++ )
initUndistortRectifyMap(cameraMatrix[k], distCoeffs[k], R[k], P[k], imageSize, CV_16SC2, map1[k], map2[k]);
Mat canvas(imageSize.height, imageSize.width*3, CV_8UC3), small_canvas;
destroyWindow("view");
canvas = Scalar::all(0);
for( i = 0; i < (int)(imageList.size()/3); i++ )
{
canvas = Scalar::all(0);
for( k = 0; k < 3; k++ )
{
int k1 = k == 0 ? 2 : k == 1 ? 0 : 1;
int k2 = k == 0 ? 1 : k == 1 ? 0 : 2;
view = imread(imageList[i*3+k], 1);
if(view.empty())
continue;
Mat rview = canvas.colRange(k2*imageSize.width, (k2+1)*imageSize.width);
remap(view, rview, map1[k1], map2[k1], INTER_LINEAR);
}
printf("%s %s %s\n", imageList[i*3].c_str(), imageList[i*3+1].c_str(), imageList[i*3+2].c_str());
resize( canvas, small_canvas, Size(1500, 1500/3), 0, 0, INTER_LINEAR_EXACT );
for( k = 0; k < small_canvas.rows; k += 16 )
line(small_canvas, Point(0, k), Point(small_canvas.cols, k), Scalar(0,255,0), 1);
imshow("rectified", small_canvas);
char c = (char)waitKey(0);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
return 0;
}

View File

@ -0,0 +1,77 @@
ocv_install_example_src(cpp *.cpp *.hpp CMakeLists.txt)
set(OPENCV_CPP_SAMPLES_REQUIRED_DEPS
opencv_core
opencv_imgproc
opencv_flann
opencv_imgcodecs
opencv_videoio
opencv_highgui
opencv_ml
opencv_video
opencv_objdetect
opencv_photo
opencv_features2d
opencv_calib3d
opencv_stitching
opencv_dnn
${OPENCV_MODULES_PUBLIC}
${OpenCV_LIB_COMPONENTS})
ocv_check_dependencies(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS})
if(NOT BUILD_EXAMPLES OR NOT OCV_DEPENDENCIES_FOUND)
return()
endif()
set(DEPS_example_snippet_imgproc_segmentation opencv_core opencv_imgproc)
set(DEPS_example_cpp_intelligent_scissors opencv_core opencv_imgproc opencv_imgcodecs opencv_highgui)
project(cpp_samples)
ocv_include_modules_recurse(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS})
file(GLOB_RECURSE cpp_samples RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
if(NOT HAVE_opencv_cudaarithm OR NOT HAVE_opencv_cudafilters)
ocv_list_filterout(cpp_samples "/gpu/")
endif()
ocv_list_filterout(cpp_samples "real_time_pose_estimation/")
ocv_list_filterout(cpp_samples "parallel_backend/")
foreach(sample_filename ${cpp_samples})
set(package "cpp")
if(sample_filename MATCHES "tutorial_code/snippet")
set(package "snippet")
elseif(sample_filename MATCHES "tutorial_code")
set(package "tutorial")
endif()
ocv_define_sample(tgt ${sample_filename} ${package})
set(deps ${OPENCV_CPP_SAMPLES_REQUIRED_DEPS})
if(DEFINED DEPS_${tgt})
set(deps ${DEPS_${tgt}})
endif()
ocv_target_link_libraries(${tgt} PRIVATE ${OPENCV_LINKER_LIBS} ${deps})
if(sample_filename MATCHES "/gpu/" AND HAVE_opencv_cudaarithm AND HAVE_opencv_cuda_filters)
ocv_target_link_libraries(${tgt} PRIVATE opencv_cudaarithm opencv_cudafilters)
endif()
if(sample_filename MATCHES "/viz/")
ocv_target_link_libraries(${tgt} PRIVATE ${VTK_LIBRARIES})
target_compile_definitions(${tgt} PRIVATE -DUSE_VTK)
endif()
if(HAVE_OPENGL AND sample_filename MATCHES "detect_mser")
target_compile_definitions(${tgt} PRIVATE HAVE_OPENGL)
endif()
if(sample_filename MATCHES "simd_")
# disabled intentionally - demonstration purposes only
#target_include_directories(${tgt} PRIVATE "${CMAKE_CURRENT_LIST_DIR}")
#target_compile_definitions(${tgt} PRIVATE OPENCV_SIMD_CONFIG_HEADER=opencv_simd_config_custom.hpp)
#target_compile_definitions(${tgt} PRIVATE OPENCV_SIMD_CONFIG_INCLUDE_DIR=1)
#target_compile_options(${tgt} PRIVATE -mavx2)
endif()
endforeach()
include("tutorial_code/calib3d/real_time_pose_estimation/CMakeLists.txt" OPTIONAL)
# Standalone samples only
if(OpenCV_FOUND AND NOT CMAKE_VERSION VERSION_LESS "3.1")
add_subdirectory("example_cmake")
endif()
if(OpenCV_FOUND AND NOT CMAKE_VERSION VERSION_LESS "3.9")
add_subdirectory("tutorial_code/core/parallel_backend")
endif()

View File

@ -0,0 +1,95 @@
/* OpenCV Application Tracing support demo. */
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/core/utils/trace.hpp>
using namespace cv;
using namespace std;
static void process_frame(const cv::UMat& frame)
{
CV_TRACE_FUNCTION(); // OpenCV Trace macro for function
imshow("Live", frame);
UMat gray, processed;
cv::cvtColor(frame, gray, COLOR_BGR2GRAY);
Canny(gray, processed, 32, 64, 3);
imshow("Processed", processed);
}
int main(int argc, char** argv)
{
CV_TRACE_FUNCTION();
cv::CommandLineParser parser(argc, argv,
"{help h ? | | help message}"
"{n | 100 | number of frames to process }"
"{@video | 0 | video filename or cameraID }"
);
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
VideoCapture capture;
std::string video = parser.get<string>("@video");
if (video.size() == 1 && isdigit(video[0]))
capture.open(parser.get<int>("@video"));
else
capture.open(samples::findFileOrKeep(video)); // keep GStreamer pipelines
int nframes = 0;
if (capture.isOpened())
{
nframes = (int)capture.get(CAP_PROP_FRAME_COUNT);
cout << "Video " << video <<
": width=" << capture.get(CAP_PROP_FRAME_WIDTH) <<
", height=" << capture.get(CAP_PROP_FRAME_HEIGHT) <<
", nframes=" << nframes << endl;
}
else
{
cout << "Could not initialize video capturing...\n";
return -1;
}
int N = parser.get<int>("n");
if (nframes > 0 && N > nframes)
N = nframes;
cout << "Start processing..." << endl
<< "Press ESC key to terminate" << endl;
UMat frame;
for (int i = 0; N > 0 ? (i < N) : true; i++)
{
CV_TRACE_REGION("FRAME"); // OpenCV Trace macro for named "scope" region
{
CV_TRACE_REGION("read");
capture.read(frame);
if (frame.empty())
{
cerr << "Can't capture frame: " << i << std::endl;
break;
}
// OpenCV Trace macro for NEXT named region in the same C++ scope
// Previous "read" region will be marked complete on this line.
// Use this to eliminate unnecessary curly braces.
CV_TRACE_REGION_NEXT("process");
process_frame(frame);
CV_TRACE_REGION_NEXT("delay");
if (waitKey(1) == 27/*ESC*/)
break;
}
}
return 0;
}

View File

@ -0,0 +1,199 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/calib3d.hpp>
#include <iostream>
#include <iomanip>
using namespace std;
using namespace cv;
static void help(char** argv)
{
cout
<< "This is a sample usage of AffineFeature detector/extractor.\n"
<< "And this is a C++ version of samples/python/asift.py\n"
<< "Usage: " << argv[0] << "\n"
<< " [ --feature=<sift|orb|brisk> ] # Feature to use.\n"
<< " [ --flann ] # use Flann-based matcher instead of bruteforce.\n"
<< " [ --maxlines=<number(50 as default)> ] # The maximum number of lines in visualizing the matching result.\n"
<< " [ --image1=<image1(aero1.jpg as default)> ]\n"
<< " [ --image2=<image2(aero3.jpg as default)> ] # Path to images to compare."
<< endl;
}
static double timer()
{
return getTickCount() / getTickFrequency();
}
int main(int argc, char** argv)
{
vector<String> fileName;
cv::CommandLineParser parser(argc, argv,
"{help h ||}"
"{feature|brisk|}"
"{flann||}"
"{maxlines|50|}"
"{image1|aero1.jpg|}{image2|aero3.jpg|}");
if (parser.has("help"))
{
help(argv);
return 0;
}
string feature = parser.get<string>("feature");
bool useFlann = parser.has("flann");
int maxlines = parser.get<int>("maxlines");
fileName.push_back(samples::findFile(parser.get<string>("image1")));
fileName.push_back(samples::findFile(parser.get<string>("image2")));
if (!parser.check())
{
parser.printErrors();
cout << "See --help (or missing '=' between argument name and value?)" << endl;
return 1;
}
Mat img1 = imread(fileName[0], IMREAD_GRAYSCALE);
Mat img2 = imread(fileName[1], IMREAD_GRAYSCALE);
if (img1.empty())
{
cerr << "Image " << fileName[0] << " is empty or cannot be found" << endl;
return 1;
}
if (img2.empty())
{
cerr << "Image " << fileName[1] << " is empty or cannot be found" << endl;
return 1;
}
Ptr<Feature2D> backend;
Ptr<DescriptorMatcher> matcher;
if (feature == "sift")
{
backend = SIFT::create();
if (useFlann)
matcher = DescriptorMatcher::create("FlannBased");
else
matcher = DescriptorMatcher::create("BruteForce");
}
else if (feature == "orb")
{
backend = ORB::create();
if (useFlann)
matcher = makePtr<FlannBasedMatcher>(makePtr<flann::LshIndexParams>(6, 12, 1));
else
matcher = DescriptorMatcher::create("BruteForce-Hamming");
}
else if (feature == "brisk")
{
backend = BRISK::create();
if (useFlann)
matcher = makePtr<FlannBasedMatcher>(makePtr<flann::LshIndexParams>(6, 12, 1));
else
matcher = DescriptorMatcher::create("BruteForce-Hamming");
}
else
{
cerr << feature << " is not supported. See --help" << endl;
return 1;
}
cout << "extracting with " << feature << "..." << endl;
Ptr<AffineFeature> ext = AffineFeature::create(backend);
vector<KeyPoint> kp1, kp2;
Mat desc1, desc2;
ext->detectAndCompute(img1, Mat(), kp1, desc1);
ext->detectAndCompute(img2, Mat(), kp2, desc2);
cout << "img1 - " << kp1.size() << " features, "
<< "img2 - " << kp2.size() << " features"
<< endl;
cout << "matching with " << (useFlann ? "flann" : "bruteforce") << "..." << endl;
double start = timer();
// match and draw
vector< vector<DMatch> > rawMatches;
vector<Point2f> p1, p2;
vector<float> distances;
matcher->knnMatch(desc1, desc2, rawMatches, 2);
// filter_matches
for (size_t i = 0; i < rawMatches.size(); i++)
{
const vector<DMatch>& m = rawMatches[i];
if (m.size() == 2 && m[0].distance < m[1].distance * 0.75)
{
p1.push_back(kp1[m[0].queryIdx].pt);
p2.push_back(kp2[m[0].trainIdx].pt);
distances.push_back(m[0].distance);
}
}
vector<uchar> status;
vector< pair<Point2f, Point2f> > pointPairs;
Mat H = findHomography(p1, p2, status, RANSAC);
int inliers = 0;
for (size_t i = 0; i < status.size(); i++)
{
if (status[i])
{
pointPairs.push_back(make_pair(p1[i], p2[i]));
distances[inliers] = distances[i];
// CV_Assert(inliers <= (int)i);
inliers++;
}
}
distances.resize(inliers);
cout << "execution time: " << fixed << setprecision(2) << (timer()-start)*1000 << " ms" << endl;
cout << inliers << " / " << status.size() << " inliers/matched" << endl;
cout << "visualizing..." << endl;
vector<int> indices(inliers);
cv::sortIdx(distances, indices, SORT_EVERY_ROW+SORT_ASCENDING);
// explore_match
int h1 = img1.size().height;
int w1 = img1.size().width;
int h2 = img2.size().height;
int w2 = img2.size().width;
Mat vis = Mat::zeros(max(h1, h2), w1+w2, CV_8U);
img1.copyTo(Mat(vis, Rect(0, 0, w1, h1)));
img2.copyTo(Mat(vis, Rect(w1, 0, w2, h2)));
cvtColor(vis, vis, COLOR_GRAY2BGR);
vector<Point2f> corners(4);
corners[0] = Point2f(0, 0);
corners[1] = Point2f((float)w1, 0);
corners[2] = Point2f((float)w1, (float)h1);
corners[3] = Point2f(0, (float)h1);
vector<Point2i> icorners;
perspectiveTransform(corners, corners, H);
transform(corners, corners, Matx23f(1,0,(float)w1,0,1,0));
Mat(corners).convertTo(icorners, CV_32S);
polylines(vis, icorners, true, Scalar(255,255,255));
for (int i = 0; i < min(inliers, maxlines); i++)
{
int idx = indices[i];
const Point2f& pi1 = pointPairs[idx].first;
const Point2f& pi2 = pointPairs[idx].second;
circle(vis, pi1, 2, Scalar(0,255,0), -1);
circle(vis, pi2 + Point2f((float)w1,0), 2, Scalar(0,255,0), -1);
line(vis, pi1, pi2 + Point2f((float)w1,0), Scalar(0,255,0));
}
if (inliers > maxlines)
cout << "only " << maxlines << " inliers are visualized" << endl;
imshow("affine find_obj", vis);
// Mat vis2 = Mat::zeros(max(h1, h2), w1+w2, CV_8U);
// Mat warp1;
// warpPerspective(img1, warp1, H, Size(w1, h1));
// warp1.copyTo(Mat(vis2, Rect(0, 0, w1, h1)));
// img2.copyTo(Mat(vis2, Rect(w1, 0, w2, h2)));
// imshow("warped", vis2);
waitKey();
cout << "done" << endl;
return 0;
}

View File

@ -0,0 +1,124 @@
// 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/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/video.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, const char** argv)
{
const String keys = "{c camera | 0 | use video stream from camera (device index starting from 0) }"
"{fn file_name | | use video file as input }"
"{m method | mog2 | method: background subtraction algorithm ('knn', 'mog2')}"
"{h help | | show help message}";
CommandLineParser parser(argc, argv, keys);
parser.about("This sample demonstrates background segmentation.");
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
int camera = parser.get<int>("camera");
String file = parser.get<String>("file_name");
String method = parser.get<String>("method");
if (!parser.check())
{
parser.printErrors();
return 1;
}
VideoCapture cap;
if (file.empty())
cap.open(camera);
else
{
file = samples::findFileOrKeep(file); // ignore gstreamer pipelines
cap.open(file.c_str());
}
if (!cap.isOpened())
{
cout << "Can not open video stream: '" << (file.empty() ? "<camera>" : file) << "'" << endl;
return 2;
}
Ptr<BackgroundSubtractor> model;
if (method == "knn")
model = createBackgroundSubtractorKNN();
else if (method == "mog2")
model = createBackgroundSubtractorMOG2();
if (!model)
{
cout << "Can not create background model using provided method: '" << method << "'" << endl;
return 3;
}
cout << "Press <space> to toggle background model update" << endl;
cout << "Press 's' to toggle foreground mask smoothing" << endl;
cout << "Press ESC or 'q' to exit" << endl;
bool doUpdateModel = true;
bool doSmoothMask = false;
Mat inputFrame, frame, foregroundMask, foreground, background;
for (;;)
{
// prepare input frame
cap >> inputFrame;
if (inputFrame.empty())
{
cout << "Finished reading: empty frame" << endl;
break;
}
const Size scaledSize(640, 640 * inputFrame.rows / inputFrame.cols);
resize(inputFrame, frame, scaledSize, 0, 0, INTER_LINEAR);
// pass the frame to background model
model->apply(frame, foregroundMask, doUpdateModel ? -1 : 0);
// show processed frame
imshow("image", frame);
// show foreground image and mask (with optional smoothing)
if (doSmoothMask)
{
GaussianBlur(foregroundMask, foregroundMask, Size(11, 11), 3.5, 3.5);
threshold(foregroundMask, foregroundMask, 10, 255, THRESH_BINARY);
}
if (foreground.empty())
foreground.create(scaledSize, frame.type());
foreground = Scalar::all(0);
frame.copyTo(foreground, foregroundMask);
imshow("foreground mask", foregroundMask);
imshow("foreground image", foreground);
// show background image
model->getBackgroundImage(background);
if (!background.empty())
imshow("mean background image", background );
// interact with user
const char key = (char)waitKey(30);
if (key == 27 || key == 'q') // ESC
{
cout << "Exit requested" << endl;
break;
}
else if (key == ' ')
{
doUpdateModel = !doUpdateModel;
cout << "Toggle background update: " << (doUpdateModel ? "ON" : "OFF") << endl;
}
else if (key == 's')
{
doSmoothMask = !doSmoothMask;
cout << "Toggle foreground mask smoothing: " << (doSmoothMask ? "ON" : "OFF") << endl;
}
}
return 0;
}

View File

@ -0,0 +1,609 @@
#include "opencv2/core.hpp"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include <cctype>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <iostream>
using namespace cv;
using namespace std;
const char * usage =
" \nexample command line for calibration from a live feed.\n"
" calibration -w=4 -h=5 -s=0.025 -o=camera.yml -op -oe\n"
" \n"
" example command line for calibration from a list of stored images:\n"
" imagelist_creator image_list.xml *.png\n"
" calibration -w=4 -h=5 -s=0.025 -o=camera.yml -op -oe image_list.xml\n"
" where image_list.xml is the standard OpenCV XML/YAML\n"
" use imagelist_creator to create the xml or yaml list\n"
" file consisting of the list of strings, e.g.:\n"
" \n"
"<?xml version=\"1.0\"?>\n"
"<opencv_storage>\n"
"<images>\n"
"view000.png\n"
"view001.png\n"
"<!-- view002.png -->\n"
"view003.png\n"
"view010.png\n"
"one_extra_view.jpg\n"
"</images>\n"
"</opencv_storage>\n";
const char* liveCaptureHelp =
"When the live video from camera is used as input, the following hot-keys may be used:\n"
" <ESC>, 'q' - quit the program\n"
" 'g' - start capturing images\n"
" 'u' - switch undistortion on/off\n";
static void help(char** argv)
{
printf( "This is a camera calibration sample.\n"
"Usage: %s\n"
" -w=<board_width> # the number of inner corners per one of board dimension\n"
" -h=<board_height> # the number of inner corners per another board dimension\n"
" [-pt=<pattern>] # the type of pattern: chessboard or circles' grid\n"
" [-n=<number_of_frames>] # the number of frames to use for calibration\n"
" # (if not specified, it will be set to the number\n"
" # of board views actually available)\n"
" [-d=<delay>] # a minimum delay in ms between subsequent attempts to capture a next view\n"
" # (used only for video capturing)\n"
" [-s=<squareSize>] # square size in some user-defined units (1 by default)\n"
" [-o=<out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters\n"
" [-op] # write detected feature points\n"
" [-oe] # write extrinsic parameters\n"
" [-oo] # write refined 3D object points\n"
" [-zt] # assume zero tangential distortion\n"
" [-a=<aspectRatio>] # fix aspect ratio (fx/fy)\n"
" [-p] # fix the principal point at the center\n"
" [-v] # flip the captured images around the horizontal axis\n"
" [-V] # use a video file, and not an image list, uses\n"
" # [input_data] string for the video file name\n"
" [-su] # show undistorted images after calibration\n"
" [-ws=<number_of_pixel>] # Half of search window for cornerSubPix (11 by default)\n"
" [-dt=<distance>] # actual distance between top-left and top-right corners of\n"
" # the calibration grid. If this parameter is specified, a more\n"
" # accurate calibration method will be used which may be better\n"
" # with inaccurate, roughly planar target.\n"
" [input_data] # input data, one of the following:\n"
" # - text file with a list of the images of the board\n"
" # the text file can be generated with imagelist_creator\n"
" # - name of video file with a video of the board\n"
" # if input_data not specified, a live view from the camera is used\n"
"\n", argv[0] );
printf("\n%s",usage);
printf( "\n%s", liveCaptureHelp );
}
enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
static double computeReprojectionErrors(
const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints,
const vector<Mat>& rvecs, const vector<Mat>& tvecs,
const Mat& cameraMatrix, const Mat& distCoeffs,
vector<float>& perViewErrors )
{
vector<Point2f> imagePoints2;
int i, totalPoints = 0;
double totalErr = 0, err;
perViewErrors.resize(objectPoints.size());
for( i = 0; i < (int)objectPoints.size(); i++ )
{
projectPoints(Mat(objectPoints[i]), rvecs[i], tvecs[i],
cameraMatrix, distCoeffs, imagePoints2);
err = norm(Mat(imagePoints[i]), Mat(imagePoints2), NORM_L2);
int n = (int)objectPoints[i].size();
perViewErrors[i] = (float)std::sqrt(err*err/n);
totalErr += err*err;
totalPoints += n;
}
return std::sqrt(totalErr/totalPoints);
}
static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD)
{
corners.resize(0);
switch(patternType)
{
case CHESSBOARD:
case CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float(j*squareSize),
float(i*squareSize), 0));
break;
case ASYMMETRIC_CIRCLES_GRID:
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float((2*j + i % 2)*squareSize),
float(i*squareSize), 0));
break;
default:
CV_Error(Error::StsBadArg, "Unknown pattern type\n");
}
}
static bool runCalibration( vector<vector<Point2f> > imagePoints,
Size imageSize, Size boardSize, Pattern patternType,
float squareSize, float aspectRatio,
float grid_width, bool release_object,
int flags, Mat& cameraMatrix, Mat& distCoeffs,
vector<Mat>& rvecs, vector<Mat>& tvecs,
vector<float>& reprojErrs,
vector<Point3f>& newObjPoints,
double& totalAvgErr)
{
cameraMatrix = Mat::eye(3, 3, CV_64F);
if( flags & CALIB_FIX_ASPECT_RATIO )
cameraMatrix.at<double>(0,0) = aspectRatio;
distCoeffs = Mat::zeros(8, 1, CV_64F);
vector<vector<Point3f> > objectPoints(1);
calcChessboardCorners(boardSize, squareSize, objectPoints[0], patternType);
objectPoints[0][boardSize.width - 1].x = objectPoints[0][0].x + grid_width;
newObjPoints = objectPoints[0];
objectPoints.resize(imagePoints.size(),objectPoints[0]);
double rms;
int iFixedPoint = -1;
if (release_object)
iFixedPoint = boardSize.width - 1;
rms = calibrateCameraRO(objectPoints, imagePoints, imageSize, iFixedPoint,
cameraMatrix, distCoeffs, rvecs, tvecs, newObjPoints,
flags | CALIB_FIX_K3 | CALIB_USE_LU);
printf("RMS error reported by calibrateCamera: %g\n", rms);
bool ok = checkRange(cameraMatrix) && checkRange(distCoeffs);
if (release_object) {
cout << "New board corners: " << endl;
cout << newObjPoints[0] << endl;
cout << newObjPoints[boardSize.width - 1] << endl;
cout << newObjPoints[boardSize.width * (boardSize.height - 1)] << endl;
cout << newObjPoints.back() << endl;
}
objectPoints.clear();
objectPoints.resize(imagePoints.size(), newObjPoints);
totalAvgErr = computeReprojectionErrors(objectPoints, imagePoints,
rvecs, tvecs, cameraMatrix, distCoeffs, reprojErrs);
return ok;
}
static void saveCameraParams( const string& filename,
Size imageSize, Size boardSize,
float squareSize, float aspectRatio, int flags,
const Mat& cameraMatrix, const Mat& distCoeffs,
const vector<Mat>& rvecs, const vector<Mat>& tvecs,
const vector<float>& reprojErrs,
const vector<vector<Point2f> >& imagePoints,
const vector<Point3f>& newObjPoints,
double totalAvgErr )
{
FileStorage fs( filename, FileStorage::WRITE );
time_t tt;
time( &tt );
struct tm *t2 = localtime( &tt );
char buf[1024];
strftime( buf, sizeof(buf)-1, "%c", t2 );
fs << "calibration_time" << buf;
if( !rvecs.empty() || !reprojErrs.empty() )
fs << "nframes" << (int)std::max(rvecs.size(), reprojErrs.size());
fs << "image_width" << imageSize.width;
fs << "image_height" << imageSize.height;
fs << "board_width" << boardSize.width;
fs << "board_height" << boardSize.height;
fs << "square_size" << squareSize;
if( flags & CALIB_FIX_ASPECT_RATIO )
fs << "aspectRatio" << aspectRatio;
if( flags != 0 )
{
sprintf( buf, "flags: %s%s%s%s",
flags & CALIB_USE_INTRINSIC_GUESS ? "+use_intrinsic_guess" : "",
flags & CALIB_FIX_ASPECT_RATIO ? "+fix_aspectRatio" : "",
flags & CALIB_FIX_PRINCIPAL_POINT ? "+fix_principal_point" : "",
flags & CALIB_ZERO_TANGENT_DIST ? "+zero_tangent_dist" : "" );
//cvWriteComment( *fs, buf, 0 );
}
fs << "flags" << flags;
fs << "camera_matrix" << cameraMatrix;
fs << "distortion_coefficients" << distCoeffs;
fs << "avg_reprojection_error" << totalAvgErr;
if( !reprojErrs.empty() )
fs << "per_view_reprojection_errors" << Mat(reprojErrs);
if( !rvecs.empty() && !tvecs.empty() )
{
CV_Assert(rvecs[0].type() == tvecs[0].type());
Mat bigmat((int)rvecs.size(), 6, rvecs[0].type());
for( int i = 0; i < (int)rvecs.size(); i++ )
{
Mat r = bigmat(Range(i, i+1), Range(0,3));
Mat t = bigmat(Range(i, i+1), Range(3,6));
CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
//*.t() is MatExpr (not Mat) so we can use assignment operator
r = rvecs[i].t();
t = tvecs[i].t();
}
//cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
fs << "extrinsic_parameters" << bigmat;
}
if( !imagePoints.empty() )
{
Mat imagePtMat((int)imagePoints.size(), (int)imagePoints[0].size(), CV_32FC2);
for( int i = 0; i < (int)imagePoints.size(); i++ )
{
Mat r = imagePtMat.row(i).reshape(2, imagePtMat.cols);
Mat imgpti(imagePoints[i]);
imgpti.copyTo(r);
}
fs << "image_points" << imagePtMat;
}
if( !newObjPoints.empty() )
{
fs << "grid_points" << newObjPoints;
}
}
static bool readStringList( const string& filename, vector<string>& l )
{
l.resize(0);
FileStorage fs(filename, FileStorage::READ);
if( !fs.isOpened() )
return false;
size_t dir_pos = filename.rfind('/');
if (dir_pos == string::npos)
dir_pos = filename.rfind('\\');
FileNode n = fs.getFirstTopLevelNode();
if( n.type() != FileNode::SEQ )
return false;
FileNodeIterator it = n.begin(), it_end = n.end();
for( ; it != it_end; ++it )
{
string fname = (string)*it;
if (dir_pos != string::npos)
{
string fpath = samples::findFile(filename.substr(0, dir_pos + 1) + fname, false);
if (fpath.empty())
{
fpath = samples::findFile(fname);
}
fname = fpath;
}
else
{
fname = samples::findFile(fname);
}
l.push_back(fname);
}
return true;
}
static bool runAndSave(const string& outputFilename,
const vector<vector<Point2f> >& imagePoints,
Size imageSize, Size boardSize, Pattern patternType, float squareSize,
float grid_width, bool release_object,
float aspectRatio, int flags, Mat& cameraMatrix,
Mat& distCoeffs, bool writeExtrinsics, bool writePoints, bool writeGrid )
{
vector<Mat> rvecs, tvecs;
vector<float> reprojErrs;
double totalAvgErr = 0;
vector<Point3f> newObjPoints;
bool ok = runCalibration(imagePoints, imageSize, boardSize, patternType, squareSize,
aspectRatio, grid_width, release_object, flags, cameraMatrix, distCoeffs,
rvecs, tvecs, reprojErrs, newObjPoints, totalAvgErr);
printf("%s. avg reprojection error = %.7f\n",
ok ? "Calibration succeeded" : "Calibration failed",
totalAvgErr);
if( ok )
saveCameraParams( outputFilename, imageSize,
boardSize, squareSize, aspectRatio,
flags, cameraMatrix, distCoeffs,
writeExtrinsics ? rvecs : vector<Mat>(),
writeExtrinsics ? tvecs : vector<Mat>(),
writeExtrinsics ? reprojErrs : vector<float>(),
writePoints ? imagePoints : vector<vector<Point2f> >(),
writeGrid ? newObjPoints : vector<Point3f>(),
totalAvgErr );
return ok;
}
int main( int argc, char** argv )
{
Size boardSize, imageSize;
float squareSize, aspectRatio = 1;
Mat cameraMatrix, distCoeffs;
string outputFilename;
string inputFilename = "";
int i, nframes;
bool writeExtrinsics, writePoints;
bool undistortImage = false;
int flags = 0;
VideoCapture capture;
bool flipVertical;
bool showUndistorted;
bool videofile;
int delay;
clock_t prevTimestamp = 0;
int mode = DETECTION;
int cameraId = 0;
vector<vector<Point2f> > imagePoints;
vector<string> imageList;
Pattern pattern = CHESSBOARD;
cv::CommandLineParser parser(argc, argv,
"{help ||}{w||}{h||}{pt|chessboard|}{n|10|}{d|1000|}{s|1|}{o|out_camera_data.yml|}"
"{op||}{oe||}{zt||}{a||}{p||}{v||}{V||}{su||}"
"{oo||}{ws|11|}{dt||}"
"{@input_data|0|}");
if (parser.has("help"))
{
help(argv);
return 0;
}
boardSize.width = parser.get<int>( "w" );
boardSize.height = parser.get<int>( "h" );
if ( parser.has("pt") )
{
string val = parser.get<string>("pt");
if( val == "circles" )
pattern = CIRCLES_GRID;
else if( val == "acircles" )
pattern = ASYMMETRIC_CIRCLES_GRID;
else if( val == "chessboard" )
pattern = CHESSBOARD;
else
return fprintf( stderr, "Invalid pattern type: must be chessboard or circles\n" ), -1;
}
squareSize = parser.get<float>("s");
nframes = parser.get<int>("n");
delay = parser.get<int>("d");
writePoints = parser.has("op");
writeExtrinsics = parser.has("oe");
bool writeGrid = parser.has("oo");
if (parser.has("a")) {
flags |= CALIB_FIX_ASPECT_RATIO;
aspectRatio = parser.get<float>("a");
}
if ( parser.has("zt") )
flags |= CALIB_ZERO_TANGENT_DIST;
if ( parser.has("p") )
flags |= CALIB_FIX_PRINCIPAL_POINT;
flipVertical = parser.has("v");
videofile = parser.has("V");
if ( parser.has("o") )
outputFilename = parser.get<string>("o");
showUndistorted = parser.has("su");
if ( isdigit(parser.get<string>("@input_data")[0]) )
cameraId = parser.get<int>("@input_data");
else
inputFilename = parser.get<string>("@input_data");
int winSize = parser.get<int>("ws");
float grid_width = squareSize * (boardSize.width - 1);
bool release_object = false;
if (parser.has("dt")) {
grid_width = parser.get<float>("dt");
release_object = true;
}
if (!parser.check())
{
help(argv);
parser.printErrors();
return -1;
}
if ( squareSize <= 0 )
return fprintf( stderr, "Invalid board square width\n" ), -1;
if ( nframes <= 3 )
return printf("Invalid number of images\n" ), -1;
if ( aspectRatio <= 0 )
return printf( "Invalid aspect ratio\n" ), -1;
if ( delay <= 0 )
return printf( "Invalid delay\n" ), -1;
if ( boardSize.width <= 0 )
return fprintf( stderr, "Invalid board width\n" ), -1;
if ( boardSize.height <= 0 )
return fprintf( stderr, "Invalid board height\n" ), -1;
if( !inputFilename.empty() )
{
if( !videofile && readStringList(samples::findFile(inputFilename), imageList) )
mode = CAPTURING;
else
capture.open(samples::findFileOrKeep(inputFilename));
}
else
capture.open(cameraId);
if( !capture.isOpened() && imageList.empty() )
return fprintf( stderr, "Could not initialize video (%d) capture\n",cameraId ), -2;
if( !imageList.empty() )
nframes = (int)imageList.size();
if( capture.isOpened() )
printf( "%s", liveCaptureHelp );
namedWindow( "Image View", 1 );
for(i = 0;;i++)
{
Mat view, viewGray;
bool blink = false;
if( capture.isOpened() )
{
Mat view0;
capture >> view0;
view0.copyTo(view);
}
else if( i < (int)imageList.size() )
view = imread(imageList[i], 1);
if(view.empty())
{
if( imagePoints.size() > 0 )
runAndSave(outputFilename, imagePoints, imageSize,
boardSize, pattern, squareSize, grid_width, release_object, aspectRatio,
flags, cameraMatrix, distCoeffs,
writeExtrinsics, writePoints, writeGrid);
break;
}
imageSize = view.size();
if( flipVertical )
flip( view, view, 0 );
vector<Point2f> pointbuf;
cvtColor(view, viewGray, COLOR_BGR2GRAY);
bool found;
switch( pattern )
{
case CHESSBOARD:
found = findChessboardCorners( view, boardSize, pointbuf,
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE);
break;
case CIRCLES_GRID:
found = findCirclesGrid( view, boardSize, pointbuf );
break;
case ASYMMETRIC_CIRCLES_GRID:
found = findCirclesGrid( view, boardSize, pointbuf, CALIB_CB_ASYMMETRIC_GRID );
break;
default:
return fprintf( stderr, "Unknown pattern type\n" ), -1;
}
// improve the found corners' coordinate accuracy
if( pattern == CHESSBOARD && found) cornerSubPix( viewGray, pointbuf, Size(winSize,winSize),
Size(-1,-1), TermCriteria( TermCriteria::EPS+TermCriteria::COUNT, 30, 0.0001 ));
if( mode == CAPTURING && found &&
(!capture.isOpened() || clock() - prevTimestamp > delay*1e-3*CLOCKS_PER_SEC) )
{
imagePoints.push_back(pointbuf);
prevTimestamp = clock();
blink = capture.isOpened();
}
if(found)
drawChessboardCorners( view, boardSize, Mat(pointbuf), found );
string msg = mode == CAPTURING ? "100/100" :
mode == CALIBRATED ? "Calibrated" : "Press 'g' to start";
int baseLine = 0;
Size textSize = getTextSize(msg, 1, 1, 1, &baseLine);
Point textOrigin(view.cols - 2*textSize.width - 10, view.rows - 2*baseLine - 10);
if( mode == CAPTURING )
{
if(undistortImage)
msg = cv::format( "%d/%d Undist", (int)imagePoints.size(), nframes );
else
msg = cv::format( "%d/%d", (int)imagePoints.size(), nframes );
}
putText( view, msg, textOrigin, 1, 1,
mode != CALIBRATED ? Scalar(0,0,255) : Scalar(0,255,0));
if( blink )
bitwise_not(view, view);
if( mode == CALIBRATED && undistortImage )
{
Mat temp = view.clone();
undistort(temp, view, cameraMatrix, distCoeffs);
}
imshow("Image View", view);
char key = (char)waitKey(capture.isOpened() ? 50 : 500);
if( key == 27 )
break;
if( key == 'u' && mode == CALIBRATED )
undistortImage = !undistortImage;
if( capture.isOpened() && key == 'g' )
{
mode = CAPTURING;
imagePoints.clear();
}
if( mode == CAPTURING && imagePoints.size() >= (unsigned)nframes )
{
if( runAndSave(outputFilename, imagePoints, imageSize,
boardSize, pattern, squareSize, grid_width, release_object, aspectRatio,
flags, cameraMatrix, distCoeffs,
writeExtrinsics, writePoints, writeGrid))
mode = CALIBRATED;
else
mode = DETECTION;
if( !capture.isOpened() )
break;
}
}
if( !capture.isOpened() && showUndistorted )
{
Mat view, rview, map1, map2;
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0),
imageSize, CV_16SC2, map1, map2);
for( i = 0; i < (int)imageList.size(); i++ )
{
view = imread(imageList[i], 1);
if(view.empty())
continue;
//undistort( view, rview, cameraMatrix, distCoeffs, cameraMatrix );
remap(view, rview, map1, map2, INTER_LINEAR);
imshow("Image View", rview);
char c = (char)waitKey();
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
return 0;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -0,0 +1,550 @@
/*
* cloning.cpp
*
* Author:
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
*
* This tutorial demonstrates how to use OpenCV seamless cloning
* module.
*
* 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.
* Step 1:
* -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button.
* -> To set the Polygon ROI, click the right mouse button or 'd' key.
* -> To reset the region selected, click the middle mouse button or 'r' key.
* Step 2:
* -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button.
* -> To get the cloned result, click the right mouse button or 'c' key.
* -> To quit the program, use 'q' key.
*
* Result: The cloned image will be displayed.
*/
#include "opencv2/photo.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include <iostream>
// we're NOT "using namespace std;" here, to avoid collisions between the beta variable and std::beta in c++17
using std::cin;
using std::cout;
using std::endl;
using std::string;
using namespace cv;
Mat img0, img1, img2, res, res1, final, final1, blend;
Point point;
int drag = 0;
int destx, desty;
int numpts = 100;
Point* pts = new Point[100];
Point* pts2 = new Point[100];
Point* pts_diff = new Point[100];
int var = 0;
int flag = 0, flag1 = 0, flag4 = 0;
int minx, miny, maxx, maxy, lenx, leny;
int minxd, minyd, maxxd, maxyd, lenxd, lenyd;
int channel, num, kernel_size;
float alpha,beta;
float red, green, blue;
float low_t, high_t;
void source(int, int, int, int, void*);
void destination(int, int, int, int, void*);
void checkfile(char*);
void source(int event, int x, int y, int, void*)
{
if (event == EVENT_LBUTTONDOWN && !drag)
{
if(flag1 == 0)
{
if(var==0)
img1 = img0.clone();
point = Point(x, y);
circle(img1,point,2,Scalar(0, 0, 255),-1, 8, 0);
pts[var] = 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)
{
flag1 = 1;
img1 = img0.clone();
for(int i = var; i < numpts ; i++)
pts[i] = point;
if(var!=0)
{
const Point* pts3[1] = {&pts[0]};
polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0);
}
for(int i=0;i<var;i++)
{
minx = min(minx,pts[i].x);
maxx = max(maxx,pts[i].x);
miny = min(miny,pts[i].y);
maxy = max(maxy,pts[i].y);
}
lenx = maxx - minx;
leny = maxy - miny;
int mid_pointx = minx + lenx/2;
int mid_pointy = miny + leny/2;
for(int i=0;i<var;i++)
{
pts_diff[i].x = pts[i].x - mid_pointx;
pts_diff[i].y = pts[i].y - mid_pointy;
}
imshow("Source", img1);
}
if (event == EVENT_RBUTTONUP)
{
flag = var;
final = Mat::zeros(img0.size(),CV_8UC3);
res1 = Mat::zeros(img0.size(),CV_8UC1);
const Point* pts4[1] = {&pts[0]};
fillPoly(res1, pts4,&numpts, 1, Scalar(255, 255, 255), 8, 0);
bitwise_and(img0, img0, final,res1);
imshow("Source", img1);
if(num == 4)
{
colorChange(img0,res1,blend,red,green,blue);
imshow("Color Change Image", blend);
waitKey(0);
}
else if(num == 5)
{
illuminationChange(img0,res1,blend,alpha,beta);
imshow("Illum Change Image", blend);
waitKey(0);
}
else if(num == 6)
{
textureFlattening(img0,res1,blend,low_t,high_t,kernel_size);
imshow("Texture Flattened", blend);
waitKey(0);
}
}
if (event == EVENT_MBUTTONDOWN)
{
for(int i = 0; i < numpts ; i++)
{
pts[i].x=0;
pts[i].y=0;
}
var = 0;
flag1 = 0;
minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
imshow("Source", img0);
if(num == 1 || num == 2 || num == 3)
imshow("Destination",img2);
drag = 0;
}
}
void destination(int event, int x, int y, int, void*)
{
Mat im1;
minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
im1 = img2.clone();
if (event == EVENT_LBUTTONDOWN)
{
flag4 = 1;
if(flag1 == 1)
{
point = Point(x, y);
for(int i=0;i<var;i++)
{
pts2[i].x = point.x + pts_diff[i].x;
pts2[i].y = point.y + pts_diff[i].y;
}
for(int i=var;i<numpts;i++)
{
pts2[i].x = point.x + pts_diff[0].x;
pts2[i].y = point.y + pts_diff[0].y;
}
const Point* pts5[1] = {&pts2[0]};
polylines( im1, pts5, &numpts,1, 1, Scalar(0,0,255), 2, 8, 0);
destx = x;
desty = y;
imshow("Destination", im1);
}
}
if (event == EVENT_RBUTTONUP)
{
for(int i=0;i<flag;i++)
{
minxd = min(minxd,pts2[i].x);
maxxd = max(maxxd,pts2[i].x);
minyd = min(minyd,pts2[i].y);
maxyd = max(maxyd,pts2[i].y);
}
if(maxxd > im1.size().width || maxyd > im1.size().height || minxd < 0 || minyd < 0)
{
cout << "Index out of range" << endl;
exit(1);
}
final1 = Mat::zeros(img2.size(),CV_8UC3);
res = Mat::zeros(img2.size(),CV_8UC1);
for(int i=miny, k=minyd;i<(miny+leny);i++,k++)
for(int j=minx,l=minxd ;j<(minx+lenx);j++,l++)
{
for(int c=0;c<channel;c++)
{
final1.at<uchar>(k,l*channel+c) = final.at<uchar>(i,j*channel+c);
}
}
const Point* pts6[1] = {&pts2[0]};
fillPoly(res, pts6, &numpts, 1, Scalar(255, 255, 255), 8, 0);
if(num == 1 || num == 2 || num == 3)
{
seamlessClone(img0,img2,res1,point,blend,num);
imshow("Cloned Image", blend);
imwrite("cloned.png",blend);
waitKey(0);
}
for(int i = 0; i < flag ; i++)
{
pts2[i].x=0;
pts2[i].y=0;
}
minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
}
im1.release();
}
int main()
{
cout << endl;
cout << "Cloning Module" << endl;
cout << "---------------" << endl;
cout << "Step 1:" << endl;
cout << " -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button." << endl;
cout << " -> To set the Polygon ROI, click the right mouse button or use 'd' key" << endl;
cout << " -> To reset the region selected, click the middle mouse button or use 'r' key." << endl;
cout << "Step 2:" << endl;
cout << " -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button." << endl;
cout << " -> To get the cloned result, click the right mouse button or use 'c' key." << endl;
cout << " -> To quit the program, use 'q' key." << 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: ";
cin >> num;
cout << endl;
minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
int flag3 = 0;
if(num == 1 || num == 2 || num == 3)
{
string src,dest;
cout << "Enter Source Image: ";
cin >> src;
cout << "Enter Destination Image: ";
cin >> dest;
img0 = imread(samples::findFile(src));
img2 = imread(samples::findFile(dest));
if(img0.empty())
{
cout << "Source Image does not exist" << endl;
exit(2);
}
if(img2.empty())
{
cout << "Destination Image does not exist" << endl;
exit(2);
}
channel = img0.channels();
res = Mat::zeros(img2.size(),CV_8UC1);
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
final1 = Mat::zeros(img2.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
/////////// destination image ///////////////
namedWindow("Destination", 1);
setMouseCallback("Destination", destination, NULL);
imshow("Destination",img2);
}
else if(num == 4)
{
string src;
cout << "Enter Source Image: ";
cin >> src;
cout << "Enter RGB values: " << endl;
cout << "Red: ";
cin >> red;
cout << "Green: ";
cin >> green;
cout << "Blue: ";
cin >> blue;
img0 = imread(samples::findFile(src));
if(img0.empty())
{
cout << "Source Image does not exist" << endl;
exit(2);
}
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
}
else if(num == 5)
{
string src;
cout << "Enter Source Image: ";
cin >> src;
cout << "alpha: ";
cin >> alpha;
cout << "beta: ";
cin >> beta;
img0 = imread(samples::findFile(src));
if(img0.empty())
{
cout << "Source Image does not exist" << endl;
exit(2);
}
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
}
else if(num == 6)
{
string src;
cout << "Enter Source Image: ";
cin >> src;
cout << "low_threshold: ";
cin >> low_t;
cout << "high_threshold: ";
cin >> high_t;
cout << "kernel_size: ";
cin >> kernel_size;
img0 = imread(samples::findFile(src));
if(img0.empty())
{
cout << "Source Image does not exist" << endl;
exit(2);
}
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
}
else
{
cout << "Wrong Option Chosen" << endl;
exit(1);
}
for(;;)
{
char key = (char)waitKey(0);
if(key == 'd' && flag3 == 0)
{
flag1 = 1;
flag3 = 1;
img1 = img0.clone();
for(int i = var; i < numpts ; i++)
pts[i] = point;
if(var!=0)
{
const Point* pts3[1] = {&pts[0]};
polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0);
}
for(int i=0;i<var;i++)
{
minx = min(minx,pts[i].x);
maxx = max(maxx,pts[i].x);
miny = min(miny,pts[i].y);
maxy = max(maxy,pts[i].y);
}
lenx = maxx - minx;
leny = maxy - miny;
int mid_pointx = minx + lenx/2;
int mid_pointy = miny + leny/2;
for(int i=0;i<var;i++)
{
pts_diff[i].x = pts[i].x - mid_pointx;
pts_diff[i].y = pts[i].y - mid_pointy;
}
flag = var;
final = Mat::zeros(img0.size(),CV_8UC3);
res1 = Mat::zeros(img0.size(),CV_8UC1);
const Point* pts4[1] = {&pts[0]};
fillPoly(res1, pts4,&numpts, 1, Scalar(255, 255, 255), 8, 0);
bitwise_and(img0, img0, final,res1);
imshow("Source", img1);
}
else if(key == 'r')
{
for(int i = 0; i < numpts ; i++)
{
pts[i].x=0;
pts[i].y=0;
}
var = 0;
flag1 = 0;
flag3 = 0;
flag4 = 0;
minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
imshow("Source", img0);
if(num == 1 || num == 2 || num == 3)
imshow("Destination",img2);
drag = 0;
}
else if ((num == 1 || num == 2 || num == 3) && key == 'c' && flag1 == 1 && flag4 == 1)
{
seamlessClone(img0,img2,res1,point,blend,num);
imshow("Cloned Image", blend);
imwrite("cloned.png",blend);
}
else if (num == 4 && key == 'c' && flag1 == 1)
{
colorChange(img0,res1,blend,red,green,blue);
imshow("Color Change Image", blend);
imwrite("cloned.png",blend);
}
else if (num == 5 && key == 'c' && flag1 == 1)
{
illuminationChange(img0,res1,blend,alpha,beta);
imshow("Illum Change Image", blend);
imwrite("cloned.png",blend);
}
else if (num == 6 && key == 'c' && flag1 == 1)
{
textureFlattening(img0,res1,blend,low_t,high_t,kernel_size);
imshow("Texture Flattened", blend);
imwrite("cloned.png",blend);
}
else if(key == 'q')
break;
}
return 0;
}

View File

@ -0,0 +1,61 @@
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat img;
int threshval = 100;
static void on_trackbar(int, void*)
{
Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);
Mat labelImage(img.size(), CV_32S);
int nLabels = connectedComponents(bw, labelImage, 8);
std::vector<Vec3b> colors(nLabels);
colors[0] = Vec3b(0, 0, 0);//background
for(int label = 1; label < nLabels; ++label){
colors[label] = Vec3b( (rand()&255), (rand()&255), (rand()&255) );
}
Mat dst(img.size(), CV_8UC3);
for(int r = 0; r < dst.rows; ++r){
for(int c = 0; c < dst.cols; ++c){
int label = labelImage.at<int>(r, c);
Vec3b &pixel = dst.at<Vec3b>(r, c);
pixel = colors[label];
}
}
imshow( "Connected Components", dst );
}
int main( int argc, const char** argv )
{
CommandLineParser parser(argc, argv, "{@image|stuff.jpg|image for converting to a grayscale}");
parser.about("\nThis program demonstrates connected components and use of the trackbar\n");
parser.printMessage();
cout << "\nThe image is converted to grayscale and displayed, another image has a trackbar\n"
"that controls thresholding and thereby the extracted contours which are drawn in color\n";
String inputImage = parser.get<string>(0);
img = imread(samples::findFile(inputImage), IMREAD_GRAYSCALE);
if(img.empty())
{
cout << "Could not read input image file: " << inputImage << endl;
return EXIT_FAILURE;
}
imshow( "Image", img );
namedWindow( "Connected Components", WINDOW_AUTOSIZE);
createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );
on_trackbar(threshval, 0);
waitKey(0);
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,96 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <math.h>
#include <iostream>
using namespace cv;
using namespace std;
static void help(char** argv)
{
cout
<< "\nThis program illustrates the use of findContours and drawContours\n"
<< "The original image is put up along with the image of drawn contours\n"
<< "Usage:\n";
cout
<< argv[0]
<< "\nA trackbar is put up which controls the contour level from -3 to 3\n"
<< endl;
}
const int w = 500;
int levels = 3;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
static void on_trackbar(int, void*)
{
Mat cnt_img = Mat::zeros(w, w, CV_8UC3);
int _levels = levels - 3;
drawContours( cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128,255,255),
3, LINE_AA, hierarchy, std::abs(_levels) );
imshow("contours", cnt_img);
}
int main( int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv, "{help h||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
Mat img = Mat::zeros(w, w, CV_8UC1);
//Draw 6 faces
for( int i = 0; i < 6; i++ )
{
int dx = (i%2)*250 - 30;
int dy = (i/2)*150;
const Scalar white = Scalar(255);
const Scalar black = Scalar(0);
if( i == 0 )
{
for( int j = 0; j <= 10; j++ )
{
double angle = (j+5)*CV_PI/21;
line(img, Point(cvRound(dx+100+j*10-80*cos(angle)),
cvRound(dy+100-90*sin(angle))),
Point(cvRound(dx+100+j*10-30*cos(angle)),
cvRound(dy+100-30*sin(angle))), white, 1, 8, 0);
}
}
ellipse( img, Point(dx+150, dy+100), Size(100,70), 0, 0, 360, white, -1, 8, 0 );
ellipse( img, Point(dx+115, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 );
ellipse( img, Point(dx+185, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 );
ellipse( img, Point(dx+115, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 );
ellipse( img, Point(dx+185, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 );
ellipse( img, Point(dx+115, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 );
ellipse( img, Point(dx+185, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 );
ellipse( img, Point(dx+150, dy+100), Size(10,5), 0, 0, 360, black, -1, 8, 0 );
ellipse( img, Point(dx+150, dy+150), Size(40,10), 0, 0, 360, black, -1, 8, 0 );
ellipse( img, Point(dx+27, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 );
ellipse( img, Point(dx+273, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 );
}
//show the faces
namedWindow( "image", 1 );
imshow( "image", img );
//Extract the contours so that
vector<vector<Point> > contours0;
findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
contours.resize(contours0.size());
for( size_t k = 0; k < contours0.size(); k++ )
approxPolyDP(Mat(contours0[k]), contours[k], 3, true);
namedWindow( "contours", 1 );
createTrackbar( "levels+3", "contours", &levels, 7, on_trackbar );
on_trackbar(0,0);
waitKey();
return 0;
}

View File

@ -0,0 +1,57 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help(char** argv)
{
cout << "\nThis sample program demonstrates the use of the convexHull() function\n"
<< "Call:\n"
<< argv[0] << endl;
}
int main( int argc, char** argv )
{
CommandLineParser parser(argc, argv, "{help h||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
Mat img(500, 500, CV_8UC3);
RNG& rng = theRNG();
for(;;)
{
int i, count = (unsigned)rng%100 + 1;
vector<Point> points;
for( i = 0; i < count; i++ )
{
Point pt;
pt.x = rng.uniform(img.cols/4, img.cols*3/4);
pt.y = rng.uniform(img.rows/4, img.rows*3/4);
points.push_back(pt);
}
vector<Point> hull;
convexHull(points, hull, true);
img = Scalar::all(0);
for( i = 0; i < count; i++ )
circle(img, points[i], 3, Scalar(0, 0, 255), FILLED, LINE_AA);
polylines(img, hull, true, Scalar(0, 255, 0), 1, LINE_AA);
imshow("hull", img);
char key = (char)waitKey();
if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
break;
}
return 0;
}

View File

@ -0,0 +1,69 @@
/*
*
* cvout_sample just demonstrates the serial out capabilities of cv::Mat
* That is, cv::Mat M(...); cout << M; Now works.
*
*/
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(char** argv)
{
cout
<< "\n------------------------------------------------------------------\n"
<< " This program shows the serial out capabilities of cv::Mat\n"
<< "That is, cv::Mat M(...); cout << M; Now works.\n"
<< "Output can be formatted to OpenCV, matlab, python, numpy, csv and \n"
<< "C styles Usage:\n"
<< argv[0]
<< "\n------------------------------------------------------------------\n\n"
<< endl;
}
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv, "{help h||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
Mat I = Mat::eye(4, 4, CV_64F);
I.at<double>(1,1) = CV_PI;
cout << "I = \n" << I << ";" << endl << endl;
Mat r = Mat(10, 3, CV_8UC3);
randu(r, Scalar::all(0), Scalar::all(255));
cout << "r (default) = \n" << r << ";" << endl << endl;
cout << "r (matlab) = \n" << format(r, Formatter::FMT_MATLAB) << ";" << endl << endl;
cout << "r (python) = \n" << format(r, Formatter::FMT_PYTHON) << ";" << endl << endl;
cout << "r (numpy) = \n" << format(r, Formatter::FMT_NUMPY) << ";" << endl << endl;
cout << "r (csv) = \n" << format(r, Formatter::FMT_CSV) << ";" << endl << endl;
cout << "r (c) = \n" << format(r, Formatter::FMT_C) << ";" << endl << endl;
Point2f p(5, 1);
cout << "p = " << p << ";" << endl;
Point3f p3f(2, 6, 7);
cout << "p3f = " << p3f << ";" << endl;
vector<float> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "shortvec = " << Mat(v) << endl;
vector<Point2f> points(20);
for (size_t i = 0; i < points.size(); ++i)
points[i] = Point2f((float)(i * 5), (float)(i % 7));
cout << "points = " << points << ";" << endl;
return 0;
}

View File

@ -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;
}

View File

@ -0,0 +1,111 @@
#if defined(__linux__) || defined(LINUX) || defined(__APPLE__) || defined(ANDROID) || (defined(_MSC_VER) && _MSC_VER>=1800)
#include <opencv2/imgproc.hpp> // Gaussian Blur
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat, Scalar)
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp> // OpenCV window I/O
#include <opencv2/features2d.hpp>
#include <opencv2/objdetect.hpp>
#include <stdio.h>
using namespace std;
using namespace cv;
const string WindowName = "Face Detection example";
class CascadeDetectorAdapter: public DetectionBasedTracker::IDetector
{
public:
CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector):
IDetector(),
Detector(detector)
{
CV_Assert(detector);
}
void detect(const cv::Mat &Image, std::vector<cv::Rect> &objects) CV_OVERRIDE
{
Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);
}
virtual ~CascadeDetectorAdapter() CV_OVERRIDE
{}
private:
CascadeDetectorAdapter();
cv::Ptr<cv::CascadeClassifier> Detector;
};
int main(int , char** )
{
namedWindow(WindowName);
VideoCapture VideoStream(0);
if (!VideoStream.isOpened())
{
printf("Error: Cannot open video stream from camera\n");
return 1;
}
std::string cascadeFrontalfilename = samples::findFile("data/lbpcascades/lbpcascade_frontalface.xml");
cv::Ptr<cv::CascadeClassifier> cascade = makePtr<cv::CascadeClassifier>(cascadeFrontalfilename);
cv::Ptr<DetectionBasedTracker::IDetector> MainDetector = makePtr<CascadeDetectorAdapter>(cascade);
if ( cascade->empty() )
{
printf("Error: Cannot load %s\n", cascadeFrontalfilename.c_str());
return 2;
}
cascade = makePtr<cv::CascadeClassifier>(cascadeFrontalfilename);
cv::Ptr<DetectionBasedTracker::IDetector> TrackingDetector = makePtr<CascadeDetectorAdapter>(cascade);
if ( cascade->empty() )
{
printf("Error: Cannot load %s\n", cascadeFrontalfilename.c_str());
return 2;
}
DetectionBasedTracker::Parameters params;
DetectionBasedTracker Detector(MainDetector, TrackingDetector, params);
if (!Detector.run())
{
printf("Error: Detector initialization failed\n");
return 2;
}
Mat ReferenceFrame;
Mat GrayFrame;
vector<Rect> Faces;
do
{
VideoStream >> ReferenceFrame;
cvtColor(ReferenceFrame, GrayFrame, COLOR_BGR2GRAY);
Detector.process(GrayFrame);
Detector.getObjects(Faces);
for (size_t i = 0; i < Faces.size(); i++)
{
rectangle(ReferenceFrame, Faces[i], Scalar(0,255,0));
}
imshow(WindowName, ReferenceFrame);
} while (waitKey(30) < 0);
Detector.stop();
return 0;
}
#else
#include <stdio.h>
int main()
{
printf("This sample works for UNIX or ANDROID or Visual Studio 2013+ only\n");
return 0;
}
#endif

View File

@ -0,0 +1,153 @@
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
static void help(char** argv)
{
cout << "\nThis program demonstrates iterative construction of\n"
"delaunay triangulation and voronoi tessellation.\n"
"It draws a random set of points in an image and then delaunay triangulates them.\n"
"Usage: \n";
cout << argv[0];
cout << "\n\nThis program builds the triangulation interactively, you may stop this process by\n"
"hitting any key.\n";
}
static void draw_subdiv_point( Mat& img, Point2f fp, Scalar color )
{
circle( img, fp, 3, color, FILLED, LINE_8, 0 );
}
static void draw_subdiv( Mat& img, Subdiv2D& subdiv, Scalar delaunay_color )
{
#if 1
vector<Vec6f> triangleList;
subdiv.getTriangleList(triangleList);
vector<Point> pt(3);
for( size_t i = 0; i < triangleList.size(); i++ )
{
Vec6f t = triangleList[i];
pt[0] = Point(cvRound(t[0]), cvRound(t[1]));
pt[1] = Point(cvRound(t[2]), cvRound(t[3]));
pt[2] = Point(cvRound(t[4]), cvRound(t[5]));
line(img, pt[0], pt[1], delaunay_color, 1, LINE_AA, 0);
line(img, pt[1], pt[2], delaunay_color, 1, LINE_AA, 0);
line(img, pt[2], pt[0], delaunay_color, 1, LINE_AA, 0);
}
#else
vector<Vec4f> edgeList;
subdiv.getEdgeList(edgeList);
for( size_t i = 0; i < edgeList.size(); i++ )
{
Vec4f e = edgeList[i];
Point pt0 = Point(cvRound(e[0]), cvRound(e[1]));
Point pt1 = Point(cvRound(e[2]), cvRound(e[3]));
line(img, pt0, pt1, delaunay_color, 1, LINE_AA, 0);
}
#endif
}
static void locate_point( Mat& img, Subdiv2D& subdiv, Point2f fp, Scalar active_color )
{
int e0=0, vertex=0;
subdiv.locate(fp, e0, vertex);
if( e0 > 0 )
{
int e = e0;
do
{
Point2f org, dst;
if( subdiv.edgeOrg(e, &org) > 0 && subdiv.edgeDst(e, &dst) > 0 )
line( img, org, dst, active_color, 3, LINE_AA, 0 );
e = subdiv.getEdge(e, Subdiv2D::NEXT_AROUND_LEFT);
}
while( e != e0 );
}
draw_subdiv_point( img, fp, active_color );
}
static void paint_voronoi( Mat& img, Subdiv2D& subdiv )
{
vector<vector<Point2f> > facets;
vector<Point2f> centers;
subdiv.getVoronoiFacetList(vector<int>(), facets, centers);
vector<Point> ifacet;
vector<vector<Point> > ifacets(1);
for( size_t i = 0; i < facets.size(); i++ )
{
ifacet.resize(facets[i].size());
for( size_t j = 0; j < facets[i].size(); j++ )
ifacet[j] = facets[i][j];
Scalar color;
color[0] = rand() & 255;
color[1] = rand() & 255;
color[2] = rand() & 255;
fillConvexPoly(img, ifacet, color, 8, 0);
ifacets[0] = ifacet;
polylines(img, ifacets, true, Scalar(), 1, LINE_AA, 0);
circle(img, centers[i], 3, Scalar(), FILLED, LINE_AA, 0);
}
}
int main( int argc, char** argv )
{
cv::CommandLineParser parser(argc, argv, "{help h||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
Scalar active_facet_color(0, 0, 255), delaunay_color(255,255,255);
Rect rect(0, 0, 600, 600);
Subdiv2D subdiv(rect);
Mat img(rect.size(), CV_8UC3);
img = Scalar::all(0);
string win = "Delaunay Demo";
imshow(win, img);
for( int i = 0; i < 200; i++ )
{
Point2f fp( (float)(rand()%(rect.width-10)+5),
(float)(rand()%(rect.height-10)+5));
locate_point( img, subdiv, fp, active_facet_color );
imshow( win, img );
if( waitKey( 100 ) >= 0 )
break;
subdiv.insert(fp);
img = Scalar::all(0);
draw_subdiv( img, subdiv, delaunay_color );
imshow( win, img );
if( waitKey( 100 ) >= 0 )
break;
}
img = Scalar::all(0);
paint_voronoi( img, subdiv );
imshow( win, img );
waitKey(0);
return 0;
}

View File

@ -0,0 +1,94 @@
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int _brightness = 100;
int _contrast = 100;
Mat image;
/* brightness/contrast callback function */
static void updateBrightnessContrast( int /*arg*/, void* )
{
int histSize = 64;
int brightness = _brightness - 100;
int contrast = _contrast - 100;
/*
* The algorithm is by Werner D. Streidt
* (http://visca.com/ffactory/archives/5-99/msg00021.html)
*/
double a, b;
if( contrast > 0 )
{
double delta = 127.*contrast/100;
a = 255./(255. - delta*2);
b = a*(brightness - delta);
}
else
{
double delta = -128.*contrast/100;
a = (256.-delta*2)/255.;
b = a*brightness + delta;
}
Mat dst, hist;
image.convertTo(dst, CV_8U, a, b);
imshow("image", dst);
calcHist(&dst, 1, 0, Mat(), hist, 1, &histSize, 0);
Mat histImage = Mat::ones(200, 320, CV_8U)*255;
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, CV_32F);
histImage = Scalar::all(255);
int binW = cvRound((double)histImage.cols/histSize);
for( int i = 0; i < histSize; i++ )
rectangle( histImage, Point(i*binW, histImage.rows),
Point((i+1)*binW, histImage.rows - cvRound(hist.at<float>(i))),
Scalar::all(0), -1, 8, 0 );
imshow("histogram", histImage);
}
const char* keys =
{
"{help h||}{@image|baboon.jpg|input image file}"
};
int main( int argc, const char** argv )
{
CommandLineParser parser(argc, argv, keys);
parser.about("\nThis program demonstrates the use of calcHist() -- histogram creation.\n");
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
string inputImage = parser.get<string>(0);
// Load the source image. HighGUI use.
image = imread(samples::findFile(inputImage), IMREAD_GRAYSCALE);
if(image.empty())
{
std::cerr << "Cannot read image file: " << inputImage << std::endl;
return -1;
}
namedWindow("image", 0);
namedWindow("histogram", 0);
createTrackbar("brightness", "image", &_brightness, 200, updateBrightnessContrast);
createTrackbar("contrast", "image", &_contrast, 200, updateBrightnessContrast);
updateBrightnessContrast(0, 0);
waitKey();
return 0;
}

View File

@ -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/master/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;
}

View File

@ -0,0 +1,537 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features2d.hpp>
#include "opencv2/core/opengl.hpp"
#include <vector>
#include <map>
#include <iostream>
#include <iomanip>
#include <limits>
#include <stdint.h>
#ifdef HAVE_OPENGL
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN 1
#define NOMINMAX 1
#include <windows.h>
#endif
#if defined(_WIN64)
#include <windows.h>
#endif
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif
#endif
using namespace std;
using namespace cv;
static void help(char** argv)
{
cout << "\nThis program demonstrates how to use MSER to detect extremal regions\n"
"Usage:\n"
<< argv[0] << " <image1(without parameter a synthetic image is used as default)>\n"
"Press esc key when image window is active to change descriptor parameter\n"
"Press 2, 8, 4, 6, +, -, or 5 keys in openGL windows to change view or use mouse\n";
}
struct MSERParams
{
MSERParams(int _delta = 5, int _min_area = 60, int _max_area = 14400,
double _max_variation = 0.25, double _min_diversity = .2,
int _max_evolution = 200, double _area_threshold = 1.01,
double _min_margin = 0.003, int _edge_blur_size = 5)
{
delta = _delta;
minArea = _min_area;
maxArea = _max_area;
maxVariation = _max_variation;
minDiversity = _min_diversity;
maxEvolution = _max_evolution;
areaThreshold = _area_threshold;
minMargin = _min_margin;
edgeBlurSize = _edge_blur_size;
pass2Only = false;
}
int delta;
int minArea;
int maxArea;
double maxVariation;
double minDiversity;
bool pass2Only;
int maxEvolution;
double areaThreshold;
double minMargin;
int edgeBlurSize;
};
static String Legende(const MSERParams &pAct)
{
ostringstream ss;
ss << "Area[" << pAct.minArea << "," << pAct.maxArea << "] ";
ss << "del. [" << pAct.delta << "] ";
ss << "var. [" << pAct.maxVariation << "] ";
ss << "div. [" << (int)pAct.minDiversity << "] ";
ss << "pas. [" << (int)pAct.pass2Only << "] ";
ss << "RGb->evo. [" << pAct.maxEvolution << "] ";
ss << "are. [" << (int)pAct.areaThreshold << "] ";
ss << "mar. [" << (int)pAct.minMargin << "] ";
ss << "siz. [" << pAct.edgeBlurSize << "]";
return ss.str();
}
#ifdef HAVE_OPENGL
const int win_width = 800;
const int win_height = 640;
#endif
bool rotateEnable=true;
bool keyPressed=false;
Vec4f rotAxis(1,0,1,0);
Vec3f zoom(1,0,0);
float obsX = 0.f;
float obsY = 0.f;
float obsZ = -10.f;
float tx = 0.f;
float ty = 0.f;
float thetaObs = -1.570f;
float phiObs = 1.570f;
float rObs = 10.f;
int prevX = -1;
int prevY = -1;
int prevTheta = -1000;
int prevPhi = -1000;
#ifdef HAVE_OPENGL
struct DrawData
{
ogl::Arrays arr;
ogl::Texture2D tex;
ogl::Buffer indices;
};
static void draw(void* userdata)
{
DrawData* data = static_cast<DrawData*>(userdata);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(obsX, obsY, obsZ, 0, 0, .0, .0, 10.0, 0.0);
glTranslatef(tx,ty,0);
keyPressed = false;
ogl::render(data->arr, data->indices, ogl::TRIANGLES);
}
static void onMouse(int event, int x, int y, int flags, void*)
{
if (event == EVENT_RBUTTONDOWN)
{
prevX = x;
prevY = y;
}
if (event == EVENT_RBUTTONUP)
{
prevX = -1;
prevY = -1;
}
if (prevX != -1)
{
tx += float((x - prevX) / 100.0);
ty -= float((y - prevY) / 100.0);
prevX = x;
prevY = y;
}
if (event == EVENT_LBUTTONDOWN)
{
prevTheta = x;
prevPhi = y;
}
if (event == EVENT_LBUTTONUP)
{
prevTheta = -1000;
prevPhi = -1000;
}
if (prevTheta != -1000)
{
if (x - prevTheta<0)
{
thetaObs += 0.02f;
}
else if (x - prevTheta>0)
{
thetaObs -= 0.02f;
}
if (y - prevPhi<0)
{
phiObs -= 0.02f;
}
else if (y - prevPhi>0)
{
phiObs += 0.02f;
}
prevTheta = x;
prevPhi = y;
}
if (event==EVENT_MOUSEWHEEL)
{
if (getMouseWheelDelta(flags)>0)
rObs += 0.1f;
else
rObs -= 0.1f;
}
float pi = static_cast<float>(CV_PI);
if (thetaObs>pi)
{
thetaObs = -2 * pi + thetaObs;
}
if (thetaObs<-pi)
{
thetaObs = 2 * pi + thetaObs;
}
if (phiObs>pi / 2)
{
phiObs = pi / 2 - 0.0001f;
}
if (phiObs<-pi / 2)
{
phiObs = -pi / 2 + 0.00001f;
}
if (rObs<0)
{
rObs = 0;
}
}
#endif
#ifdef HAVE_OPENGL
static void DrawOpenGLMSER(Mat img, Mat result)
{
Mat imgGray;
if (img.type() != CV_8UC1)
cvtColor(img, imgGray, COLOR_BGR2GRAY);
else
imgGray = img;
namedWindow("OpenGL", WINDOW_OPENGL);
setMouseCallback("OpenGL", onMouse, NULL);
Mat_<Vec3f> vertex(1, img.cols*img.rows);
Mat_<Vec2f> texCoords(1, img.cols*img.rows);
for (int i = 0, nbPix = 0; i<img.rows; i++)
{
for (int j = 0; j<img.cols; j++, nbPix++)
{
float x = (j) / (float)img.cols;
float y = (i) / (float)img.rows;
vertex.at< Vec3f >(0, nbPix) = Vec3f(float(2 * (x - 0.5)), float(2 * (0.5 - y)), float(imgGray.at<uchar>(i, j) / 512.0));
texCoords.at< Vec2f>(0, nbPix) = Vec2f(x, y);
}
}
Mat_<int> indices(1, (img.rows - 1)*(6 * img.cols));
for (int i = 1, nbPix = 0; i<img.rows; i++)
{
for (int j = 1; j<img.cols; j++)
{
int c = i*img.cols + j;
indices.at<int>(0, nbPix++) = c;
indices.at<int>(0, nbPix++) = c - 1;
indices.at<int>(0, nbPix++) = c - img.cols - 1;
indices.at<int>(0, nbPix++) = c - img.cols - 1;
indices.at<int>(0, nbPix++) = c - img.cols;
indices.at<int>(0, nbPix++) = c;
}
}
DrawData *data = new DrawData;
data->arr.setVertexArray(vertex);
data->arr.setTexCoordArray(texCoords);
data->indices.copyFrom(indices);
data->tex.copyFrom(result);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (double)win_width / win_height, 0.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
data->tex.bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glDisable(GL_CULL_FACE);
setOpenGlDrawCallback("OpenGL", draw, data);
for (;;)
{
updateWindow("OpenGL");
char key = (char)waitKey(40);
if (key == 27)
break;
if (key == 0x20)
rotateEnable = !rotateEnable;
float pi = static_cast<float>(CV_PI);
switch (key) {
case '5':
obsX = 0, obsY = 0, obsZ = -10;
thetaObs = -pi/2, phiObs = pi/2, rObs = 10;
tx=0; ty=0;
break;
case '4':
thetaObs += 0.1f;
break;
case '6':
thetaObs -= 0.1f;
break;
case '2':
phiObs -= 0.1f;
break;
case '8':
phiObs += 0.1f;
break;
case '+':
rObs -= 0.1f;
break;
case '-':
rObs += 0.1f;
break;
}
if (thetaObs>pi)
{
thetaObs = -2 * pi + thetaObs;
}
if (thetaObs<-pi)
thetaObs = 2 * pi + thetaObs;
if (phiObs>pi / 2)
phiObs = pi / 2 - 0.0001f;
if (phiObs<-pi / 2)
phiObs = -pi / 2 + 0.00001f;
if (rObs<0)
rObs = 0;
obsX = rObs*cos(thetaObs)*cos(phiObs);
obsY = rObs*sin(thetaObs)*cos(phiObs);
obsZ = rObs*sin(phiObs);
}
setOpenGlDrawCallback("OpenGL", 0, 0);
destroyAllWindows();
}
#endif
// Add nested rectangles of different widths and colors to an image
static void addNestedRectangles(Mat &img, Point p0, int* width, int *color, int n) {
for (int i = 0; i<n; i++)
{
rectangle(img, Rect(p0, Size(width[i], width[i])), Scalar(color[i]), 1);
p0 += Point((width[i] - width[i + 1]) / 2, (width[i] - width[i + 1]) / 2);
floodFill(img, p0, Scalar(color[i]));
}
}
// Add nested circles of different widths and colors to an image
static void addNestedCircles(Mat &img, Point p0, int *width, int *color, int n) {
for (int i = 0; i<n; i++)
{
circle(img, p0, width[i] / 2, Scalar(color[i]), 1);
floodFill(img, p0, Scalar(color[i]));
}
}
static Mat MakeSyntheticImage()
{
const int fond = 0;
Mat img(800, 800, CV_8UC1);
img = Scalar(fond);
int width[] = { 390, 380, 300, 290, 280, 270, 260, 250, 210, 190, 150, 100, 80, 70 };
int color1[] = { 80, 180, 160, 140, 120, 100, 90, 110, 170, 150, 140, 100, 220 };
int color2[] = { 81, 181, 161, 141, 121, 101, 91, 111, 171, 151, 141, 101, 221 };
int color3[] = { 175, 75, 95, 115, 135, 155, 165, 145, 85, 105, 115, 155, 35 };
int color4[] = { 173, 73, 93, 113, 133, 153, 163, 143, 83, 103, 113, 153, 33 };
addNestedRectangles(img, Point(10, 10), width, color1, 13);
addNestedCircles(img, Point(200, 600), width, color2, 13);
addNestedRectangles(img, Point(410, 10), width, color3, 13);
addNestedCircles(img, Point(600, 600), width, color4, 13);
int histSize = 256;
float range[] = { 0, 256 };
const float* histRange[] = { range };
Mat hist;
// we compute the histogram
calcHist(&img, 1, 0, Mat(), hist, 1, &histSize, histRange, true, false);
cout << "****************Maximal region************************\n";
for (int i = 0; i < hist.rows; i++)
{
if (hist.at<float>(i, 0)!=0)
{
cout << "h" << setw(3) << left << i << "\t=\t" << hist.at<float>(i, 0) << "\n";
}
}
return img;
}
int main(int argc, char *argv[])
{
Mat imgOrig, img;
Size blurSize(5, 5);
cv::CommandLineParser parser(argc, argv, "{ help h | | }{ @input | | }");
if (parser.has("help"))
{
help(argv);
return 0;
}
string input = parser.get<string>("@input");
if (!input.empty())
{
imgOrig = imread(samples::findFile(input), IMREAD_GRAYSCALE);
blur(imgOrig, img, blurSize);
}
else
{
imgOrig = MakeSyntheticImage();
img = imgOrig;
}
// Descriptor array MSER
vector<String> typeDesc;
// Param array for MSER
vector<MSERParams> pMSER;
// Color palette
vector<Vec3b> palette;
for (int i = 0; i<=numeric_limits<uint16_t>::max(); i++)
palette.push_back(Vec3b((uchar)rand(), (uchar)rand(), (uchar)rand()));
help(argv);
MSERParams params;
params.delta = 10;
params.minArea = 100;
params.maxArea = 5000;
params.maxVariation = 2;
params.minDiversity = 0;
params.pass2Only = true;
typeDesc.push_back("MSER");
pMSER.push_back(params);
params.pass2Only = false;
typeDesc.push_back("MSER");
pMSER.push_back(params);
params.delta = 100;
typeDesc.push_back("MSER");
pMSER.push_back(params);
vector<MSERParams>::iterator itMSER = pMSER.begin();
Ptr<Feature2D> b;
String label;
// Descriptor loop
vector<String>::iterator itDesc;
Mat result(img.rows, img.cols, CV_8UC3);
for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
{
vector<KeyPoint> keyImg1;
if (*itDesc == "MSER")
{
if (img.type() == CV_8UC3)
{
b = MSER::create(itMSER->delta, itMSER->minArea, itMSER->maxArea, itMSER->maxVariation, itMSER->minDiversity, itMSER->maxEvolution,
itMSER->areaThreshold, itMSER->minMargin, itMSER->edgeBlurSize);
label = Legende(*itMSER);
++itMSER;
}
else
{
b = MSER::create(itMSER->delta, itMSER->minArea, itMSER->maxArea, itMSER->maxVariation, itMSER->minDiversity);
b.dynamicCast<MSER>()->setPass2Only(itMSER->pass2Only);
label = Legende(*itMSER);
++itMSER;
}
}
if (img.type()==CV_8UC3)
{
img.copyTo(result);
}
else
{
vector<Mat> plan;
plan.push_back(img);
plan.push_back(img);
plan.push_back(img);
merge(plan,result);
}
try
{
// We can detect regions using detectRegions method
vector<KeyPoint> keyImg;
vector<Rect> zone;
vector<vector <Point> > region;
Mat desc;
if (b.dynamicCast<MSER>().get())
{
Ptr<MSER> sbd = b.dynamicCast<MSER>();
sbd->detectRegions(img, region, zone);
//result = Scalar(0, 0, 0);
int nbPixelInMSER=0;
for (vector<vector <Point> >::iterator itr = region.begin(); itr != region.end(); ++itr)
{
for (vector <Point>::iterator itp = itr->begin(); itp != itr->end(); ++itp)
{
// all pixels belonging to region become blue
result.at<Vec3b>(itp->y, itp->x) = Vec3b(128, 0, 0);
nbPixelInMSER++;
}
}
cout << "Number of MSER region: " << region.size() << "; Number of pixels in all MSER region: " << nbPixelInMSER << "\n";
}
const string winName = *itDesc + label;
namedWindow(winName, WINDOW_AUTOSIZE);
imshow(winName, result);
imshow("Original", img);
}
catch (const Exception& e)
{
cout << "Feature: " << *itDesc << "\n";
cout << e.msg << endl;
}
#ifdef HAVE_OPENGL
DrawOpenGLMSER(img, result);
#endif
waitKey();
}
return 0;
}

View File

@ -0,0 +1,86 @@
#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
using namespace cv;
using namespace std;
static void help(const char ** argv)
{
printf("\nThis program demonstrated the use of the discrete Fourier transform (dft)\n"
"The dft of an image is taken and it's power spectrum is displayed.\n"
"Usage:\n %s [image_name -- default lena.jpg]\n",argv[0]);
}
const char* keys =
{
"{help h||}{@image|lena.jpg|input image file}"
};
int main(int argc, const char ** argv)
{
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);
if( img.empty() )
{
help(argv);
printf("Cannot read image file: %s\n", filename.c_str());
return -1;
}
int M = getOptimalDFTSize( img.rows );
int N = getOptimalDFTSize( img.cols );
Mat padded;
copyMakeBorder(img, padded, 0, M - img.rows, 0, N - img.cols, BORDER_CONSTANT, Scalar::all(0));
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexImg;
merge(planes, 2, complexImg);
dft(complexImg, complexImg);
// compute log(1 + sqrt(Re(DFT(img))**2 + Im(DFT(img))**2))
split(complexImg, planes);
magnitude(planes[0], planes[1], planes[0]);
Mat mag = planes[0];
mag += Scalar::all(1);
log(mag, mag);
// crop the spectrum, if it has an odd number of rows or columns
mag = mag(Rect(0, 0, mag.cols & -2, mag.rows & -2));
int cx = mag.cols/2;
int cy = mag.rows/2;
// rearrange the quadrants of Fourier image
// so that the origin is at the image center
Mat tmp;
Mat q0(mag, Rect(0, 0, cx, cy));
Mat q1(mag, Rect(cx, 0, cx, cy));
Mat q2(mag, Rect(0, cy, cx, cy));
Mat q3(mag, Rect(cx, cy, cx, cy));
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
normalize(mag, mag, 0, 1, NORM_MINMAX);
imshow("spectrum magnitude", mag);
waitKey();
return 0;
}

View File

@ -0,0 +1,182 @@
// This example provides a digital recognition based on LeNet-5 and connected component analysis.
// It makes it possible for OpenCV beginner to run dnn models in real time using only CPU.
// It can read pictures from the camera in real time to make predictions, and display the recognized digits as overlays on top of the original digits.
//
// In order to achieve a better display effect, please write the number on white paper and occupy the entire camera.
//
// You can follow the following guide to train LeNet-5 by yourself using the MNIST dataset.
// https://github.com/intel/caffe/blob/a3d5b022fe026e9092fc7abc7654b1162ab9940d/examples/mnist/readme.md
//
// You can also download already trained model directly.
// https://github.com/zihaomu/opencv_digit_text_recognition_demo/tree/master/src
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <vector>
using namespace cv;
using namespace cv::dnn;
const char *keys =
"{ help h | | Print help message. }"
"{ input i | | Path to input image or video file. Skip this argument to capture frames from a camera.}"
"{ device | 0 | camera device number. }"
"{ modelBin | | Path to a binary .caffemodel file contains trained network.}"
"{ modelTxt | | Path to a .prototxt file contains the model definition of trained network.}"
"{ width | 640 | Set the width of the camera }"
"{ height | 480 | Set the height of the camera }"
"{ thr | 0.7 | Confidence threshold. }";
// Find best class for the blob (i.e. class with maximal probability)
static void getMaxClass(const Mat &probBlob, int &classId, double &classProb);
void predictor(Net net, const Mat &roi, int &class_id, double &probability);
int main(int argc, char **argv)
{
// Parse command line arguments.
CommandLineParser parser(argc, argv, keys);
if (argc == 1 || parser.has("help"))
{
parser.printMessage();
return 0;
}
int vWidth = parser.get<int>("width");
int vHeight = parser.get<int>("height");
float confThreshold = parser.get<float>("thr");
std::string modelTxt = parser.get<String>("modelTxt");
std::string modelBin = parser.get<String>("modelBin");
Net net;
try
{
net = readNet(modelTxt, modelBin);
}
catch (cv::Exception &ee)
{
std::cerr << "Exception: " << ee.what() << std::endl;
std::cout << "Can't load the network by using the flowing files:" << std::endl;
std::cout << "modelTxt: " << modelTxt << std::endl;
std::cout << "modelBin: " << modelBin << std::endl;
return 1;
}
const std::string resultWinName = "Please write the number on white paper and occupy the entire camera.";
const std::string preWinName = "Preprocessing";
namedWindow(preWinName, WINDOW_AUTOSIZE);
namedWindow(resultWinName, WINDOW_AUTOSIZE);
Mat labels, stats, centroids;
Point position;
Rect getRectangle;
bool ifDrawingBox = false;
int classId = 0;
double probability = 0;
Rect basicRect = Rect(0, 0, vWidth, vHeight);
Mat rawImage;
double fps = 0;
// Open a video file or an image file or a camera stream.
VideoCapture cap;
if (parser.has("input"))
cap.open(parser.get<String>("input"));
else
cap.open(parser.get<int>("device"));
TickMeter tm;
while (waitKey(1) < 0)
{
cap >> rawImage;
if (rawImage.empty())
{
waitKey();
break;
}
tm.reset();
tm.start();
Mat image = rawImage.clone();
// Image preprocessing
cvtColor(image, image, COLOR_BGR2GRAY);
GaussianBlur(image, image, Size(3, 3), 2, 2);
adaptiveThreshold(image, image, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 25, 10);
bitwise_not(image, image);
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1,-1));
dilate(image, image, element, Point(-1,-1), 1);
// Find connected component
int nccomps = cv::connectedComponentsWithStats(image, labels, stats, centroids);
for (int i = 1; i < nccomps; i++)
{
ifDrawingBox = false;
// Extend the bounding box of connected component for easier recognition
if (stats.at<int>(i - 1, CC_STAT_AREA) > 80 && stats.at<int>(i - 1, CC_STAT_AREA) < 3000)
{
ifDrawingBox = true;
int left = stats.at<int>(i - 1, CC_STAT_HEIGHT) / 4;
getRectangle = Rect(stats.at<int>(i - 1, CC_STAT_LEFT) - left, stats.at<int>(i - 1, CC_STAT_TOP) - left, stats.at<int>(i - 1, CC_STAT_WIDTH) + 2 * left, stats.at<int>(i - 1, CC_STAT_HEIGHT) + 2 * left);
getRectangle &= basicRect;
}
if (ifDrawingBox && !getRectangle.empty())
{
Mat roi = image(getRectangle);
predictor(net, roi, classId, probability);
if (probability < confThreshold)
continue;
rectangle(rawImage, getRectangle, Scalar(128, 255, 128), 2);
position = Point(getRectangle.br().x - 7, getRectangle.br().y + 25);
putText(rawImage, std::to_string(classId), position, 3, 1.0, Scalar(128, 128, 255), 2);
}
}
tm.stop();
fps = 1 / tm.getTimeSec();
std::string fpsString = format("Inference FPS: %.2f.", fps);
putText(rawImage, fpsString, Point(5, 20), FONT_HERSHEY_SIMPLEX, 0.6, Scalar(128, 255, 128));
imshow(resultWinName, rawImage);
imshow(preWinName, image);
}
return 0;
}
static void getMaxClass(const Mat &probBlob, int &classId, double &classProb)
{
Mat probMat = probBlob.reshape(1, 1);
Point classNumber;
minMaxLoc(probMat, NULL, &classProb, NULL, &classNumber);
classId = classNumber.x;
}
void predictor(Net net, const Mat &roi, int &classId, double &probability)
{
Mat pred;
// Convert Mat to batch of images
Mat inputBlob = dnn::blobFromImage(roi, 1.0, Size(28, 28));
// Set the network input
net.setInput(inputBlob);
// Compute output
pred = net.forward();
getMaxClass(pred, classId, probability);
}

View File

@ -0,0 +1,375 @@
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/ml.hpp"
#include <algorithm>
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
const int SZ = 20; // size of each digit is SZ x SZ
const int CLASS_N = 10;
const char* DIGITS_FN = "digits.png";
static void help(char** argv)
{
cout <<
"\n"
"SVM and KNearest digit recognition.\n"
"\n"
"Sample loads a dataset of handwritten digits from 'digits.png'.\n"
"Then it trains a SVM and KNearest classifiers on it and evaluates\n"
"their accuracy.\n"
"\n"
"Following preprocessing is applied to the dataset:\n"
" - Moment-based image deskew (see deskew())\n"
" - Digit images are split into 4 10x10 cells and 16-bin\n"
" histogram of oriented gradients is computed for each\n"
" cell\n"
" - Transform histograms to space with Hellinger metric (see [1] (RootSIFT))\n"
"\n"
"\n"
"[1] R. Arandjelovic, A. Zisserman\n"
" \"Three things everyone should know to improve object retrieval\"\n"
" http://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf\n"
"\n"
"Usage:\n"
<< argv[0] << endl;
}
static void split2d(const Mat& image, const Size cell_size, vector<Mat>& cells)
{
int height = image.rows;
int width = image.cols;
int sx = cell_size.width;
int sy = cell_size.height;
cells.clear();
for (int i = 0; i < height; i += sy)
{
for (int j = 0; j < width; j += sx)
{
cells.push_back(image(Rect(j, i, sx, sy)));
}
}
}
static void load_digits(const char* fn, vector<Mat>& digits, vector<int>& labels)
{
digits.clear();
labels.clear();
String filename = samples::findFile(fn);
cout << "Loading " << filename << " ..." << endl;
Mat digits_img = imread(filename, IMREAD_GRAYSCALE);
split2d(digits_img, Size(SZ, SZ), digits);
for (int i = 0; i < CLASS_N; i++)
{
for (size_t j = 0; j < digits.size() / CLASS_N; j++)
{
labels.push_back(i);
}
}
}
static void deskew(const Mat& img, Mat& deskewed_img)
{
Moments m = moments(img);
if (abs(m.mu02) < 0.01)
{
deskewed_img = img.clone();
return;
}
float skew = (float)(m.mu11 / m.mu02);
float M_vals[2][3] = {{1, skew, -0.5f * SZ * skew}, {0, 1, 0}};
Mat M(Size(3, 2), CV_32F);
for (int i = 0; i < M.rows; i++)
{
for (int j = 0; j < M.cols; j++)
{
M.at<float>(i, j) = M_vals[i][j];
}
}
warpAffine(img, deskewed_img, M, Size(SZ, SZ), WARP_INVERSE_MAP | INTER_LINEAR);
}
static void mosaic(const int width, const vector<Mat>& images, Mat& grid)
{
int mat_width = SZ * width;
int mat_height = SZ * (int)ceil((double)images.size() / width);
if (!images.empty())
{
grid = Mat(Size(mat_width, mat_height), images[0].type());
for (size_t i = 0; i < images.size(); i++)
{
Mat location_on_grid = grid(Rect(SZ * ((int)i % width), SZ * ((int)i / width), SZ, SZ));
images[i].copyTo(location_on_grid);
}
}
}
static void evaluate_model(const vector<float>& predictions, const vector<Mat>& digits, const vector<int>& labels, Mat& mos)
{
double err = 0;
for (size_t i = 0; i < predictions.size(); i++)
{
if ((int)predictions[i] != labels[i])
{
err++;
}
}
err /= predictions.size();
cout << cv::format("error: %.2f %%", err * 100) << endl;
int confusion[10][10] = {};
for (size_t i = 0; i < labels.size(); i++)
{
confusion[labels[i]][(int)predictions[i]]++;
}
cout << "confusion matrix:" << endl;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
cout << cv::format("%2d ", confusion[i][j]);
}
cout << endl;
}
cout << endl;
vector<Mat> vis;
for (size_t i = 0; i < digits.size(); i++)
{
Mat img;
cvtColor(digits[i], img, COLOR_GRAY2BGR);
if ((int)predictions[i] != labels[i])
{
for (int j = 0; j < img.rows; j++)
{
for (int k = 0; k < img.cols; k++)
{
img.at<Vec3b>(j, k)[0] = 0;
img.at<Vec3b>(j, k)[1] = 0;
}
}
}
vis.push_back(img);
}
mosaic(25, vis, mos);
}
static void bincount(const Mat& x, const Mat& weights, const int min_length, vector<double>& bins)
{
double max_x_val = 0;
minMaxLoc(x, NULL, &max_x_val);
bins = vector<double>(max((int)max_x_val, min_length));
for (int i = 0; i < x.rows; i++)
{
for (int j = 0; j < x.cols; j++)
{
bins[x.at<int>(i, j)] += weights.at<float>(i, j);
}
}
}
static void preprocess_hog(const vector<Mat>& digits, Mat& hog)
{
int bin_n = 16;
int half_cell = SZ / 2;
double eps = 1e-7;
hog = Mat(Size(4 * bin_n, (int)digits.size()), CV_32F);
for (size_t img_index = 0; img_index < digits.size(); img_index++)
{
Mat gx;
Sobel(digits[img_index], gx, CV_32F, 1, 0);
Mat gy;
Sobel(digits[img_index], gy, CV_32F, 0, 1);
Mat mag;
Mat ang;
cartToPolar(gx, gy, mag, ang);
Mat bin(ang.size(), CV_32S);
for (int i = 0; i < ang.rows; i++)
{
for (int j = 0; j < ang.cols; j++)
{
bin.at<int>(i, j) = (int)(bin_n * ang.at<float>(i, j) / (2 * CV_PI));
}
}
Mat bin_cells[] = {
bin(Rect(0, 0, half_cell, half_cell)),
bin(Rect(half_cell, 0, half_cell, half_cell)),
bin(Rect(0, half_cell, half_cell, half_cell)),
bin(Rect(half_cell, half_cell, half_cell, half_cell))
};
Mat mag_cells[] = {
mag(Rect(0, 0, half_cell, half_cell)),
mag(Rect(half_cell, 0, half_cell, half_cell)),
mag(Rect(0, half_cell, half_cell, half_cell)),
mag(Rect(half_cell, half_cell, half_cell, half_cell))
};
vector<double> hist;
hist.reserve(4 * bin_n);
for (int i = 0; i < 4; i++)
{
vector<double> partial_hist;
bincount(bin_cells[i], mag_cells[i], bin_n, partial_hist);
hist.insert(hist.end(), partial_hist.begin(), partial_hist.end());
}
// transform to Hellinger kernel
double sum = 0;
for (size_t i = 0; i < hist.size(); i++)
{
sum += hist[i];
}
for (size_t i = 0; i < hist.size(); i++)
{
hist[i] /= sum + eps;
hist[i] = sqrt(hist[i]);
}
double hist_norm = norm(hist);
for (size_t i = 0; i < hist.size(); i++)
{
hog.at<float>((int)img_index, (int)i) = (float)(hist[i] / (hist_norm + eps));
}
}
}
static void shuffle(vector<Mat>& digits, vector<int>& labels)
{
vector<int> shuffled_indexes(digits.size());
for (size_t i = 0; i < digits.size(); i++)
{
shuffled_indexes[i] = (int)i;
}
randShuffle(shuffled_indexes);
vector<Mat> shuffled_digits(digits.size());
vector<int> shuffled_labels(labels.size());
for (size_t i = 0; i < shuffled_indexes.size(); i++)
{
shuffled_digits[shuffled_indexes[i]] = digits[i];
shuffled_labels[shuffled_indexes[i]] = labels[i];
}
digits = shuffled_digits;
labels = shuffled_labels;
}
int main(int /* argc */, char* argv[])
{
help(argv);
vector<Mat> digits;
vector<int> labels;
load_digits(DIGITS_FN, digits, labels);
cout << "preprocessing..." << endl;
// shuffle digits
shuffle(digits, labels);
vector<Mat> digits2;
for (size_t i = 0; i < digits.size(); i++)
{
Mat deskewed_digit;
deskew(digits[i], deskewed_digit);
digits2.push_back(deskewed_digit);
}
Mat samples;
preprocess_hog(digits2, samples);
int train_n = (int)(0.9 * samples.rows);
Mat test_set;
vector<Mat> digits_test(digits2.begin() + train_n, digits2.end());
mosaic(25, digits_test, test_set);
imshow("test set", test_set);
Mat samples_train = samples(Rect(0, 0, samples.cols, train_n));
Mat samples_test = samples(Rect(0, train_n, samples.cols, samples.rows - train_n));
vector<int> labels_train(labels.begin(), labels.begin() + train_n);
vector<int> labels_test(labels.begin() + train_n, labels.end());
Ptr<ml::KNearest> k_nearest;
Ptr<ml::SVM> svm;
vector<float> predictions;
Mat vis;
cout << "training KNearest..." << endl;
k_nearest = ml::KNearest::create();
k_nearest->train(samples_train, ml::ROW_SAMPLE, labels_train);
// predict digits with KNearest
k_nearest->findNearest(samples_test, 4, predictions);
evaluate_model(predictions, digits_test, labels_test, vis);
imshow("KNearest test", vis);
k_nearest.release();
cout << "training SVM..." << endl;
svm = ml::SVM::create();
svm->setGamma(5.383);
svm->setC(2.67);
svm->setKernel(ml::SVM::RBF);
svm->setType(ml::SVM::C_SVC);
svm->train(samples_train, ml::ROW_SAMPLE, labels_train);
// predict digits with SVM
svm->predict(samples_test, predictions);
evaluate_model(predictions, digits_test, labels_test, vis);
imshow("SVM test", vis);
cout << "Saving SVM as \"digits_svm.yml\"..." << endl;
svm->save("digits_svm.yml");
svm.release();
waitKey();
return 0;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,189 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
using namespace cv;
static void help(char** argv)
{
printf("\nThis program demonstrates OpenCV drawing and text output functions.\n"
"Usage:\n"
" %s\n", argv[0]);
}
static Scalar randomColor(RNG& rng)
{
int icolor = (unsigned)rng;
return Scalar(icolor&255, (icolor>>8)&255, (icolor>>16)&255);
}
int main(int /* argc */, char** argv)
{
help(argv);
char wndname[] = "Drawing Demo";
const int NUMBER = 100;
const int DELAY = 5;
int lineType = LINE_AA; // change it to LINE_8 to see non-antialiased graphics
int i, width = 1000, height = 700;
int x1 = -width/2, x2 = width*3/2, y1 = -height/2, y2 = height*3/2;
RNG rng(0xFFFFFFFF);
Mat image = Mat::zeros(height, width, CV_8UC3);
imshow(wndname, image);
waitKey(DELAY);
for (i = 0; i < NUMBER * 2; i++)
{
Point pt1, pt2;
pt1.x = rng.uniform(x1, x2);
pt1.y = rng.uniform(y1, y2);
pt2.x = rng.uniform(x1, x2);
pt2.y = rng.uniform(y1, y2);
int arrowed = rng.uniform(0, 6);
if( arrowed < 3 )
line( image, pt1, pt2, randomColor(rng), rng.uniform(1,10), lineType );
else
arrowedLine(image, pt1, pt2, randomColor(rng), rng.uniform(1, 10), lineType);
imshow(wndname, image);
if(waitKey(DELAY) >= 0)
return 0;
}
for (i = 0; i < NUMBER * 2; i++)
{
Point pt1, pt2;
pt1.x = rng.uniform(x1, x2);
pt1.y = rng.uniform(y1, y2);
pt2.x = rng.uniform(x1, x2);
pt2.y = rng.uniform(y1, y2);
int thickness = rng.uniform(-3, 10);
int marker = rng.uniform(0, 10);
int marker_size = rng.uniform(30, 80);
if (marker > 5)
rectangle(image, pt1, pt2, randomColor(rng), MAX(thickness, -1), lineType);
else
drawMarker(image, pt1, randomColor(rng), marker, marker_size );
imshow(wndname, image);
if(waitKey(DELAY) >= 0)
return 0;
}
for (i = 0; i < NUMBER; i++)
{
Point center;
center.x = rng.uniform(x1, x2);
center.y = rng.uniform(y1, y2);
Size axes;
axes.width = rng.uniform(0, 200);
axes.height = rng.uniform(0, 200);
double angle = rng.uniform(0, 180);
ellipse( image, center, axes, angle, angle - 100, angle + 200,
randomColor(rng), rng.uniform(-1,9), lineType );
imshow(wndname, image);
if(waitKey(DELAY) >= 0)
return 0;
}
for (i = 0; i< NUMBER; i++)
{
Point pt[2][3];
pt[0][0].x = rng.uniform(x1, x2);
pt[0][0].y = rng.uniform(y1, y2);
pt[0][1].x = rng.uniform(x1, x2);
pt[0][1].y = rng.uniform(y1, y2);
pt[0][2].x = rng.uniform(x1, x2);
pt[0][2].y = rng.uniform(y1, y2);
pt[1][0].x = rng.uniform(x1, x2);
pt[1][0].y = rng.uniform(y1, y2);
pt[1][1].x = rng.uniform(x1, x2);
pt[1][1].y = rng.uniform(y1, y2);
pt[1][2].x = rng.uniform(x1, x2);
pt[1][2].y = rng.uniform(y1, y2);
const Point* ppt[2] = {pt[0], pt[1]};
int npt[] = {3, 3};
polylines(image, ppt, npt, 2, true, randomColor(rng), rng.uniform(1,10), lineType);
imshow(wndname, image);
if(waitKey(DELAY) >= 0)
return 0;
}
for (i = 0; i< NUMBER; i++)
{
Point pt[2][3];
pt[0][0].x = rng.uniform(x1, x2);
pt[0][0].y = rng.uniform(y1, y2);
pt[0][1].x = rng.uniform(x1, x2);
pt[0][1].y = rng.uniform(y1, y2);
pt[0][2].x = rng.uniform(x1, x2);
pt[0][2].y = rng.uniform(y1, y2);
pt[1][0].x = rng.uniform(x1, x2);
pt[1][0].y = rng.uniform(y1, y2);
pt[1][1].x = rng.uniform(x1, x2);
pt[1][1].y = rng.uniform(y1, y2);
pt[1][2].x = rng.uniform(x1, x2);
pt[1][2].y = rng.uniform(y1, y2);
const Point* ppt[2] = {pt[0], pt[1]};
int npt[] = {3, 3};
fillPoly(image, ppt, npt, 2, randomColor(rng), lineType);
imshow(wndname, image);
if(waitKey(DELAY) >= 0)
return 0;
}
for (i = 0; i < NUMBER; i++)
{
Point center;
center.x = rng.uniform(x1, x2);
center.y = rng.uniform(y1, y2);
circle(image, center, rng.uniform(0, 300), randomColor(rng),
rng.uniform(-1, 9), lineType);
imshow(wndname, image);
if(waitKey(DELAY) >= 0)
return 0;
}
for (i = 1; i < NUMBER; i++)
{
Point org;
org.x = rng.uniform(x1, x2);
org.y = rng.uniform(y1, y2);
putText(image, "Testing text rendering", org, rng.uniform(0,8),
rng.uniform(0,100)*0.05+0.1, randomColor(rng), rng.uniform(1, 10), lineType);
imshow(wndname, image);
if(waitKey(DELAY) >= 0)
return 0;
}
Size textsize = getTextSize("OpenCV forever!", FONT_HERSHEY_COMPLEX, 3, 5, 0);
Point org((width - textsize.width)/2, (height - textsize.height)/2);
Mat image2;
for( i = 0; i < 255; i += 2 )
{
image2 = image - Scalar::all(i);
putText(image2, "OpenCV forever!", org, FONT_HERSHEY_COMPLEX, 3,
Scalar(i, i, 255), 5, lineType);
imshow(wndname, image2);
if(waitKey(DELAY) >= 0)
return 0;
}
waitKey();
return 0;
}

View File

@ -0,0 +1,85 @@
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
using namespace cv;
using namespace std;
int edgeThresh = 1;
int edgeThreshScharr=1;
Mat image, gray, blurImage, edge1, edge2, cedge;
const char* window_name1 = "Edge map : Canny default (Sobel gradient)";
const char* window_name2 = "Edge map : Canny with custom gradient (Scharr)";
// define a trackbar callback
static void onTrackbar(int, void*)
{
blur(gray, blurImage, Size(3,3));
// Run the edge detector on grayscale
Canny(blurImage, edge1, edgeThresh, edgeThresh*3, 3);
cedge = Scalar::all(0);
image.copyTo(cedge, edge1);
imshow(window_name1, cedge);
/// Canny detector with scharr
Mat dx,dy;
Scharr(blurImage,dx,CV_16S,1,0);
Scharr(blurImage,dy,CV_16S,0,1);
Canny( dx,dy, edge2, edgeThreshScharr, edgeThreshScharr*3 );
/// Using Canny's output as a mask, we display our result
cedge = Scalar::all(0);
image.copyTo(cedge, edge2);
imshow(window_name2, cedge);
}
static void help(const char** argv)
{
printf("\nThis sample demonstrates Canny edge detection\n"
"Call:\n"
" %s [image_name -- Default is fruits.jpg]\n\n", argv[0]);
}
const char* keys =
{
"{help h||}{@image |fruits.jpg|input image name}"
};
int main( int argc, const char** argv )
{
help(argv);
CommandLineParser parser(argc, argv, keys);
string filename = parser.get<string>(0);
image = imread(samples::findFile(filename), IMREAD_COLOR);
if(image.empty())
{
printf("Cannot read image file: %s\n", filename.c_str());
help(argv);
return -1;
}
cedge.create(image.size(), image.type());
cvtColor(image, gray, COLOR_BGR2GRAY);
// Create a window
namedWindow(window_name1, 1);
namedWindow(window_name2, 1);
// create a toolbar
createTrackbar("Canny threshold default", window_name1, &edgeThresh, 100, onTrackbar);
createTrackbar("Canny threshold Scharr", window_name2, &edgeThreshScharr, 400, onTrackbar);
// Show the image
onTrackbar(0, 0);
// Wait for a key stroke; the same function arranges events processing
waitKey(0);
return 0;
}

View File

@ -0,0 +1,67 @@
/**
@file ela.cpp
@author Alessandro de Oliveira Faria (A.K.A. CABELO)
@brief Error Level Analysis (ELA) permits identifying areas within an image that are at different compression levels. With JPEG images, the entire picture should be at roughly the same level. If a section of the image is at a significantly different error level, then it likely indicates a digital modification. This example allows to see visually the changes made in a JPG image based in it's compression error analysis. Questions and suggestions email to: Alessandro de Oliveira Faria cabelo[at]opensuse[dot]org or OpenCV Team.
@date Jun 24, 2018
*/
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
int scale_value = 7;
int quality = 95;
Mat image;
Mat compressed_img;
const char* decodedwin = "the recompressed image";
const char* diffwin = "scaled difference between the original and recompressed images";
static void processImage(int , void*)
{
Mat Ela;
// Compression jpeg
std::vector<int> compressing_factor;
std::vector<uchar> buf;
compressing_factor.push_back(IMWRITE_JPEG_QUALITY);
compressing_factor.push_back(quality);
imencode(".jpg", image, buf, compressing_factor);
compressed_img = imdecode(buf, 1);
Mat output;
absdiff(image,compressed_img,output);
output.convertTo(Ela, CV_8UC3, scale_value);
// Shows processed image
imshow(decodedwin, compressed_img);
imshow(diffwin, Ela);
}
int main (int argc, char* argv[])
{
CommandLineParser parser(argc, argv, "{ input i | ela_modified.jpg | Input image to calculate ELA algorithm. }");
parser.about("\nJpeg Recompression Example:\n");
parser.printMessage();
// Read the new image
image = imread(samples::findFile(parser.get<String>("input")));
// Check image
if (!image.empty())
{
processImage(0, 0);
createTrackbar("Scale", diffwin, &scale_value, 100, processImage);
createTrackbar("Quality", diffwin, &quality, 100, processImage);
waitKey(0);
}
else
{
std::cout << "> Error in load image\n";
}
return 0;
}

View File

@ -0,0 +1,70 @@
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/ml.hpp"
using namespace cv;
using namespace cv::ml;
int main( int /*argc*/, char** /*argv*/ )
{
const int N = 4;
const int N1 = (int)sqrt((double)N);
const Scalar colors[] =
{
Scalar(0,0,255), Scalar(0,255,0),
Scalar(0,255,255),Scalar(255,255,0)
};
int i, j;
int nsamples = 100;
Mat samples( nsamples, 2, CV_32FC1 );
Mat labels;
Mat img = Mat::zeros( Size( 500, 500 ), CV_8UC3 );
Mat sample( 1, 2, CV_32FC1 );
samples = samples.reshape(2, 0);
for( i = 0; i < N; i++ )
{
// form the training samples
Mat samples_part = samples.rowRange(i*nsamples/N, (i+1)*nsamples/N );
Scalar mean(((i%N1)+1)*img.rows/(N1+1),
((i/N1)+1)*img.rows/(N1+1));
Scalar sigma(30,30);
randn( samples_part, mean, sigma );
}
samples = samples.reshape(1, 0);
// cluster the data
Ptr<EM> em_model = EM::create();
em_model->setClustersNumber(N);
em_model->setCovarianceMatrixType(EM::COV_MAT_SPHERICAL);
em_model->setTermCriteria(TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 300, 0.1));
em_model->trainEM( samples, noArray(), labels, noArray() );
// classify every image pixel
for( i = 0; i < img.rows; i++ )
{
for( j = 0; j < img.cols; j++ )
{
sample.at<float>(0) = (float)j;
sample.at<float>(1) = (float)i;
int response = cvRound(em_model->predict2( sample, noArray() )[1]);
Scalar c = colors[response];
circle( img, Point(j, i), 1, c*0.75, FILLED );
}
}
//draw the clustered samples
for( i = 0; i < nsamples; i++ )
{
Point pt(cvRound(samples.at<float>(i, 0)), cvRound(samples.at<float>(i, 1)));
circle( img, pt, 1, colors[labels.at<int>(i)], FILLED );
}
imshow( "EM-clustering result", img );
waitKey(0);
return 0;
}

View File

@ -0,0 +1,106 @@
// 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/calib3d.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);
}

View File

@ -0,0 +1,342 @@
// 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/calib3d.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <vector>
#include <iostream>
#include <fstream>
using namespace cv;
static double getError2EpipLines (const Mat &F, const Mat &pts1, const Mat &pts2, const Mat &mask) {
Mat points1, points2;
vconcat(pts1, Mat::ones(1, pts1.cols, pts1.type()), points1);
vconcat(pts2, Mat::ones(1, pts2.cols, pts2.type()), points2);
double mean_error = 0;
for (int pt = 0; pt < (int) mask.total(); pt++)
if (mask.at<uchar>(pt)) {
const Mat l2 = F * points1.col(pt);
const Mat l1 = F.t() * points2.col(pt);
mean_error += (fabs(points1.col(pt).dot(l1)) / sqrt(pow(l1.at<double>(0), 2) + pow(l1.at<double>(1), 2)) +
fabs(points2.col(pt).dot(l2) / sqrt(pow(l2.at<double>(0), 2) + pow(l2.at<double>(1), 2)))) / 2;
}
return mean_error / mask.total();
}
static int sgn(double val) { return (0 < val) - (val < 0); }
/*
* @points3d - vector of Point3 or Mat of size Nx3
* @planes - vector of found planes
* @labels - vector of size point3d. Every point which has non-zero label is classified to this plane.
*/
static void getPlanes (InputArray points3d_, std::vector<int> &labels, std::vector<Vec4d> &planes, int desired_num_planes, double thr_, double conf_, int max_iters_) {
Mat points3d = points3d_.getMat();
points3d.convertTo(points3d, CV_64F); // convert points to have double precision
if (points3d_.isVector())
points3d = Mat((int)points3d.total(), 3, CV_64F, points3d.data);
else {
if (points3d.type() != CV_64F)
points3d = points3d.reshape(1, (int)points3d.total()); // convert point to have 1 channel
if (points3d.rows < points3d.cols)
transpose(points3d, points3d); // transpose so points will be in rows
CV_CheckEQ(points3d.cols, 3, "Invalid dimension of point");
}
/*
* 3D plane fitting with RANSAC
* @best_model contains coefficients [a b c d] s.t. ax + by + cz = d
*
*/
auto plane_ransac = [] (const Mat &pts, double thr, double conf, int max_iters, Vec4d &best_model, std::vector<bool> &inliers) {
const int pts_size = pts.rows, max_lo_inliers = 15, max_lo_iters = 10;
int best_inls = 0;
if (pts_size < 3) return false;
RNG rng;
const auto * const points = (double *) pts.data;
std::vector<int> min_sample(3);
inliers = std::vector<bool>(pts_size);
const double log_conf = log(1-conf);
Vec4d model, lo_model;
std::vector<int> random_pool (pts_size);
for (int p = 0; p < pts_size; p++)
random_pool[p] = p;
// estimate plane coefficients using covariance matrix
auto estimate = [&] (const std::vector<int> &sample, Vec4d &model_) {
// https://www.ilikebigbits.com/2017_09_25_plane_from_points_2.html
const int n = static_cast<int>(sample.size());
if (n < 3) return false;
double sum_x = 0, sum_y = 0, sum_z = 0;
for (int s : sample) {
sum_x += points[3*s ];
sum_y += points[3*s+1];
sum_z += points[3*s+2];
}
const double c_x = sum_x / n, c_y = sum_y / n, c_z = sum_z / n;
double xx = 0, yy = 0, zz = 0, xy = 0, xz = 0, yz = 0;
for (int s : sample) {
const double x_ = points[3*s] - c_x, y_ = points[3*s+1] - c_y, z_ = points[3*s+2] - c_z;
xx += x_*x_; yy += y_*y_; zz += z_*z_; xy += x_*y_; yz += y_*z_; xz += x_*z_;
}
xx /= n; yy /= n; zz /= n; xy /= n; yz /= n; xz /= n;
Vec3d weighted_normal(0,0,0);
const double det_x = yy*zz - yz*yz, det_y = xx*zz - xz*xz, det_z = xx*yy - xy*xy;
Vec3d axis_x (det_x, xz*xz-xy*zz, xy*yz-xz*yy);
Vec3d axis_y (xz*yz-xy*zz, det_y, xy*xz-yz*xx);
Vec3d axis_z (xy*yz-xz*yy, xy*xz-yz*xx, det_z);
weighted_normal += axis_x * det_x * det_x;
weighted_normal += sgn(weighted_normal.dot(axis_y)) * axis_y * det_y * det_y;
weighted_normal += sgn(weighted_normal.dot(axis_z)) * axis_z * det_z * det_z;
weighted_normal /= norm(weighted_normal);
if (std::isinf(weighted_normal(0)) ||
std::isinf(weighted_normal(1)) ||
std::isinf(weighted_normal(2))) return false;
// find plane model from normal and centroid
model_ = Vec4d(weighted_normal(0), weighted_normal(1), weighted_normal(2),
weighted_normal.dot(Vec3d(c_x, c_y, c_z)));
return true;
};
// calculate number of inliers
auto getInliers = [&] (const Vec4d &model_) {
const double a = model_(0), b = model_(1), c = model_(2), d = model_(3);
int num_inliers = 0;
std::fill(inliers.begin(), inliers.end(), false);
for (int p = 0; p < pts_size; p++) {
inliers[p] = fabs(a * points[3*p] + b * points[3*p+1] + c * points[3*p+2] - d) < thr;
if (inliers[p]) num_inliers++;
if (num_inliers + pts_size - p < best_inls) break;
}
return num_inliers;
};
// main RANSAC loop
for (int iters = 0; iters < max_iters; iters++) {
// find minimal sample: 3 points
min_sample[0] = rng.uniform(0, pts_size);
min_sample[1] = rng.uniform(0, pts_size);
min_sample[2] = rng.uniform(0, pts_size);
if (! estimate(min_sample, model))
continue;
int num_inliers = getInliers(model);
if (num_inliers > best_inls) {
// store so-far-the-best
std::vector<bool> best_inliers = inliers;
// do Local Optimization
for (int lo_iter = 0; lo_iter < max_lo_iters; lo_iter++) {
std::vector<int> inliers_idx; inliers_idx.reserve(max_lo_inliers);
randShuffle(random_pool);
for (int p : random_pool) {
if (best_inliers[p]) {
inliers_idx.emplace_back(p);
if ((int)inliers_idx.size() >= max_lo_inliers)
break;
}
}
if (! estimate(inliers_idx, lo_model))
continue;
int lo_inls = getInliers(lo_model);
if (best_inls < lo_inls) {
best_model = lo_model;
best_inls = lo_inls;
best_inliers = inliers;
}
}
if (best_inls < num_inliers) {
best_model = model;
best_inls = num_inliers;
}
// update max iters
// because points are quite noisy we need more iterations
const double max_hyp = 3 * log_conf / log(1 - pow(double(best_inls) / pts_size, 3));
if (! std::isinf(max_hyp) && max_hyp < max_iters)
max_iters = static_cast<int>(max_hyp);
}
}
getInliers(best_model);
return best_inls != 0;
};
labels = std::vector<int>(points3d.rows, 0);
Mat pts3d_plane_fit = points3d.clone();
// keep array of indices of points corresponding to original points3d
std::vector<int> to_orig_pts_arr(pts3d_plane_fit.rows);
for (int i = 0; i < (int) to_orig_pts_arr.size(); i++)
to_orig_pts_arr[i] = i;
for (int num_planes = 1; num_planes <= desired_num_planes; num_planes++) {
Vec4d model;
std::vector<bool> inl;
if (!plane_ransac(pts3d_plane_fit, thr_, conf_, max_iters_, model, inl))
break;
planes.emplace_back(model);
const int pts3d_size = pts3d_plane_fit.rows;
pts3d_plane_fit = Mat();
pts3d_plane_fit.reserve(points3d.rows);
int cnt = 0;
for (int p = 0; p < pts3d_size; p++) {
if (! inl[p]) {
// if point is not inlier to found plane - add it to next run
to_orig_pts_arr[cnt] = to_orig_pts_arr[p];
pts3d_plane_fit.push_back(points3d.row(to_orig_pts_arr[cnt]));
cnt++;
} else labels[to_orig_pts_arr[p]] = num_planes; // otherwise label this point
}
}
}
int main(int args, char** argv) {
std::string data_file, image_dir;
if (args < 3) {
CV_Error(Error::StsBadArg,
"Path to data file and directory to image files are missing!\nData file must have"
" format:\n--------------\n image_name_1\nimage_name_2\nk11 k12 k13\n0 k22 k23\n"
"0 0 1\n--------------\nIf image_name_{1,2} are not in the same directory as "
"the data file then add argument with directory to image files.\nFor example: "
"./essential_mat_reconstr essential_mat_data.txt ./");
} else {
data_file = argv[1];
image_dir = argv[2];
}
std::ifstream file(data_file, std::ios_base::in);
CV_CheckEQ((int)file.is_open(), 1, "Data file is not found!");
std::string filename1, filename2;
std::getline(file, filename1);
std::getline(file, filename2);
Mat image1 = imread(image_dir+filename1);
Mat image2 = imread(image_dir+filename2);
CV_CheckEQ((int)image1.empty(), 0, "Image 1 is not found!");
CV_CheckEQ((int)image2.empty(), 0, "Image 2 is not found!");
// read calibration
Matx33d K;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
file >> K(i,j);
file.close();
Mat descriptors1, descriptors2;
std::vector<KeyPoint> keypoints1, keypoints2;
// detect points with SIFT
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);
// filter keypoints with Lowe ratio test
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);
}
}
Mat inliers;
const int pts_size = (int) pts1.size();
const auto begin_time = std::chrono::steady_clock::now();
// fine essential matrix
const Mat E = findEssentialMat(pts1, pts2, Mat(K), RANSAC, 0.99, 1.0, inliers);
std::cout << "RANSAC essential matrix time " << std::chrono::duration_cast<std::chrono::microseconds>
(std::chrono::steady_clock::now() - begin_time).count() <<
"mcs.\nNumber of inliers " << countNonZero(inliers) << "\n";
Mat points1 = Mat((int)pts1.size(), 2, CV_64F, pts1.data());
Mat points2 = Mat((int)pts2.size(), 2, CV_64F, pts2.data());
points1 = points1.t(); points2 = points2.t();
std::cout << "Mean error to epipolar lines " <<
getError2EpipLines(K.inv().t() * E * K.inv(), points1, points2, inliers) << "\n";
// decompose essential into rotation and translation
Mat R1, R2, t;
decomposeEssentialMat(E, R1, R2, t);
// Create two relative pose
// P1 = K [ I | 0 ]
// P2 = K [R{1,2} | {+-}t]
Mat P1;
hconcat(K, Vec3d::zeros(), P1);
std::vector<Mat> P2s(4);
hconcat(K * R1, K * t, P2s[0]);
hconcat(K * R1, -K * t, P2s[1]);
hconcat(K * R2, K * t, P2s[2]);
hconcat(K * R2, -K * t, P2s[3]);
// find objects point by enumerating over 4 different projection matrices of second camera
// vector to keep object points
std::vector<std::vector<Vec3d>> obj_pts_per_cam(4);
// vector to keep indices of image points corresponding to object points
std::vector<std::vector<int>> img_idxs_per_cam(4);
int cam_idx = 0, best_cam_idx = 0, max_obj_pts = 0;
for (const auto &P2 : P2s) {
obj_pts_per_cam[cam_idx].reserve(pts_size);
img_idxs_per_cam[cam_idx].reserve(pts_size);
for (int i = 0; i < pts_size; i++) {
// process only inliers
if (! inliers.at<uchar>(i))
continue;
Vec4d obj_pt;
// find object point using triangulation
triangulatePoints(P1, P2, points1.col(i), points2.col(i), obj_pt);
obj_pt /= obj_pt(3); // normalize 4d point
if (obj_pt(2) > 0) { // check if projected point has positive depth
obj_pts_per_cam[cam_idx].emplace_back(Vec3d(obj_pt(0), obj_pt(1), obj_pt(2)));
img_idxs_per_cam[cam_idx].emplace_back(i);
}
}
if (max_obj_pts < (int) obj_pts_per_cam[cam_idx].size()) {
max_obj_pts = (int) obj_pts_per_cam[cam_idx].size();
best_cam_idx = cam_idx;
}
cam_idx++;
}
std::cout << "Number of object points " << max_obj_pts << "\n";
const int circle_sz = 7;
// draw image points that are inliers on two images
std::vector<int> labels;
std::vector<Vec4d> planes;
getPlanes (obj_pts_per_cam[best_cam_idx], labels, planes, 4, 0.002, 0.99, 10000);
const int num_found_planes = (int) planes.size();
RNG rng;
std::vector<Scalar> plane_colors (num_found_planes);
for (int pl = 0; pl < num_found_planes; pl++)
plane_colors[pl] = Scalar (rng.uniform(0,256), rng.uniform(0,256), rng.uniform(0,256));
for (int obj_pt = 0; obj_pt < max_obj_pts; obj_pt++) {
const int pt = img_idxs_per_cam[best_cam_idx][obj_pt];
if (labels[obj_pt] > 0) { // plot plane points
circle (image1, pts1[pt], circle_sz, plane_colors[labels[obj_pt]-1], -1);
circle (image2, pts2[pt], circle_sz, plane_colors[labels[obj_pt]-1], -1);
} else { // plot inliers
circle (image1, pts1[pt], circle_sz, Scalar(0,0,0), -1);
circle (image2, pts2[pt], circle_sz, Scalar(0,0,0), -1);
}
}
// 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("image 1-2", image1);
imwrite("planes.png", image1);
waitKey(0);
}

View File

@ -0,0 +1,26 @@
# cmake needs this line
cmake_minimum_required(VERSION 3.1)
# Define project name
project(opencv_example_project)
# Find OpenCV, you may need to set OpenCV_DIR variable
# to the absolute path to the directory containing OpenCVConfig.cmake file
# via the command line or GUI
find_package(OpenCV REQUIRED)
# If the package has been found, several variables will
# be set, you can find the full list with descriptions
# in the OpenCVConfig.cmake file.
# Print some message showing some of them
message(STATUS "OpenCV library status:")
message(STATUS " config: ${OpenCV_DIR}")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
# Declare the executable target built from your sources
add_executable(opencv_example example.cpp)
# Link your application with OpenCV libraries
target_link_libraries(opencv_example PRIVATE ${OpenCV_LIBS})

View File

@ -0,0 +1,12 @@
CXX ?= g++
CXXFLAGS += -c -Wall $(shell pkg-config --cflags opencv)
LDFLAGS += $(shell pkg-config --libs --static opencv)
all: opencv_example
opencv_example: example.o; $(CXX) $< -o $@ $(LDFLAGS)
%.o: %.cpp; $(CXX) $< -o $@ $(CXXFLAGS)
clean: ; rm -f example.o opencv_example

View File

@ -0,0 +1,50 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void drawText(Mat & image);
int main()
{
cout << "Built with OpenCV " << CV_VERSION << endl;
Mat image;
VideoCapture capture;
capture.open(0);
if(capture.isOpened())
{
cout << "Capture is opened" << endl;
for(;;)
{
capture >> image;
if(image.empty())
break;
drawText(image);
imshow("Sample", image);
if(waitKey(10) >= 0)
break;
}
}
else
{
cout << "No capture" << endl;
image = Mat::zeros(480, 640, CV_8UC1);
drawText(image);
imshow("Sample", image);
waitKey(0);
}
return 0;
}
void drawText(Mat & image)
{
putText(image, "Hello OpenCV",
Point(20, 50),
FONT_HERSHEY_COMPLEX, 1, // font face and scale
Scalar(255, 255, 255), // white
1, LINE_AA); // line thickness and type
}

View File

@ -0,0 +1,257 @@
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(const char** argv)
{
cout << "\nThis program demonstrates the use of cv::CascadeClassifier class to detect objects (Face + eyes). You can use Haar or LBP features.\n"
"This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
"It's most known use is for faces.\n"
"Usage:\n"
<< argv[0]
<< " [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
" [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
" [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
" [--try-flip]\n"
" [filename|camera_index]\n\n"
"example:\n"
<< argv[0]
<< " --cascade=\"data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"data/haarcascades/haarcascade_eye_tree_eyeglasses.xml\" --scale=1.3\n\n"
"During execution:\n\tHit any key to quit.\n"
"\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip );
string cascadeName;
string nestedCascadeName;
int main( int argc, const char** argv )
{
VideoCapture capture;
Mat frame, image;
string inputName;
bool tryflip;
CascadeClassifier cascade, nestedCascade;
double scale;
cv::CommandLineParser parser(argc, argv,
"{help h||}"
"{cascade|data/haarcascades/haarcascade_frontalface_alt.xml|}"
"{nested-cascade|data/haarcascades/haarcascade_eye_tree_eyeglasses.xml|}"
"{scale|1|}{try-flip||}{@filename||}"
);
if (parser.has("help"))
{
help(argv);
return 0;
}
cascadeName = parser.get<string>("cascade");
nestedCascadeName = parser.get<string>("nested-cascade");
scale = parser.get<double>("scale");
if (scale < 1)
scale = 1;
tryflip = parser.has("try-flip");
inputName = parser.get<string>("@filename");
if (!parser.check())
{
parser.printErrors();
return 0;
}
if (!nestedCascade.load(samples::findFileOrKeep(nestedCascadeName)))
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
if (!cascade.load(samples::findFile(cascadeName)))
{
cerr << "ERROR: Could not load classifier cascade" << endl;
help(argv);
return -1;
}
if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
{
int camera = inputName.empty() ? 0 : inputName[0] - '0';
if(!capture.open(camera))
{
cout << "Capture from camera #" << camera << " didn't work" << endl;
return 1;
}
}
else if (!inputName.empty())
{
image = imread(samples::findFileOrKeep(inputName), IMREAD_COLOR);
if (image.empty())
{
if (!capture.open(samples::findFileOrKeep(inputName)))
{
cout << "Could not read " << inputName << endl;
return 1;
}
}
}
else
{
image = imread(samples::findFile("lena.jpg"), IMREAD_COLOR);
if (image.empty())
{
cout << "Couldn't read lena.jpg" << endl;
return 1;
}
}
if( capture.isOpened() )
{
cout << "Video capturing has been started ..." << endl;
for(;;)
{
capture >> frame;
if( frame.empty() )
break;
Mat frame1 = frame.clone();
detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
char c = (char)waitKey(10);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
else
{
cout << "Detecting face(s) in " << inputName << endl;
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
waitKey(0);
}
else if( !inputName.empty() )
{
/* assume it is a text file containing the
list of the image filenames to be processed - one per line */
FILE* f = fopen( inputName.c_str(), "rt" );
if( f )
{
char buf[1000+1];
while( fgets( buf, 1000, f ) )
{
int len = (int)strlen(buf);
while( len > 0 && isspace(buf[len-1]) )
len--;
buf[len] = '\0';
cout << "file " << buf << endl;
image = imread( buf, 1 );
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
char c = (char)waitKey(0);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
else
{
cerr << "Aw snap, couldn't read image " << buf << endl;
}
}
fclose(f);
}
}
}
return 0;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip )
{
double t = 0;
vector<Rect> faces, faces2;
const static Scalar colors[] =
{
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)
};
Mat gray, smallImg;
cvtColor( img, gray, COLOR_BGR2GRAY );
double fx = 1 / scale;
resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
equalizeHist( smallImg, smallImg );
t = (double)getTickCount();
cascade.detectMultiScale( smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
if( tryflip )
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale( smallImg, faces2,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
{
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
}
}
t = (double)getTickCount() - t;
printf( "detection time = %g ms\n", t*1000/getTickFrequency());
for ( size_t i = 0; i < faces.size(); i++ )
{
Rect r = faces[i];
Mat smallImgROI;
vector<Rect> nestedObjects;
Point center;
Scalar color = colors[i%8];
int radius;
double aspect_ratio = (double)r.width/r.height;
if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
{
center.x = cvRound((r.x + r.width*0.5)*scale);
center.y = cvRound((r.y + r.height*0.5)*scale);
radius = cvRound((r.width + r.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
else
rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
color, 3, 8, 0);
if( nestedCascade.empty() )
continue;
smallImgROI = smallImg( r );
nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
//|CASCADE_DO_CANNY_PRUNING
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for ( size_t j = 0; j < nestedObjects.size(); j++ )
{
Rect nr = nestedObjects[j];
center.x = cvRound((r.x + nr.x + nr.width*0.5)*scale);
center.y = cvRound((r.y + nr.y + nr.height*0.5)*scale);
radius = cvRound((nr.width + nr.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
}
imshow( "result", img );
}

View File

@ -0,0 +1,215 @@
/*
* Author: Samyak Datta (datta[dot]samyak[at]gmail.com)
*
* A program to detect facial feature points using
* Haarcascade classifiers for face, eyes, nose and mouth
*
*/
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;
// Functions for facial feature detection
static void help(char** argv);
static void detectFaces(Mat&, vector<Rect_<int> >&, string);
static void detectEyes(Mat&, vector<Rect_<int> >&, string);
static void detectNose(Mat&, vector<Rect_<int> >&, string);
static void detectMouth(Mat&, vector<Rect_<int> >&, string);
static void detectFacialFeaures(Mat&, const vector<Rect_<int> >, string, string, string);
string input_image_path;
string face_cascade_path, eye_cascade_path, nose_cascade_path, mouth_cascade_path;
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv,
"{eyes||}{nose||}{mouth||}{help h||}{@image||}{@facexml||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
input_image_path = parser.get<string>("@image");
face_cascade_path = parser.get<string>("@facexml");
eye_cascade_path = parser.has("eyes") ? parser.get<string>("eyes") : "";
nose_cascade_path = parser.has("nose") ? parser.get<string>("nose") : "";
mouth_cascade_path = parser.has("mouth") ? parser.get<string>("mouth") : "";
if (input_image_path.empty() || face_cascade_path.empty())
{
cout << "IMAGE or FACE_CASCADE are not specified";
return 1;
}
// Load image and cascade classifier files
Mat image;
image = imread(samples::findFile(input_image_path));
// Detect faces and facial features
vector<Rect_<int> > faces;
detectFaces(image, faces, face_cascade_path);
detectFacialFeaures(image, faces, eye_cascade_path, nose_cascade_path, mouth_cascade_path);
imshow("Result", image);
waitKey(0);
return 0;
}
static void help(char** argv)
{
cout << "\nThis file demonstrates facial feature points detection using Haarcascade classifiers.\n"
"The program detects a face and eyes, nose and mouth inside the face."
"The code has been tested on the Japanese Female Facial Expression (JAFFE) database and found"
"to give reasonably accurate results. \n";
cout << "\nUSAGE: " << argv[0] << " [IMAGE] [FACE_CASCADE] [OPTIONS]\n"
"IMAGE\n\tPath to the image of a face taken as input.\n"
"FACE_CASCSDE\n\t Path to a haarcascade classifier for face detection.\n"
"OPTIONS: \nThere are 3 options available which are described in detail. There must be a "
"space between the option and it's argument (All three options accept arguments).\n"
"\t-eyes=<eyes_cascade> : Specify the haarcascade classifier for eye detection.\n"
"\t-nose=<nose_cascade> : Specify the haarcascade classifier for nose detection.\n"
"\t-mouth=<mouth-cascade> : Specify the haarcascade classifier for mouth detection.\n";
cout << "EXAMPLE:\n"
"(1) " << argv[0] << " image.jpg face.xml -eyes=eyes.xml -mouth=mouth.xml\n"
"\tThis will detect the face, eyes and mouth in image.jpg.\n"
"(2) " << argv[0] << " image.jpg face.xml -nose=nose.xml\n"
"\tThis will detect the face and nose in image.jpg.\n"
"(3) " << argv[0] << " image.jpg face.xml\n"
"\tThis will detect only the face in image.jpg.\n";
cout << " \n\nThe classifiers for face and eyes can be downloaded from : "
" \nhttps://github.com/opencv/opencv/tree/master/data/haarcascades";
cout << "\n\nThe classifiers for nose and mouth can be downloaded from : "
" \nhttps://github.com/opencv/opencv_contrib/tree/master/modules/face/data/cascades\n";
}
static void detectFaces(Mat& img, vector<Rect_<int> >& faces, string cascade_path)
{
CascadeClassifier face_cascade;
face_cascade.load(samples::findFile(cascade_path));
if (!face_cascade.empty())
face_cascade.detectMultiScale(img, faces, 1.15, 3, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectFacialFeaures(Mat& img, const vector<Rect_<int> > faces, string eye_cascade,
string nose_cascade, string mouth_cascade)
{
for(unsigned int i = 0; i < faces.size(); ++i)
{
// Mark the bounding box enclosing the face
Rect face = faces[i];
rectangle(img, Point(face.x, face.y), Point(face.x+face.width, face.y+face.height),
Scalar(255, 0, 0), 1, 4);
// Eyes, nose and mouth will be detected inside the face (region of interest)
Mat ROI = img(Rect(face.x, face.y, face.width, face.height));
// Check if all features (eyes, nose and mouth) are being detected
bool is_full_detection = false;
if( (!eye_cascade.empty()) && (!nose_cascade.empty()) && (!mouth_cascade.empty()) )
is_full_detection = true;
// Detect eyes if classifier provided by the user
if(!eye_cascade.empty())
{
vector<Rect_<int> > eyes;
detectEyes(ROI, eyes, eye_cascade);
// Mark points corresponding to the centre of the eyes
for(unsigned int j = 0; j < eyes.size(); ++j)
{
Rect e = eyes[j];
circle(ROI, Point(e.x+e.width/2, e.y+e.height/2), 3, Scalar(0, 255, 0), -1, 8);
/* rectangle(ROI, Point(e.x, e.y), Point(e.x+e.width, e.y+e.height),
Scalar(0, 255, 0), 1, 4); */
}
}
// Detect nose if classifier provided by the user
double nose_center_height = 0.0;
if(!nose_cascade.empty())
{
vector<Rect_<int> > nose;
detectNose(ROI, nose, nose_cascade);
// Mark points corresponding to the centre (tip) of the nose
for(unsigned int j = 0; j < nose.size(); ++j)
{
Rect n = nose[j];
circle(ROI, Point(n.x+n.width/2, n.y+n.height/2), 3, Scalar(0, 255, 0), -1, 8);
nose_center_height = (n.y + n.height/2);
}
}
// Detect mouth if classifier provided by the user
double mouth_center_height = 0.0;
if(!mouth_cascade.empty())
{
vector<Rect_<int> > mouth;
detectMouth(ROI, mouth, mouth_cascade);
for(unsigned int j = 0; j < mouth.size(); ++j)
{
Rect m = mouth[j];
mouth_center_height = (m.y + m.height/2);
// The mouth should lie below the nose
if( (is_full_detection) && (mouth_center_height > nose_center_height) )
{
rectangle(ROI, Point(m.x, m.y), Point(m.x+m.width, m.y+m.height), Scalar(0, 255, 0), 1, 4);
}
else if( (is_full_detection) && (mouth_center_height <= nose_center_height) )
continue;
else
rectangle(ROI, Point(m.x, m.y), Point(m.x+m.width, m.y+m.height), Scalar(0, 255, 0), 1, 4);
}
}
}
return;
}
static void detectEyes(Mat& img, vector<Rect_<int> >& eyes, string cascade_path)
{
CascadeClassifier eyes_cascade;
eyes_cascade.load(samples::findFile(cascade_path, !cascade_path.empty()));
if (!eyes_cascade.empty())
eyes_cascade.detectMultiScale(img, eyes, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectNose(Mat& img, vector<Rect_<int> >& nose, string cascade_path)
{
CascadeClassifier nose_cascade;
nose_cascade.load(samples::findFile(cascade_path, !cascade_path.empty()));
if (!nose_cascade.empty())
nose_cascade.detectMultiScale(img, nose, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}
static void detectMouth(Mat& img, vector<Rect_<int> >& mouth, string cascade_path)
{
CascadeClassifier mouth_cascade;
mouth_cascade.load(samples::findFile(cascade_path, !cascade_path.empty()));
if (!mouth_cascade.empty())
mouth_cascade.detectMultiScale(img, mouth, 1.20, 5, 0|CASCADE_SCALE_IMAGE, Size(30, 30));
return;
}

View File

@ -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", "User defined (random)" };
static void TrackColorMap(int x, void *r)
{
ParamColorMap *p = (ParamColorMap*)r;
Mat dst;
p->iColormap= x;
if (x == COLORMAP_TURBO + 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,&p.iColormap,1,TrackColorMap,(void*)&p);
setTrackbarMin("colormap", winName, COLORMAP_AUTUMN);
setTrackbarMax("colormap", winName, COLORMAP_TURBO+1);
setTrackbarPos("colormap", winName, -1);
TrackColorMap(0, (void*)&p);
cout << "Press a key to exit" << endl;
waitKey(0);
return 0;
}

View File

@ -0,0 +1,68 @@
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help(char** argv)
{
cout <<
"\nThis program demonstrates dense optical flow algorithm by Gunnar Farneback\n"
"Mainly the function: calcOpticalFlowFarneback()\n"
"Call:\n"
<< argv[0]
<< "This reads from video camera 0\n" << endl;
}
static void drawOptFlowMap(const Mat& flow, Mat& cflowmap, int step,
double, const Scalar& color)
{
for(int y = 0; y < cflowmap.rows; y += step)
for(int x = 0; x < cflowmap.cols; x += step)
{
const Point2f& fxy = flow.at<Point2f>(y, x);
line(cflowmap, Point(x,y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)),
color);
circle(cflowmap, Point(x,y), 2, color, -1);
}
}
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv, "{help h||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
VideoCapture cap(0);
help(argv);
if( !cap.isOpened() )
return -1;
Mat flow, cflow, frame;
UMat gray, prevgray, uflow;
namedWindow("flow", 1);
for(;;)
{
cap >> frame;
cvtColor(frame, gray, COLOR_BGR2GRAY);
if( !prevgray.empty() )
{
calcOpticalFlowFarneback(prevgray, gray, uflow, 0.5, 3, 15, 3, 5, 1.2, 0);
cvtColor(prevgray, cflow, COLOR_GRAY2BGR);
uflow.copyTo(flow);
drawOptFlowMap(flow, cflow, 16, 1.5, Scalar(0, 255, 0));
imshow("flow", cflow);
}
if(waitKey(30)>=0)
break;
std::swap(prevgray, gray);
}
return 0;
}

View File

@ -0,0 +1,177 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help(char** argv)
{
cout << "\nThis program demonstrated the floodFill() function\n"
"Call:\n"
<< argv[0]
<< " [image_name -- Default: fruits.jpg]\n" << endl;
cout << "Hot keys: \n"
"\tESC - quit the program\n"
"\tc - switch color/grayscale mode\n"
"\tm - switch mask mode\n"
"\tr - restore the original image\n"
"\ts - use null-range floodfill\n"
"\tf - use gradient floodfill with fixed(absolute) range\n"
"\tg - use gradient floodfill with floating(relative) range\n"
"\t4 - use 4-connectivity mode\n"
"\t8 - use 8-connectivity mode\n" << endl;
}
Mat image0, image, gray, mask;
int ffillMode = 1;
int loDiff = 20, upDiff = 20;
int connectivity = 4;
int isColor = true;
bool useMask = false;
int newMaskVal = 255;
static void onMouse( int event, int x, int y, int, void* )
{
if( event != EVENT_LBUTTONDOWN )
return;
Point seed = Point(x,y);
int lo = ffillMode == 0 ? 0 : loDiff;
int up = ffillMode == 0 ? 0 : upDiff;
int flags = connectivity + (newMaskVal << 8) +
(ffillMode == 1 ? FLOODFILL_FIXED_RANGE : 0);
int b = (unsigned)theRNG() & 255;
int g = (unsigned)theRNG() & 255;
int r = (unsigned)theRNG() & 255;
Rect ccomp;
Scalar newVal = isColor ? Scalar(b, g, r) : Scalar(r*0.299 + g*0.587 + b*0.114);
Mat dst = isColor ? image : gray;
int area;
if( useMask )
{
threshold(mask, mask, 1, 128, THRESH_BINARY);
area = floodFill(dst, mask, seed, newVal, &ccomp, Scalar(lo, lo, lo),
Scalar(up, up, up), flags);
imshow( "mask", mask );
}
else
{
area = floodFill(dst, seed, newVal, &ccomp, Scalar(lo, lo, lo),
Scalar(up, up, up), flags);
}
imshow("image", dst);
cout << area << " pixels were repainted\n";
}
int main( int argc, char** argv )
{
cv::CommandLineParser parser (argc, argv,
"{help h | | show help message}{@image|fruits.jpg| input image}"
);
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
string filename = parser.get<string>("@image");
image0 = imread(samples::findFile(filename), 1);
if( image0.empty() )
{
cout << "Image empty\n";
parser.printMessage();
return 0;
}
help(argv);
image0.copyTo(image);
cvtColor(image0, gray, COLOR_BGR2GRAY);
mask.create(image0.rows+2, image0.cols+2, CV_8UC1);
namedWindow( "image", 0 );
createTrackbar( "lo_diff", "image", &loDiff, 255, 0 );
createTrackbar( "up_diff", "image", &upDiff, 255, 0 );
setMouseCallback( "image", onMouse, 0 );
for(;;)
{
imshow("image", isColor ? image : gray);
char c = (char)waitKey(0);
if( c == 27 )
{
cout << "Exiting ...\n";
break;
}
switch( c )
{
case 'c':
if( isColor )
{
cout << "Grayscale mode is set\n";
cvtColor(image0, gray, COLOR_BGR2GRAY);
mask = Scalar::all(0);
isColor = false;
}
else
{
cout << "Color mode is set\n";
image0.copyTo(image);
mask = Scalar::all(0);
isColor = true;
}
break;
case 'm':
if( useMask )
{
destroyWindow( "mask" );
useMask = false;
}
else
{
namedWindow( "mask", 0 );
mask = Scalar::all(0);
imshow("mask", mask);
useMask = true;
}
break;
case 'r':
cout << "Original image is restored\n";
image0.copyTo(image);
cvtColor(image, gray, COLOR_BGR2GRAY);
mask = Scalar::all(0);
break;
case 's':
cout << "Simple floodfill mode is set\n";
ffillMode = 0;
break;
case 'f':
cout << "Fixed Range floodfill mode is set\n";
ffillMode = 1;
break;
case 'g':
cout << "Gradient (floating range) floodfill mode is set\n";
ffillMode = 2;
break;
case '4':
cout << "4-connectivity mode is set\n";
connectivity = 4;
break;
case '8':
cout << "8-connectivity mode is set\n";
connectivity = 8;
break;
}
}
return 0;
}

View File

@ -0,0 +1,193 @@
/*
* filestorage_sample demonstrate the usage of the opencv serialization functionality
*/
#include "opencv2/core.hpp"
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
using std::cerr;
using std::ostream;
using namespace cv;
static void help(char** av)
{
cout << "\nfilestorage_sample demonstrate the usage of the opencv serialization functionality.\n"
<< "usage:\n"
<< av[0] << " outputfile.yml.gz\n"
<< "\n outputfile above can have many different extensions, see below."
<< "\nThis program demonstrates the use of FileStorage for serialization, that is in use << and >> in OpenCV\n"
<< "For example, how to create a class and have it serialize, but also how to use it to read and write matrices.\n"
<< "FileStorage allows you to serialize to various formats specified by the file end type."
<< "\nYou should try using different file extensions.(e.g. yaml yml xml xml.gz yaml.gz etc...)\n" << endl;
}
struct MyData
{
MyData() :
A(0), X(0), id()
{
}
explicit MyData(int) :
A(97), X(CV_PI), id("mydata1234")
{
}
int A;
double X;
string id;
void write(FileStorage& fs) const //Write serialization for this class
{
fs << "{" << "A" << A << "X" << X << "id" << id << "}";
}
void read(const FileNode& node) //Read serialization for this class
{
A = (int)node["A"];
X = (double)node["X"];
id = (string)node["id"];
}
};
//These write and read functions must exist as per the inline functions in operations.hpp
static void write(FileStorage& fs, const std::string&, const MyData& x){
x.write(fs);
}
static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()){
if(node.empty())
x = default_value;
else
x.read(node);
}
static ostream& operator<<(ostream& out, const MyData& m){
out << "{ id = " << m.id << ", ";
out << "X = " << m.X << ", ";
out << "A = " << m.A << "}";
return out;
}
int main(int ac, char** av)
{
cv::CommandLineParser parser(ac, av,
"{@input||}{help h ||}"
);
if (parser.has("help"))
{
help(av);
return 0;
}
string filename = parser.get<string>("@input");
if (filename.empty())
{
help(av);
return 1;
}
//write
{
FileStorage fs(filename, FileStorage::WRITE);
cout << "writing images\n";
fs << "images" << "[";
fs << "image1.jpg" << "myfi.png" << "baboon.jpg";
cout << "image1.jpg" << " myfi.png" << " baboon.jpg" << endl;
fs << "]";
cout << "writing mats\n";
Mat R =Mat_<double>::eye(3, 3),T = Mat_<double>::zeros(3, 1);
cout << "R = " << R << "\n";
cout << "T = " << T << "\n";
fs << "R" << R;
fs << "T" << T;
cout << "writing MyData struct\n";
MyData m(1);
fs << "mdata" << m;
cout << m << endl;
}
//read
{
FileStorage fs(filename, FileStorage::READ);
if (!fs.isOpened())
{
cerr << "failed to open " << filename << endl;
help(av);
return 1;
}
FileNode n = fs["images"];
if (n.type() != FileNode::SEQ)
{
cerr << "images is not a sequence! FAIL" << endl;
return 1;
}
cout << "reading images\n";
FileNodeIterator it = n.begin(), it_end = n.end();
for (; it != it_end; ++it)
{
cout << (string)*it << "\n";
}
Mat R, T;
cout << "reading R and T" << endl;
fs["R"] >> R;
fs["T"] >> T;
cout << "R = " << R << "\n";
cout << "T = " << T << endl;
MyData m;
fs["mdata"] >> m;
cout << "read mdata\n";
cout << m << endl;
cout << "attempting to read mdata_b\n"; //Show default behavior for empty matrix
fs["mdata_b"] >> m;
cout << "read mdata_b\n";
cout << m << endl;
}
cout << "Try opening " << filename << " to see the serialized data." << endl << endl;
//read from string
{
cout << "Read data from string\n";
string dataString =
"%YAML:1.0\n"
"mdata:\n"
" A: 97\n"
" X: 3.1415926535897931e+00\n"
" id: mydata1234\n";
MyData m;
FileStorage fs(dataString, FileStorage::READ | FileStorage::MEMORY);
cout << "attempting to read mdata_b from string\n"; //Show default behavior for empty matrix
fs["mdata"] >> m;
cout << "read mdata\n";
cout << m << endl;
}
//write to string
{
cout << "Write data to string\n";
FileStorage fs(filename, FileStorage::WRITE | FileStorage::MEMORY | FileStorage::FORMAT_YAML);
cout << "writing MyData struct\n";
MyData m(1);
fs << "mdata" << m;
cout << m << endl;
string createdString = fs.releaseAndGetString();
cout << "Created string:\n" << createdString << "\n";
}
return 0;
}

View File

@ -0,0 +1,315 @@
/********************************************************************************
*
*
* This program is demonstration for ellipse fitting. Program finds
* contours and approximate it by ellipses using three methods.
* 1: OpenCV's original method fitEllipse which implements Fitzgibbon 1995 method.
* 2: The Approximate Mean Square (AMS) method fitEllipseAMS proposed by Taubin 1991
* 3: The Direct least square (Direct) method fitEllipseDirect proposed by Fitzgibbon1999.
*
* Trackbar specify threshold parameter.
*
* White lines is contours/input points and the true ellipse used to generate the data.
* 1: Blue lines is fitting ellipses using openCV's original method.
* 2: Green lines is fitting ellipses using the AMS method.
* 3: Red lines is fitting ellipses using the Direct method.
*
*
* Original Author: Denis Burenkov
* AMS and Direct Methods Author: Jasper Shemilt
*
*
********************************************************************************/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
class canvas{
public:
bool setupQ;
cv::Point origin;
cv::Point corner;
int minDims,maxDims;
double scale;
int rows, cols;
cv::Mat img;
void init(int minD, int maxD){
// Initialise the canvas with minimum and maximum rows and column sizes.
minDims = minD; maxDims = maxD;
origin = cv::Point(0,0);
corner = cv::Point(0,0);
scale = 1.0;
rows = 0;
cols = 0;
setupQ = false;
}
void stretch(cv::Point2f min, cv::Point2f max){
// Stretch the canvas to include the points min and max.
if(setupQ){
if(corner.x < max.x){corner.x = (int)(max.x + 1.0);};
if(corner.y < max.y){corner.y = (int)(max.y + 1.0);};
if(origin.x > min.x){origin.x = (int) min.x;};
if(origin.y > min.y){origin.y = (int) min.y;};
} else {
origin = cv::Point((int)min.x, (int)min.y);
corner = cv::Point((int)(max.x + 1.0), (int)(max.y + 1.0));
}
int c = (int)(scale*((corner.x + 1.0) - origin.x));
if(c<minDims){
scale = scale * (double)minDims/(double)c;
} else {
if(c>maxDims){
scale = scale * (double)maxDims/(double)c;
}
}
int r = (int)(scale*((corner.y + 1.0) - origin.y));
if(r<minDims){
scale = scale * (double)minDims/(double)r;
} else {
if(r>maxDims){
scale = scale * (double)maxDims/(double)r;
}
}
cols = (int)(scale*((corner.x + 1.0) - origin.x));
rows = (int)(scale*((corner.y + 1.0) - origin.y));
setupQ = true;
}
void stretch(vector<Point2f> pts)
{ // Stretch the canvas so all the points pts are on the canvas.
cv::Point2f min = pts[0];
cv::Point2f max = pts[0];
for(size_t i=1; i < pts.size(); i++){
Point2f pnt = pts[i];
if(max.x < pnt.x){max.x = pnt.x;};
if(max.y < pnt.y){max.y = pnt.y;};
if(min.x > pnt.x){min.x = pnt.x;};
if(min.y > pnt.y){min.y = pnt.y;};
};
stretch(min, max);
}
void stretch(cv::RotatedRect box)
{ // Stretch the canvas so that the rectangle box is on the canvas.
cv::Point2f min = box.center;
cv::Point2f max = box.center;
cv::Point2f vtx[4];
box.points(vtx);
for( int i = 0; i < 4; i++ ){
cv::Point2f pnt = vtx[i];
if(max.x < pnt.x){max.x = pnt.x;};
if(max.y < pnt.y){max.y = pnt.y;};
if(min.x > pnt.x){min.x = pnt.x;};
if(min.y > pnt.y){min.y = pnt.y;};
}
stretch(min, max);
}
void drawEllipseWithBox(cv::RotatedRect box, cv::Scalar color, int lineThickness)
{
if(img.empty()){
stretch(box);
img = cv::Mat::zeros(rows,cols,CV_8UC3);
}
box.center = scale * cv::Point2f(box.center.x - origin.x, box.center.y - origin.y);
box.size.width = (float)(scale * box.size.width);
box.size.height = (float)(scale * box.size.height);
ellipse(img, box, color, lineThickness, LINE_AA);
Point2f vtx[4];
box.points(vtx);
for( int j = 0; j < 4; j++ ){
line(img, vtx[j], vtx[(j+1)%4], color, lineThickness, LINE_AA);
}
}
void drawPoints(vector<Point2f> pts, cv::Scalar color)
{
if(img.empty()){
stretch(pts);
img = cv::Mat::zeros(rows,cols,CV_8UC3);
}
for(size_t i=0; i < pts.size(); i++){
Point2f pnt = scale * cv::Point2f(pts[i].x - origin.x, pts[i].y - origin.y);
img.at<cv::Vec3b>(int(pnt.y), int(pnt.x))[0] = (uchar)color[0];
img.at<cv::Vec3b>(int(pnt.y), int(pnt.x))[1] = (uchar)color[1];
img.at<cv::Vec3b>(int(pnt.y), int(pnt.x))[2] = (uchar)color[2];
};
}
void drawLabels( std::vector<std::string> text, std::vector<cv::Scalar> colors)
{
if(img.empty()){
img = cv::Mat::zeros(rows,cols,CV_8UC3);
}
int vPos = 0;
for (size_t i=0; i < text.size(); i++) {
cv::Scalar color = colors[i];
std::string txt = text[i];
Size textsize = getTextSize(txt, FONT_HERSHEY_COMPLEX, 1, 1, 0);
vPos += (int)(1.3 * textsize.height);
Point org((img.cols - textsize.width), vPos);
cv::putText(img, txt, org, FONT_HERSHEY_COMPLEX, 1, color, 1, LINE_8);
}
}
};
static void help(char** argv)
{
cout << "\nThis program is demonstration for ellipse fitting. The program finds\n"
"contours and approximate it by ellipses. Three methods are used to find the \n"
"elliptical fits: fitEllipse, fitEllipseAMS and fitEllipseDirect.\n"
"Call:\n"
<< argv[0] << " [image_name -- Default ellipses.jpg]\n" << endl;
}
int sliderPos = 70;
Mat image;
bool fitEllipseQ, fitEllipseAMSQ, fitEllipseDirectQ;
cv::Scalar fitEllipseColor = Scalar(255, 0, 0);
cv::Scalar fitEllipseAMSColor = Scalar( 0,255, 0);
cv::Scalar fitEllipseDirectColor = Scalar( 0, 0,255);
cv::Scalar fitEllipseTrueColor = Scalar(255,255,255);
void processImage(int, void*);
int main( int argc, char** argv )
{
fitEllipseQ = true;
fitEllipseAMSQ = true;
fitEllipseDirectQ = true;
cv::CommandLineParser parser(argc, argv,"{help h||}{@image|ellipses.jpg|}");
if (parser.has("help"))
{
help(argv);
return 0;
}
string filename = parser.get<string>("@image");
image = imread(samples::findFile(filename), 0);
if( image.empty() )
{
cout << "Couldn't open image " << filename << "\n";
return 0;
}
imshow("source", image);
namedWindow("result", WINDOW_NORMAL );
// Create toolbars. HighGUI use.
createTrackbar( "threshold", "result", &sliderPos, 255, processImage );
processImage(0, 0);
// Wait for a key stroke; the same function arranges events processing
waitKey();
return 0;
}
// Define trackbar callback function. This function finds contours,
// draws them, and approximates by ellipses.
void processImage(int /*h*/, void*)
{
RotatedRect box, boxAMS, boxDirect;
vector<vector<Point> > contours;
Mat bimage = image >= sliderPos;
findContours(bimage, contours, RETR_LIST, CHAIN_APPROX_NONE);
canvas paper;
paper.init(int(0.8*MIN(bimage.rows, bimage.cols)), int(1.2*MAX(bimage.rows, bimage.cols)));
paper.stretch(cv::Point2f(0.0f, 0.0f), cv::Point2f((float)(bimage.cols+2.0), (float)(bimage.rows+2.0)));
std::vector<std::string> text;
std::vector<cv::Scalar> color;
if (fitEllipseQ) {
text.push_back("OpenCV");
color.push_back(fitEllipseColor);
}
if (fitEllipseAMSQ) {
text.push_back("AMS");
color.push_back(fitEllipseAMSColor);
}
if (fitEllipseDirectQ) {
text.push_back("Direct");
color.push_back(fitEllipseDirectColor);
}
paper.drawLabels(text, color);
int margin = 2;
vector< vector<Point2f> > points;
for(size_t i = 0; i < contours.size(); i++)
{
size_t count = contours[i].size();
if( count < 6 )
continue;
Mat pointsf;
Mat(contours[i]).convertTo(pointsf, CV_32F);
vector<Point2f>pts;
for (int j = 0; j < pointsf.rows; j++) {
Point2f pnt = Point2f(pointsf.at<float>(j,0), pointsf.at<float>(j,1));
if ((pnt.x > margin && pnt.y > margin && pnt.x < bimage.cols-margin && pnt.y < bimage.rows-margin)) {
if(j%20==0){
pts.push_back(pnt);
}
}
}
points.push_back(pts);
}
for(size_t i = 0; i < points.size(); i++)
{
vector<Point2f> pts = points[i];
if (pts.size()<=5) {
continue;
}
if (fitEllipseQ) {
box = fitEllipse(pts);
if( MAX(box.size.width, box.size.height) > MIN(box.size.width, box.size.height)*30 ||
MAX(box.size.width, box.size.height) <= 0 ||
MIN(box.size.width, box.size.height) <= 0){continue;};
}
if (fitEllipseAMSQ) {
boxAMS = fitEllipseAMS(pts);
if( MAX(boxAMS.size.width, boxAMS.size.height) > MIN(boxAMS.size.width, boxAMS.size.height)*30 ||
MAX(box.size.width, box.size.height) <= 0 ||
MIN(box.size.width, box.size.height) <= 0){continue;};
}
if (fitEllipseDirectQ) {
boxDirect = fitEllipseDirect(pts);
if( MAX(boxDirect.size.width, boxDirect.size.height) > MIN(boxDirect.size.width, boxDirect.size.height)*30 ||
MAX(box.size.width, box.size.height) <= 0 ||
MIN(box.size.width, box.size.height) <= 0 ){continue;};
}
if (fitEllipseQ) {
paper.drawEllipseWithBox(box, fitEllipseColor, 3);
}
if (fitEllipseAMSQ) {
paper.drawEllipseWithBox(boxAMS, fitEllipseAMSColor, 2);
}
if (fitEllipseDirectQ) {
paper.drawEllipseWithBox(boxDirect, fitEllipseDirectColor, 1);
}
paper.drawPoints(pts, cv::Scalar(255,255,255));
}
imshow("result", paper.img);
}

View File

@ -0,0 +1,250 @@
// flann_search_dataset.cpp
// Naive program to search a query picture in a dataset illustrating usage of FLANN
#include <iostream>
#include <vector>
#include "opencv2/core.hpp"
#include "opencv2/core/utils/filesystem.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/flann.hpp"
using namespace cv;
using std::cout;
using std::endl;
#define _ORB_
const char* keys =
"{ help h | | Print help message. }"
"{ dataset | | Path to the images folder used as dataset. }"
"{ image | | Path to the image to search for in the dataset. }"
"{ save | | Path and filename where to save the flann structure to. }"
"{ load | | Path and filename where to load the flann structure from. }";
struct img_info {
int img_index;
unsigned int nbr_of_matches;
img_info(int _img_index, unsigned int _nbr_of_matches)
: img_index(_img_index)
, nbr_of_matches(_nbr_of_matches)
{}
};
int main( int argc, char* argv[] )
{
//-- Test the program options
CommandLineParser parser( argc, argv, keys );
if (parser.has("help"))
{
parser.printMessage();
return -1;
}
const cv::String img_path = parser.get<String>("image");
Mat img = imread( samples::findFile( img_path ), IMREAD_GRAYSCALE );
if (img.empty() )
{
cout << "Could not open the image "<< img_path << endl;
return -1;
}
const cv::String db_path = parser.get<String>("dataset");
if (!utils::fs::isDirectory(db_path))
{
cout << "Dataset folder "<< db_path.c_str() <<" doesn't exist!" << endl;
return -1;
}
const cv::String load_db_path = parser.get<String>("load");
if ((load_db_path != String()) && (!utils::fs::exists(load_db_path)))
{
cout << "File " << load_db_path.c_str()
<< " where to load the flann structure from doesn't exist!" << endl;
return -1;
}
const cv::String save_db_path = parser.get<String>("save");
//-- Step 1: Detect the keypoints using a detector, compute the descriptors
// in the folder containing the images of the dataset
#ifdef _SIFT_
int minHessian = 400;
Ptr<Feature2D> detector = SIFT::create( minHessian );
#elif defined(_ORB_)
Ptr<Feature2D> detector = ORB::create();
#else
cout << "Missing or unknown defined descriptor. "
"Only SIFT and ORB are currently interfaced here" << endl;
return -1;
#endif
std::vector<KeyPoint> db_keypoints;
Mat db_descriptors;
std::vector<unsigned int> db_images_indice_range; //store the range of indices per image
std::vector<int> db_indice_2_image_lut; //match descriptor indice to its image
db_images_indice_range.push_back(0);
std::vector<cv::String> files;
utils::fs::glob(db_path, cv::String(), files);
for (std::vector<cv::String>::iterator itr = files.begin(); itr != files.end(); ++itr)
{
Mat tmp_img = imread( *itr, IMREAD_GRAYSCALE );
if (!tmp_img.empty())
{
std::vector<KeyPoint> kpts;
Mat descriptors;
detector->detectAndCompute( tmp_img, noArray(), kpts, descriptors );
db_keypoints.insert( db_keypoints.end(), kpts.begin(), kpts.end() );
db_descriptors.push_back( descriptors );
db_images_indice_range.push_back( db_images_indice_range.back()
+ static_cast<unsigned int>(kpts.size()) );
}
}
//-- Set the LUT
db_indice_2_image_lut.resize( db_images_indice_range.back() );
const int nbr_of_imgs = static_cast<int>( db_images_indice_range.size()-1 );
for (int i = 0; i < nbr_of_imgs; ++i)
{
const unsigned int first_indice = db_images_indice_range[i];
const unsigned int last_indice = db_images_indice_range[i+1];
std::fill( db_indice_2_image_lut.begin() + first_indice,
db_indice_2_image_lut.begin() + last_indice,
i );
}
//-- Step 2: build the structure storing the descriptors
#if defined(_SIFT_)
cv::Ptr<flann::GenericIndex<cvflann::L2<float> > > index;
if (load_db_path != String())
index = cv::makePtr<flann::GenericIndex<cvflann::L2<float> > >(db_descriptors,
cvflann::SavedIndexParams(load_db_path));
else
index = cv::makePtr<flann::GenericIndex<cvflann::L2<float> > >(db_descriptors,
cvflann::KDTreeIndexParams(4));
#elif defined(_ORB_)
cv::Ptr<flann::GenericIndex<cvflann::Hamming<unsigned char> > > index;
if (load_db_path != String())
index = cv::makePtr<flann::GenericIndex<cvflann::Hamming<unsigned char> > >
(db_descriptors, cvflann::SavedIndexParams(load_db_path));
else
index = cv::makePtr<flann::GenericIndex<cvflann::Hamming<unsigned char> > >
(db_descriptors, cvflann::LshIndexParams());
#else
cout<< "Descriptor not listed. Set the proper FLANN distance for this descriptor" <<endl;
return -1;
#endif
if (save_db_path != String())
index->save(save_db_path);
// Return if no query image was set
if (img_path == String())
return 0;
//-- Detect the keypoints and compute the descriptors for the query image
std::vector<KeyPoint> img_keypoints;
Mat img_descriptors;
detector->detectAndCompute( img, noArray(), img_keypoints, img_descriptors );
//-- Step 3: retrieve the descriptors in the dataset matching the ones of the query image
// /!\ knnSearch doesn't follow OpenCV standards by not initialising empty Mat properties
const int knn = 2;
Mat indices(img_descriptors.rows, knn, CV_32S);
#if defined(_SIFT_)
#define DIST_TYPE float
Mat dists(img_descriptors.rows, knn, CV_32F);
#elif defined(_ORB_)
#define DIST_TYPE int
Mat dists(img_descriptors.rows, knn, CV_32S);
#endif
index->knnSearch( img_descriptors, indices, dists, knn, cvflann::SearchParams(32) );
//-- Filter matches using the Lowe's ratio test
const float ratio_thresh = 0.7f;
std::vector<DMatch> good_matches; //contains
std::vector<unsigned int> matches_per_img_histogram( nbr_of_imgs, 0 );
for (int i = 0; i < dists.rows; ++i)
{
if (dists.at<DIST_TYPE>(i,0) < ratio_thresh * dists.at<DIST_TYPE>(i,1))
{
const int indice_in_db = indices.at<int>(i,0);
DMatch dmatch(i, indice_in_db, db_indice_2_image_lut[indice_in_db],
static_cast<float>(dists.at<DIST_TYPE>(i,0)));
good_matches.push_back( dmatch );
matches_per_img_histogram[ db_indice_2_image_lut[indice_in_db] ]++;
}
}
//-- Step 4: find the dataset image with the highest proportion of matches
std::multimap<float, img_info> images_infos;
for (int i = 0; i < nbr_of_imgs; ++i)
{
const unsigned int nbr_of_matches = matches_per_img_histogram[i];
if (nbr_of_matches < 4) //we need at leat 4 points for a homography
continue;
const unsigned int nbr_of_kpts = db_images_indice_range[i+1] - db_images_indice_range[i];
const float inverse_proportion_of_retrieved_kpts =
static_cast<float>(nbr_of_kpts) / static_cast<float>(nbr_of_matches);
img_info info(i, nbr_of_matches);
images_infos.insert( std::pair<float,img_info>(inverse_proportion_of_retrieved_kpts,
info) );
}
if (images_infos.begin() == images_infos.end())
{
cout<<"No good match could be found."<<endl;
return 0;
}
//-- if there are several images with a similar proportion of matches,
// select the one with the highest number of matches weighted by the
// squared ratio of proportions
const float best_matches_proportion = images_infos.begin()->first;
float new_matches_proportion = best_matches_proportion;
img_info best_img = images_infos.begin()->second;
std::multimap<float, img_info>::iterator it = images_infos.begin();
++it;
while ((it!=images_infos.end()) && (it->first < 1.1*best_matches_proportion))
{
const float ratio = new_matches_proportion / it->first;
if( it->second.nbr_of_matches * (ratio * ratio) > best_img.nbr_of_matches)
{
new_matches_proportion = it->first;
best_img = it->second;
}
++it;
}
//-- Step 5: filter goodmatches that belong to the best image match of the dataset
std::vector<DMatch> filtered_good_matches;
for (std::vector<DMatch>::iterator itr(good_matches.begin()); itr != good_matches.end(); ++itr)
{
if (itr->imgIdx == best_img.img_index)
filtered_good_matches.push_back(*itr);
}
//-- Retrieve the best image match from the dataset
Mat db_img = imread( files[best_img.img_index], IMREAD_GRAYSCALE );
//-- Draw matches
Mat img_matches;
drawMatches( img, img_keypoints, db_img, db_keypoints, filtered_good_matches, img_matches, Scalar::all(-1),
Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Show detected matches
imshow("Good Matches", img_matches );
waitKey();
return 0;
}

View File

@ -0,0 +1,350 @@
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(char** argv)
{
cout << "\nThis program demonstrates GrabCut segmentation -- select an object in a region\n"
"and then grabcut will attempt to segment it out.\n"
"Call:\n"
<< argv[0] << " <image_name>\n"
"\nSelect a rectangular area around the object you want to segment\n" <<
"\nHot keys: \n"
"\tESC - quit the program\n"
"\tr - restore the original image\n"
"\tn - next iteration\n"
"\n"
"\tleft mouse button - set rectangle\n"
"\n"
"\tCTRL+left mouse button - set GC_BGD pixels\n"
"\tSHIFT+left mouse button - set GC_FGD pixels\n"
"\n"
"\tCTRL+right mouse button - set GC_PR_BGD pixels\n"
"\tSHIFT+right mouse button - set GC_PR_FGD pixels\n" << endl;
}
const Scalar RED = Scalar(0,0,255);
const Scalar PINK = Scalar(230,130,255);
const Scalar BLUE = Scalar(255,0,0);
const Scalar LIGHTBLUE = Scalar(255,255,160);
const Scalar GREEN = Scalar(0,255,0);
const int BGD_KEY = EVENT_FLAG_CTRLKEY;
const int FGD_KEY = EVENT_FLAG_SHIFTKEY;
static void getBinMask( const Mat& comMask, Mat& binMask )
{
if( comMask.empty() || comMask.type()!=CV_8UC1 )
CV_Error( Error::StsBadArg, "comMask is empty or has incorrect type (not CV_8UC1)" );
if( binMask.empty() || binMask.rows!=comMask.rows || binMask.cols!=comMask.cols )
binMask.create( comMask.size(), CV_8UC1 );
binMask = comMask & 1;
}
class GCApplication
{
public:
enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 };
static const int radius = 2;
static const int thickness = -1;
void reset();
void setImageAndWinName( const Mat& _image, const string& _winName );
void showImage() const;
void mouseClick( int event, int x, int y, int flags, void* param );
int nextIter();
int getIterCount() const { return iterCount; }
private:
void setRectInMask();
void setLblsInMask( int flags, Point p, bool isPr );
const string* winName;
const Mat* image;
Mat mask;
Mat bgdModel, fgdModel;
uchar rectState, lblsState, prLblsState;
bool isInitialized;
Rect rect;
vector<Point> fgdPxls, bgdPxls, prFgdPxls, prBgdPxls;
int iterCount;
};
void GCApplication::reset()
{
if( !mask.empty() )
mask.setTo(Scalar::all(GC_BGD));
bgdPxls.clear(); fgdPxls.clear();
prBgdPxls.clear(); prFgdPxls.clear();
isInitialized = false;
rectState = NOT_SET;
lblsState = NOT_SET;
prLblsState = NOT_SET;
iterCount = 0;
}
void GCApplication::setImageAndWinName( const Mat& _image, const string& _winName )
{
if( _image.empty() || _winName.empty() )
return;
image = &_image;
winName = &_winName;
mask.create( image->size(), CV_8UC1);
reset();
}
void GCApplication::showImage() const
{
if( image->empty() || winName->empty() )
return;
Mat res;
Mat binMask;
image->copyTo( res );
if( isInitialized ){
getBinMask( mask, binMask);
Mat black (binMask.rows, binMask.cols, CV_8UC3, cv::Scalar(0,0,0));
black.setTo(Scalar::all(255), binMask);
addWeighted(black, 0.5, res, 0.5, 0.0, res);
}
vector<Point>::const_iterator it;
for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it )
circle( res, *it, radius, BLUE, thickness );
for( it = fgdPxls.begin(); it != fgdPxls.end(); ++it )
circle( res, *it, radius, RED, thickness );
for( it = prBgdPxls.begin(); it != prBgdPxls.end(); ++it )
circle( res, *it, radius, LIGHTBLUE, thickness );
for( it = prFgdPxls.begin(); it != prFgdPxls.end(); ++it )
circle( res, *it, radius, PINK, thickness );
if( rectState == IN_PROCESS || rectState == SET )
rectangle( res, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2);
imshow( *winName, res );
}
void GCApplication::setRectInMask()
{
CV_Assert( !mask.empty() );
mask.setTo( GC_BGD );
rect.x = max(0, rect.x);
rect.y = max(0, rect.y);
rect.width = min(rect.width, image->cols-rect.x);
rect.height = min(rect.height, image->rows-rect.y);
(mask(rect)).setTo( Scalar(GC_PR_FGD) );
}
void GCApplication::setLblsInMask( int flags, Point p, bool isPr )
{
vector<Point> *bpxls, *fpxls;
uchar bvalue, fvalue;
if( !isPr )
{
bpxls = &bgdPxls;
fpxls = &fgdPxls;
bvalue = GC_BGD;
fvalue = GC_FGD;
}
else
{
bpxls = &prBgdPxls;
fpxls = &prFgdPxls;
bvalue = GC_PR_BGD;
fvalue = GC_PR_FGD;
}
if( flags & BGD_KEY )
{
bpxls->push_back(p);
circle( mask, p, radius, bvalue, thickness );
}
if( flags & FGD_KEY )
{
fpxls->push_back(p);
circle( mask, p, radius, fvalue, thickness );
}
}
void GCApplication::mouseClick( int event, int x, int y, int flags, void* )
{
// TODO add bad args check
switch( event )
{
case EVENT_LBUTTONDOWN: // set rect or GC_BGD(GC_FGD) labels
{
bool isb = (flags & BGD_KEY) != 0,
isf = (flags & FGD_KEY) != 0;
if( rectState == NOT_SET && !isb && !isf )
{
rectState = IN_PROCESS;
rect = Rect( x, y, 1, 1 );
}
if ( (isb || isf) && rectState == SET )
lblsState = IN_PROCESS;
}
break;
case EVENT_RBUTTONDOWN: // set GC_PR_BGD(GC_PR_FGD) labels
{
bool isb = (flags & BGD_KEY) != 0,
isf = (flags & FGD_KEY) != 0;
if ( (isb || isf) && rectState == SET )
prLblsState = IN_PROCESS;
}
break;
case EVENT_LBUTTONUP:
if( rectState == IN_PROCESS )
{
if(rect.x == x || rect.y == y){
rectState = NOT_SET;
}
else{
rect = Rect( Point(rect.x, rect.y), Point(x,y) );
rectState = SET;
setRectInMask();
CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
}
showImage();
}
if( lblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), false);
lblsState = SET;
nextIter();
showImage();
}
else{
if(rectState == SET){
nextIter();
showImage();
}
}
break;
case EVENT_RBUTTONUP:
if( prLblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), true);
prLblsState = SET;
}
if(rectState == SET){
nextIter();
showImage();
}
break;
case EVENT_MOUSEMOVE:
if( rectState == IN_PROCESS )
{
rect = Rect( Point(rect.x, rect.y), Point(x,y) );
CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
showImage();
}
else if( lblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), false);
showImage();
}
else if( prLblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), true);
showImage();
}
break;
}
}
int GCApplication::nextIter()
{
if( isInitialized )
grabCut( *image, mask, rect, bgdModel, fgdModel, 1 );
else
{
if( rectState != SET )
return iterCount;
if( lblsState == SET || prLblsState == SET )
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK );
else
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT );
isInitialized = true;
}
iterCount++;
bgdPxls.clear(); fgdPxls.clear();
prBgdPxls.clear(); prFgdPxls.clear();
return iterCount;
}
GCApplication gcapp;
static void on_mouse( int event, int x, int y, int flags, void* param )
{
gcapp.mouseClick( event, x, y, flags, param );
}
int main( int argc, char** argv )
{
cv::CommandLineParser parser(argc, argv, "{@input| messi5.jpg |}");
help(argv);
string filename = parser.get<string>("@input");
if( filename.empty() )
{
cout << "\nDurn, empty filename" << endl;
return 1;
}
Mat image = imread(samples::findFile(filename), IMREAD_COLOR);
if( image.empty() )
{
cout << "\n Durn, couldn't read image filename " << filename << endl;
return 1;
}
const string winName = "image";
namedWindow( winName, WINDOW_AUTOSIZE );
setMouseCallback( winName, on_mouse, 0 );
gcapp.setImageAndWinName( image, winName );
gcapp.showImage();
for(;;)
{
char c = (char)waitKey(0);
switch( c )
{
case '\x1b':
cout << "Exiting ..." << endl;
goto exit_main;
case 'r':
cout << endl;
gcapp.reset();
gcapp.showImage();
break;
case 'n':
int iterCount = gcapp.getIterCount();
cout << "<" << iterCount << "... ";
int newIterCount = gcapp.nextIter();
if( newIterCount > iterCount )
{
gcapp.showImage();
cout << iterCount << ">" << endl;
}
else
cout << "rect must be determined>" << endl;
break;
}
}
exit_main:
destroyWindow( winName );
return 0;
}

View File

@ -0,0 +1,394 @@
/*
* This sample demonstrates the use of the function
* findTransformECC that implements the image alignment ECC algorithm
*
*
* The demo loads an image (defaults to fruits.jpg) and it artificially creates
* a template image based on the given motion type. When two images are given,
* the first image is the input image and the second one defines the template image.
* In the latter case, you can also parse the warp's initialization.
*
* Input and output warp files consist of the raw warp (transform) elements
*
* Authors: G. Evangelidis, INRIA, Grenoble, France
* M. Asbach, Fraunhofer IAIS, St. Augustin, Germany
*/
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/video.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core/utility.hpp>
#include <stdio.h>
#include <string>
#include <time.h>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
static void help(const char** argv);
static int readWarp(string iFilename, Mat& warp, int motionType);
static int saveWarp(string fileName, const Mat& warp, int motionType);
static void draw_warped_roi(Mat& image, const int width, const int height, Mat& W);
#define HOMO_VECTOR(H, x, y)\
H.at<float>(0,0) = (float)(x);\
H.at<float>(1,0) = (float)(y);\
H.at<float>(2,0) = 1.;
#define GET_HOMO_VALUES(X, x, y)\
(x) = static_cast<float> (X.at<float>(0,0)/X.at<float>(2,0));\
(y) = static_cast<float> (X.at<float>(1,0)/X.at<float>(2,0));
const std::string keys =
"{@inputImage | fruits.jpg | input image filename }"
"{@templateImage | | template image filename (optional)}"
"{@inputWarp | | input warp (matrix) filename (optional)}"
"{n numOfIter | 50 | ECC's iterations }"
"{e epsilon | 0.0001 | ECC's convergence epsilon }"
"{o outputWarp | outWarp.ecc | output warp (matrix) filename }"
"{m motionType | affine | type of motion (translation, euclidean, affine, homography) }"
"{v verbose | 1 | display initial and final images }"
"{w warpedImfile | warpedECC.png | warped input image }"
"{h help | | print help message }"
;
static void help(const char** argv)
{
cout << "\nThis file demonstrates the use of the ECC image alignment algorithm. When one image"
" is given, the template image is artificially formed by a random warp. When both images"
" are given, the initialization of the warp by command line parsing is possible. "
"If inputWarp is missing, the identity transformation initializes the algorithm. \n" << endl;
cout << "\nUsage example (one image): \n"
<< argv[0]
<< " fruits.jpg -o=outWarp.ecc "
"-m=euclidean -e=1e-6 -N=70 -v=1 \n" << endl;
cout << "\nUsage example (two images with initialization): \n"
<< argv[0]
<< " yourInput.png yourTemplate.png "
"yourInitialWarp.ecc -o=outWarp.ecc -m=homography -e=1e-6 -N=70 -v=1 -w=yourFinalImage.png \n" << endl;
}
static int readWarp(string iFilename, Mat& warp, int motionType){
// it reads from file a specific number of raw values:
// 9 values for homography, 6 otherwise
CV_Assert(warp.type()==CV_32FC1);
int numOfElements;
if (motionType==MOTION_HOMOGRAPHY)
numOfElements=9;
else
numOfElements=6;
int i;
int ret_value;
ifstream myfile(iFilename.c_str());
if (myfile.is_open()){
float* matPtr = warp.ptr<float>(0);
for(i=0; i<numOfElements; i++){
myfile >> matPtr[i];
}
ret_value = 1;
}
else {
cout << "Unable to open file " << iFilename.c_str() << endl;
ret_value = 0;
}
return ret_value;
}
static int saveWarp(string fileName, const Mat& warp, int motionType)
{
// it saves the raw matrix elements in a file
CV_Assert(warp.type()==CV_32FC1);
const float* matPtr = warp.ptr<float>(0);
int ret_value;
ofstream outfile(fileName.c_str());
if( !outfile ) {
cerr << "error in saving "
<< "Couldn't open file '" << fileName.c_str() << "'!" << endl;
ret_value = 0;
}
else {//save the warp's elements
outfile << matPtr[0] << " " << matPtr[1] << " " << matPtr[2] << endl;
outfile << matPtr[3] << " " << matPtr[4] << " " << matPtr[5] << endl;
if (motionType==MOTION_HOMOGRAPHY){
outfile << matPtr[6] << " " << matPtr[7] << " " << matPtr[8] << endl;
}
ret_value = 1;
}
return ret_value;
}
static void draw_warped_roi(Mat& image, const int width, const int height, Mat& W)
{
Point2f top_left, top_right, bottom_left, bottom_right;
Mat H = Mat (3, 1, CV_32F);
Mat U = Mat (3, 1, CV_32F);
Mat warp_mat = Mat::eye (3, 3, CV_32F);
for (int y = 0; y < W.rows; y++)
for (int x = 0; x < W.cols; x++)
warp_mat.at<float>(y,x) = W.at<float>(y,x);
//warp the corners of rectangle
// top-left
HOMO_VECTOR(H, 1, 1);
gemm(warp_mat, H, 1, 0, 0, U);
GET_HOMO_VALUES(U, top_left.x, top_left.y);
// top-right
HOMO_VECTOR(H, width, 1);
gemm(warp_mat, H, 1, 0, 0, U);
GET_HOMO_VALUES(U, top_right.x, top_right.y);
// bottom-left
HOMO_VECTOR(H, 1, height);
gemm(warp_mat, H, 1, 0, 0, U);
GET_HOMO_VALUES(U, bottom_left.x, bottom_left.y);
// bottom-right
HOMO_VECTOR(H, width, height);
gemm(warp_mat, H, 1, 0, 0, U);
GET_HOMO_VALUES(U, bottom_right.x, bottom_right.y);
// draw the warped perimeter
line(image, top_left, top_right, Scalar(255));
line(image, top_right, bottom_right, Scalar(255));
line(image, bottom_right, bottom_left, Scalar(255));
line(image, bottom_left, top_left, Scalar(255));
}
int main (const int argc, const char * argv[])
{
CommandLineParser parser(argc, argv, keys);
parser.about("ECC demo");
parser.printMessage();
help(argv);
string imgFile = parser.get<string>(0);
string tempImgFile = parser.get<string>(1);
string inWarpFile = parser.get<string>(2);
int number_of_iterations = parser.get<int>("n");
double termination_eps = parser.get<double>("e");
string warpType = parser.get<string>("m");
int verbose = parser.get<int>("v");
string finalWarp = parser.get<string>("o");
string warpedImFile = parser.get<string>("w");
if (!parser.check())
{
parser.printErrors();
return -1;
}
if (!(warpType == "translation" || warpType == "euclidean"
|| warpType == "affine" || warpType == "homography"))
{
cerr << "Invalid motion transformation" << endl;
return -1;
}
int mode_temp;
if (warpType == "translation")
mode_temp = MOTION_TRANSLATION;
else if (warpType == "euclidean")
mode_temp = MOTION_EUCLIDEAN;
else if (warpType == "affine")
mode_temp = MOTION_AFFINE;
else
mode_temp = MOTION_HOMOGRAPHY;
Mat inputImage = imread(samples::findFile(imgFile), IMREAD_GRAYSCALE);
if (inputImage.empty())
{
cerr << "Unable to load the inputImage" << endl;
return -1;
}
Mat target_image;
Mat template_image;
if (tempImgFile!="") {
inputImage.copyTo(target_image);
template_image = imread(samples::findFile(tempImgFile), IMREAD_GRAYSCALE);
if (template_image.empty()){
cerr << "Unable to load the template image" << endl;
return -1;
}
}
else{ //apply random warp to input image
resize(inputImage, target_image, Size(216, 216), 0, 0, INTER_LINEAR_EXACT);
Mat warpGround;
RNG rng(getTickCount());
double angle;
switch (mode_temp) {
case MOTION_TRANSLATION:
warpGround = (Mat_<float>(2,3) << 1, 0, (rng.uniform(10.f, 20.f)),
0, 1, (rng.uniform(10.f, 20.f)));
warpAffine(target_image, template_image, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
case MOTION_EUCLIDEAN:
angle = CV_PI/30 + CV_PI*rng.uniform((double)-2.f, (double)2.f)/180;
warpGround = (Mat_<float>(2,3) << cos(angle), -sin(angle), (rng.uniform(10.f, 20.f)),
sin(angle), cos(angle), (rng.uniform(10.f, 20.f)));
warpAffine(target_image, template_image, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
case MOTION_AFFINE:
warpGround = (Mat_<float>(2,3) << (1-rng.uniform(-0.05f, 0.05f)),
(rng.uniform(-0.03f, 0.03f)), (rng.uniform(10.f, 20.f)),
(rng.uniform(-0.03f, 0.03f)), (1-rng.uniform(-0.05f, 0.05f)),
(rng.uniform(10.f, 20.f)));
warpAffine(target_image, template_image, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
case MOTION_HOMOGRAPHY:
warpGround = (Mat_<float>(3,3) << (1-rng.uniform(-0.05f, 0.05f)),
(rng.uniform(-0.03f, 0.03f)), (rng.uniform(10.f, 20.f)),
(rng.uniform(-0.03f, 0.03f)), (1-rng.uniform(-0.05f, 0.05f)),(rng.uniform(10.f, 20.f)),
(rng.uniform(0.0001f, 0.0003f)), (rng.uniform(0.0001f, 0.0003f)), 1.f);
warpPerspective(target_image, template_image, warpGround,
Size(200,200), INTER_LINEAR + WARP_INVERSE_MAP);
break;
}
}
const int warp_mode = mode_temp;
// initialize or load the warp matrix
Mat warp_matrix;
if (warpType == "homography")
warp_matrix = Mat::eye(3, 3, CV_32F);
else
warp_matrix = Mat::eye(2, 3, CV_32F);
if (inWarpFile!=""){
int readflag = readWarp(inWarpFile, warp_matrix, warp_mode);
if ((!readflag) || warp_matrix.empty())
{
cerr << "-> Check warp initialization file" << endl << flush;
return -1;
}
}
else {
printf("\n ->Performance Warning: Identity warp ideally assumes images of "
"similar size. If the deformation is strong, the identity warp may not "
"be a good initialization. \n");
}
if (number_of_iterations > 200)
cout << "-> Warning: too many iterations " << endl;
if (warp_mode != MOTION_HOMOGRAPHY)
warp_matrix.rows = 2;
// start timing
const double tic_init = (double) getTickCount ();
double cc = findTransformECC (template_image, target_image, warp_matrix, warp_mode,
TermCriteria (TermCriteria::COUNT+TermCriteria::EPS,
number_of_iterations, termination_eps));
if (cc == -1)
{
cerr << "The execution was interrupted. The correlation value is going to be minimized." << endl;
cerr << "Check the warp initialization and/or the size of images." << endl << flush;
}
// end timing
const double toc_final = (double) getTickCount ();
const double total_time = (toc_final-tic_init)/(getTickFrequency());
if (verbose){
cout << "Alignment time (" << warpType << " transformation): "
<< total_time << " sec" << endl << flush;
// cout << "Final correlation: " << cc << endl << flush;
}
// save the final warp matrix
saveWarp(finalWarp, warp_matrix, warp_mode);
if (verbose){
cout << "\nThe final warp has been saved in the file: " << finalWarp << endl << flush;
}
// save the final warped image
Mat warped_image = Mat(template_image.rows, template_image.cols, CV_32FC1);
if (warp_mode != MOTION_HOMOGRAPHY)
warpAffine (target_image, warped_image, warp_matrix, warped_image.size(),
INTER_LINEAR + WARP_INVERSE_MAP);
else
warpPerspective (target_image, warped_image, warp_matrix, warped_image.size(),
INTER_LINEAR + WARP_INVERSE_MAP);
//save the warped image
imwrite(warpedImFile, warped_image);
// display resulting images
if (verbose)
{
cout << "The warped image has been saved in the file: " << warpedImFile << endl << flush;
namedWindow ("image", WINDOW_AUTOSIZE);
namedWindow ("template", WINDOW_AUTOSIZE);
namedWindow ("warped image", WINDOW_AUTOSIZE);
namedWindow ("error (black: no error)", WINDOW_AUTOSIZE);
moveWindow ("image", 20, 300);
moveWindow ("template", 300, 300);
moveWindow ("warped image", 600, 300);
moveWindow ("error (black: no error)", 900, 300);
// draw boundaries of corresponding regions
Mat identity_matrix = Mat::eye(3,3,CV_32F);
draw_warped_roi (target_image, template_image.cols-2, template_image.rows-2, warp_matrix);
draw_warped_roi (template_image, template_image.cols-2, template_image.rows-2, identity_matrix);
Mat errorImage;
subtract(template_image, warped_image, errorImage);
double max_of_error;
minMaxLoc(errorImage, NULL, &max_of_error);
// show images
cout << "Press any key to exit the demo (you might need to click on the images before)." << endl << flush;
imshow ("image", target_image);
waitKey (200);
imshow ("template", template_image);
waitKey (200);
imshow ("warped image", warped_image);
waitKey(200);
imshow ("error (black: no error)", abs(errorImage)*255/max_of_error);
waitKey(0);
}
// done
return 0;
}

View File

@ -0,0 +1,54 @@
/*this creates a yaml or xml list of files from the command line args
*/
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <string>
#include <iostream>
using std::string;
using std::cout;
using std::endl;
using namespace cv;
static void help(char** av)
{
cout << "\nThis creates a yaml or xml list of files from the command line args\n"
"usage:\n./" << av[0] << " imagelist.yaml *.png\n"
<< "Try using different extensions.(e.g. yaml yml xml xml.gz etc...)\n"
<< "This will serialize this list of images or whatever with opencv's FileStorage framework" << endl;
}
int main(int ac, char** av)
{
cv::CommandLineParser parser(ac, av, "{help h||}{@output||}");
if (parser.has("help"))
{
help(av);
return 0;
}
string outputname = parser.get<string>("@output");
if (outputname.empty())
{
help(av);
return 1;
}
Mat m = imread(outputname); //check if the output is an image - prevent overwrites!
if(!m.empty()){
std::cerr << "fail! Please specify an output file, don't want to overwrite you images!" << endl;
help(av);
return 1;
}
FileStorage fs(outputname, FileStorage::WRITE);
fs << "images" << "[";
for(int i = 2; i < ac; i++){
fs << string(av[i]);
}
fs << "]";
return 0;
}

View File

@ -0,0 +1,80 @@
/*
* Created on: Nov 23, 2010
* Author: Ethan Rublee
*
* A starter sample for using opencv, load up an imagelist
* that was generated with imagelist_creator.cpp
* easy as CV_PI right?
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
static void help(char** av)
{
cout << "\nThis program gets you started being able to read images from a list in a file\n"
"Usage:\n./" << av[0] << " image_list.yaml\n"
<< "\tThis is a starter sample, to get you up and going in a copy pasta fashion.\n"
<< "\tThe program reads in an list of images from a yaml or xml file and displays\n"
<< "one at a time\n"
<< "\tTry running imagelist_creator to generate a list of images.\n"
"Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
}
static bool readStringList(const string& filename, vector<string>& l)
{
l.resize(0);
FileStorage fs(filename, FileStorage::READ);
if (!fs.isOpened())
return false;
FileNode n = fs.getFirstTopLevelNode();
if (n.type() != FileNode::SEQ)
return false;
FileNodeIterator it = n.begin(), it_end = n.end();
for (; it != it_end; ++it)
l.push_back((string)*it);
return true;
}
static int process(const vector<string>& images)
{
namedWindow("image", WINDOW_KEEPRATIO); //resizable window;
for (size_t i = 0; i < images.size(); i++)
{
Mat image = imread(images[i], IMREAD_GRAYSCALE); // do grayscale processing?
imshow("image",image);
cout << "Press a key to see the next image in the list." << endl;
waitKey(); // wait infinitely for a key to be pressed
}
return 0;
}
int main(int ac, char** av)
{
cv::CommandLineParser parser(ac, av, "{help h||}{@input||}");
if (parser.has("help"))
{
help(av);
return 0;
}
std::string arg = parser.get<std::string>("@input");
if (arg.empty())
{
help(av);
return 1;
}
vector<string> imagelist;
if (!readStringList(arg,imagelist))
{
cerr << "Failed to read image list\n" << endl;
help(av);
return 1;
}
return process(imagelist);
}

View File

@ -0,0 +1,91 @@
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/photo.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help( char** argv )
{
cout << "\nCool inpainging demo. Inpainting repairs damage to images by floodfilling the damage \n"
<< "with surrounding image areas.\n"
"Using OpenCV version %s\n" << CV_VERSION << "\n"
"Usage:\n" << argv[0] <<" [image_name -- Default fruits.jpg]\n" << endl;
cout << "Hot keys: \n"
"\tESC - quit the program\n"
"\tr - restore the original image\n"
"\ti or SPACE - run inpainting algorithm\n"
"\t\t(before running it, paint something on the image)\n" << endl;
}
Mat img, inpaintMask;
Point prevPt(-1,-1);
static void onMouse( int event, int x, int y, int flags, void* )
{
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( inpaintMask, 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, "{@image|fruits.jpg|}");
help(argv);
string filename = samples::findFile(parser.get<string>("@image"));
Mat img0 = imread(filename, IMREAD_COLOR);
if(img0.empty())
{
cout << "Couldn't open the image " << filename << ". Usage: inpaint <image_name>\n" << endl;
return 0;
}
namedWindow("image", WINDOW_AUTOSIZE);
img = img0.clone();
inpaintMask = Mat::zeros(img.size(), CV_8U);
imshow("image", img);
setMouseCallback( "image", onMouse, NULL);
for(;;)
{
char c = (char)waitKey();
if( c == 27 )
break;
if( c == 'r' )
{
inpaintMask = Scalar::all(0);
img0.copyTo(img);
imshow("image", img);
}
if( c == 'i' || c == ' ' )
{
Mat inpainted;
inpaint(img, inpaintMask, inpainted, 3, INPAINT_TELEA);
imshow("inpainted image", inpainted);
}
}
return 0;
}

View File

@ -0,0 +1,235 @@
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
struct Pix
{
Point next_point;
double cost;
bool operator > (const Pix &b) const
{
return cost > b.cost;
}
};
struct Parameters
{
Mat img, img_pre_render, img_render;
Point end;
std::vector<std::vector<Point> > contours;
std::vector<Point> tmp_contour;
Mat zero_crossing, gradient_magnitude, Ix, Iy, hit_map_x, hit_map_y;
};
static float local_cost(const Point& p, const Point& q, const Mat& gradient_magnitude, const Mat& Iy, const Mat& Ix, const Mat& zero_crossing)
{
float fG = gradient_magnitude.at<float>(q.y, q.x);
float dp;
float dq;
const float WEIGHT_LAP_ZERO_CROSS = 0.43f;
const float WEIGHT_GRADIENT_MAGNITUDE = 0.14f;
const float WEIGHT_GRADIENT_DIRECTION = 0.43f;
bool isDiag = (p.x != q.x) && (p.y != q.y);
if ((Iy.at<float>(p) * (q.x - p.x) - Ix.at<float>(p) * (q.y - p.y)) >= 0)
{
dp = Iy.at<float>(p) * (q.x - p.x) - Ix.at<float>(p) * (q.y - p.y);
dq = Iy.at<float>(q) * (q.x - p.x) - Ix.at<float>(q) * (q.y - p.y);
}
else
{
dp = Iy.at<float>(p) * (p.x - q.x) + (-Ix.at<float>(p)) * (p.y - q.y);
dq = Iy.at<float>(q) * (p.x - q.x) + (-Ix.at<float>(q)) * (p.y - q.y);
}
if (isDiag)
{
dp /= sqrtf(2);
dq /= sqrtf(2);
}
else
{
fG /= sqrtf(2);
}
return WEIGHT_LAP_ZERO_CROSS * zero_crossing.at<uchar>(q) +
WEIGHT_GRADIENT_DIRECTION * (acosf(dp) + acosf(dq)) / static_cast<float>(CV_PI) +
WEIGHT_GRADIENT_MAGNITUDE * fG;
}
static void find_min_path(const Point& start, Parameters* param)
{
Pix begin;
Mat &img = param->img;
Mat cost_map(img.size(), CV_32F, Scalar(FLT_MAX));
Mat expand(img.size(), CV_8UC1, Scalar(0));
Mat processed(img.size(), CV_8UC1, Scalar(0));
Mat removed(img.size(), CV_8UC1, Scalar(0));
std::priority_queue < Pix, std::vector<Pix>, std::greater<Pix> > L;
cost_map.at<float>(start) = 0;
processed.at<uchar>(start) = 1;
begin.cost = 0;
begin.next_point = start;
L.push(begin);
while (!L.empty())
{
Pix P = L.top();
L.pop();
Point p = P.next_point;
processed.at<uchar>(p) = 0;
if (removed.at<uchar>(p) == 0)
{
expand.at<uchar>(p) = 1;
for (int i = -1; i <= 1; i++)
{
for(int j = -1; j <= 1; j++)
{
int tx = p.x + i;
int ty = p.y + j;
if (tx < 0 || tx >= img.cols || ty < 0 || ty >= img.rows)
continue;
if (expand.at<uchar>(ty, tx) == 0)
{
Point q = Point(tx, ty);
float cost = cost_map.at<float>(p) + local_cost(p, q, param->gradient_magnitude, param->Iy, param->Ix, param->zero_crossing);
if (processed.at<uchar>(q) == 1 && cost < cost_map.at<float>(q))
{
removed.at<uchar>(q) = 1;
}
if (processed.at<uchar>(q) == 0)
{
cost_map.at<float>(q) = cost;
param->hit_map_x.at<int>(q)= p.x;
param->hit_map_y.at<int>(q) = p.y;
processed.at<uchar>(q) = 1;
Pix val;
val.cost = cost_map.at<float>(q);
val.next_point = q;
L.push(val);
}
}
}
}
}
}
}
static void onMouse(int event, int x, int y, int , void* userdata)
{
Parameters* param = reinterpret_cast<Parameters*>(userdata);
Point &end = param->end;
std::vector<std::vector<Point> > &contours = param->contours;
std::vector<Point> &tmp_contour = param->tmp_contour;
Mat &img_render = param->img_render;
Mat &img_pre_render = param->img_pre_render;
if (event == EVENT_LBUTTONDOWN)
{
end = Point(x, y);
if (!contours.back().empty())
{
for (int i = static_cast<int>(tmp_contour.size()) - 1; i >= 0; i--)
{
contours.back().push_back(tmp_contour[i]);
}
tmp_contour.clear();
}
else
{
contours.back().push_back(end);
}
find_min_path(end, param);
img_render.copyTo(img_pre_render);
imshow("lasso", img_render);
}
else if (event == EVENT_RBUTTONDOWN)
{
img_pre_render.copyTo(img_render);
drawContours(img_pre_render, contours, static_cast<int>(contours.size()) - 1, Scalar(0,255,0), FILLED);
addWeighted(img_pre_render, 0.3, img_render, 0.7, 0, img_render);
contours.resize(contours.size() + 1);
imshow("lasso", img_render);
}
else if (event == EVENT_MOUSEMOVE && !contours.back().empty())
{
tmp_contour.clear();
img_pre_render.copyTo(img_render);
Point val_point = Point(x, y);
while (val_point != end)
{
tmp_contour.push_back(val_point);
Point cur = Point(param->hit_map_x.at<int>(val_point), param->hit_map_y.at<int>(val_point));
line(img_render, val_point, cur, Scalar(255, 0, 0), 2);
val_point = cur;
}
imshow("lasso", img_render);
}
}
const char* keys =
{
"{help h | |}"
"{@image | fruits.jpg| Path to image to process}"
};
int main( int argc, const char** argv )
{
Parameters param;
const int EDGE_THRESHOLD_LOW = 50;
const int EDGE_THRESHOLD_HIGH = 100;
CommandLineParser parser(argc, argv, keys);
parser.about("\nThis program demonstrates implementation of 'Intelligent Scissors' algorithm designed\n"
"by Eric N. Mortensen and William A. Barrett, and described in article\n"
"'Intelligent Scissors for Image Composition':\n"
"http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.138.3811&rep=rep1&type=pdf\n"
"To start drawing a new contour select a pixel, click LEFT mouse button.\n"
"To fix a path click LEFT mouse button again.\n"
"To finish drawing a contour click RIGHT mouse button.\n");
if (parser.has("help"))
{
parser.printMessage();
return 1;
}
std::vector<std::vector<Point> > c(1);
param.contours = c;
std::string filename = parser.get<std::string>(0);
Mat grayscale, img_canny;
param.img = imread(samples::findFile(filename));
param.hit_map_x.create(param.img.rows, param.img.cols, CV_32SC1);
param.hit_map_y.create(param.img.rows, param.img.cols, CV_32SC1);
cvtColor(param.img, grayscale, COLOR_BGR2GRAY);
Canny(grayscale, img_canny, EDGE_THRESHOLD_LOW, EDGE_THRESHOLD_HIGH);
threshold(img_canny, param.zero_crossing, 254, 1, THRESH_BINARY_INV);
Sobel(grayscale, param.Ix, CV_32FC1, 1, 0, 1);
Sobel(grayscale, param.Iy, CV_32FC1, 0, 1, 1);
param.Ix.convertTo(param.Ix, CV_32F, 1.0/255);
param.Iy.convertTo(param.Iy, CV_32F, 1.0/255);
// Compute gradients magnitude.
double max_val = 0.0;
magnitude(param.Iy, param.Ix, param.gradient_magnitude);
minMaxLoc(param.gradient_magnitude, 0, &max_val);
param.gradient_magnitude.convertTo(param.gradient_magnitude, CV_32F, -1/max_val, 1.0);
param.img.copyTo(param.img_pre_render);
param.img.copyTo(param.img_render);
namedWindow("lasso");
setMouseCallback("lasso", onMouse, &param);
imshow("lasso", param.img);
waitKey(0);
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,558 @@
#include "opencv2/core.hpp"
#include "opencv2/ml.hpp"
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
using namespace cv;
using namespace cv::ml;
static void help(char** argv)
{
printf("\nThe sample demonstrates how to train Random Trees classifier\n"
"(or Boosting classifier, or MLP, or Knearest, or Nbayes, or Support Vector Machines - see main()) using the provided dataset.\n"
"\n"
"We use the sample database letter-recognition.data\n"
"from UCI Repository, here is the link:\n"
"\n"
"Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998).\n"
"UCI Repository of machine learning databases\n"
"[http://www.ics.uci.edu/~mlearn/MLRepository.html].\n"
"Irvine, CA: University of California, Department of Information and Computer Science.\n"
"\n"
"The dataset consists of 20000 feature vectors along with the\n"
"responses - capital latin letters A..Z.\n"
"The first 16000 (10000 for boosting)) samples are used for training\n"
"and the remaining 4000 (10000 for boosting) - to test the classifier.\n"
"======================================================\n");
printf("\nThis is letter recognition sample.\n"
"The usage: %s [-data=<path to letter-recognition.data>] \\\n"
" [-save=<output XML file for the classifier>] \\\n"
" [-load=<XML file with the pre-trained classifier>] \\\n"
" [-boost|-mlp|-knearest|-nbayes|-svm] # to use boost/mlp/knearest/SVM classifier instead of default Random Trees\n", argv[0] );
}
// This function reads data and responses from the file <filename>
static bool
read_num_class_data( const string& filename, int var_count,
Mat* _data, Mat* _responses )
{
const int M = 1024;
char buf[M+2];
Mat el_ptr(1, var_count, CV_32F);
int i;
vector<int> responses;
_data->release();
_responses->release();
FILE* f = fopen( filename.c_str(), "rt" );
if( !f )
{
cout << "Could not read the database " << filename << endl;
return false;
}
for(;;)
{
char* ptr;
if( !fgets( buf, M, f ) || !strchr( buf, ',' ) )
break;
responses.push_back((int)buf[0]);
ptr = buf+2;
for( i = 0; i < var_count; i++ )
{
int n = 0;
sscanf( ptr, "%f%n", &el_ptr.at<float>(i), &n );
ptr += n + 1;
}
if( i < var_count )
break;
_data->push_back(el_ptr);
}
fclose(f);
Mat(responses).copyTo(*_responses);
cout << "The database " << filename << " is loaded.\n";
return true;
}
template<typename T>
static Ptr<T> load_classifier(const string& filename_to_load)
{
// load classifier from the specified file
Ptr<T> model = StatModel::load<T>( filename_to_load );
if( model.empty() )
cout << "Could not read the classifier " << filename_to_load << endl;
else
cout << "The classifier " << filename_to_load << " is loaded.\n";
return model;
}
static Ptr<TrainData>
prepare_train_data(const Mat& data, const Mat& responses, int ntrain_samples)
{
Mat sample_idx = Mat::zeros( 1, data.rows, CV_8U );
Mat train_samples = sample_idx.colRange(0, ntrain_samples);
train_samples.setTo(Scalar::all(1));
int nvars = data.cols;
Mat var_type( nvars + 1, 1, CV_8U );
var_type.setTo(Scalar::all(VAR_ORDERED));
var_type.at<uchar>(nvars) = VAR_CATEGORICAL;
return TrainData::create(data, ROW_SAMPLE, responses,
noArray(), sample_idx, noArray(), var_type);
}
inline TermCriteria TC(int iters, double eps)
{
return TermCriteria(TermCriteria::MAX_ITER + (eps > 0 ? TermCriteria::EPS : 0), iters, eps);
}
static void test_and_save_classifier(const Ptr<StatModel>& model,
const Mat& data, const Mat& responses,
int ntrain_samples, int rdelta,
const string& filename_to_save)
{
int i, nsamples_all = data.rows;
double train_hr = 0, test_hr = 0;
// compute prediction error on train and test data
for( i = 0; i < nsamples_all; i++ )
{
Mat sample = data.row(i);
float r = model->predict( sample );
r = std::abs(r + rdelta - responses.at<int>(i)) <= FLT_EPSILON ? 1.f : 0.f;
if( i < ntrain_samples )
train_hr += r;
else
test_hr += r;
}
test_hr /= nsamples_all - ntrain_samples;
train_hr = ntrain_samples > 0 ? train_hr/ntrain_samples : 1.;
printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
train_hr*100., test_hr*100. );
if( !filename_to_save.empty() )
{
model->save( filename_to_save );
}
}
static bool
build_rtrees_classifier( const string& data_filename,
const string& filename_to_save,
const string& filename_to_load )
{
Mat data;
Mat responses;
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
if( !ok )
return ok;
Ptr<RTrees> model;
int nsamples_all = data.rows;
int ntrain_samples = (int)(nsamples_all*0.8);
// Create or load Random Trees classifier
if( !filename_to_load.empty() )
{
model = load_classifier<RTrees>(filename_to_load);
if( model.empty() )
return false;
ntrain_samples = 0;
}
else
{
// create classifier by using <data> and <responses>
cout << "Training the classifier ...\n";
// Params( int maxDepth, int minSampleCount,
// double regressionAccuracy, bool useSurrogates,
// int maxCategories, const Mat& priors,
// bool calcVarImportance, int nactiveVars,
// TermCriteria termCrit );
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
model = RTrees::create();
model->setMaxDepth(10);
model->setMinSampleCount(10);
model->setRegressionAccuracy(0);
model->setUseSurrogates(false);
model->setMaxCategories(15);
model->setPriors(Mat());
model->setCalculateVarImportance(true);
model->setActiveVarCount(4);
model->setTermCriteria(TC(100,0.01f));
model->train(tdata);
cout << endl;
}
test_and_save_classifier(model, data, responses, ntrain_samples, 0, filename_to_save);
cout << "Number of trees: " << model->getRoots().size() << endl;
// Print variable importance
Mat var_importance = model->getVarImportance();
if( !var_importance.empty() )
{
double rt_imp_sum = sum( var_importance )[0];
printf("var#\timportance (in %%):\n");
int i, n = (int)var_importance.total();
for( i = 0; i < n; i++ )
printf( "%-2d\t%-4.1f\n", i, 100.f*var_importance.at<float>(i)/rt_imp_sum);
}
return true;
}
static bool
build_boost_classifier( const string& data_filename,
const string& filename_to_save,
const string& filename_to_load )
{
const int class_count = 26;
Mat data;
Mat responses;
Mat weak_responses;
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
if( !ok )
return ok;
int i, j, k;
Ptr<Boost> model;
int nsamples_all = data.rows;
int ntrain_samples = (int)(nsamples_all*0.5);
int var_count = data.cols;
// Create or load Boosted Tree classifier
if( !filename_to_load.empty() )
{
model = load_classifier<Boost>(filename_to_load);
if( model.empty() )
return false;
ntrain_samples = 0;
}
else
{
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// As currently boosted tree classifier in MLL can only be trained
// for 2-class problems, we transform the training database by
// "unrolling" each training sample as many times as the number of
// classes (26) that we have.
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Mat new_data( ntrain_samples*class_count, var_count + 1, CV_32F );
Mat new_responses( ntrain_samples*class_count, 1, CV_32S );
// 1. unroll the database type mask
printf( "Unrolling the database...\n");
for( i = 0; i < ntrain_samples; i++ )
{
const float* data_row = data.ptr<float>(i);
for( j = 0; j < class_count; j++ )
{
float* new_data_row = (float*)new_data.ptr<float>(i*class_count+j);
memcpy(new_data_row, data_row, var_count*sizeof(data_row[0]));
new_data_row[var_count] = (float)j;
new_responses.at<int>(i*class_count + j) = responses.at<int>(i) == j+'A';
}
}
Mat var_type( 1, var_count + 2, CV_8U );
var_type.setTo(Scalar::all(VAR_ORDERED));
var_type.at<uchar>(var_count) = var_type.at<uchar>(var_count+1) = VAR_CATEGORICAL;
Ptr<TrainData> tdata = TrainData::create(new_data, ROW_SAMPLE, new_responses,
noArray(), noArray(), noArray(), var_type);
vector<double> priors(2);
priors[0] = 1;
priors[1] = 26;
cout << "Training the classifier (may take a few minutes)...\n";
model = Boost::create();
model->setBoostType(Boost::GENTLE);
model->setWeakCount(100);
model->setWeightTrimRate(0.95);
model->setMaxDepth(5);
model->setUseSurrogates(false);
model->setPriors(Mat(priors));
model->train(tdata);
cout << endl;
}
Mat temp_sample( 1, var_count + 1, CV_32F );
float* tptr = temp_sample.ptr<float>();
// compute prediction error on train and test data
double train_hr = 0, test_hr = 0;
for( i = 0; i < nsamples_all; i++ )
{
int best_class = 0;
double max_sum = -DBL_MAX;
const float* ptr = data.ptr<float>(i);
for( k = 0; k < var_count; k++ )
tptr[k] = ptr[k];
for( j = 0; j < class_count; j++ )
{
tptr[var_count] = (float)j;
float s = model->predict( temp_sample, noArray(), StatModel::RAW_OUTPUT );
if( max_sum < s )
{
max_sum = s;
best_class = j + 'A';
}
}
double r = std::abs(best_class - responses.at<int>(i)) < FLT_EPSILON ? 1 : 0;
if( i < ntrain_samples )
train_hr += r;
else
test_hr += r;
}
test_hr /= nsamples_all-ntrain_samples;
train_hr = ntrain_samples > 0 ? train_hr/ntrain_samples : 1.;
printf( "Recognition rate: train = %.1f%%, test = %.1f%%\n",
train_hr*100., test_hr*100. );
cout << "Number of trees: " << model->getRoots().size() << endl;
// Save classifier to file if needed
if( !filename_to_save.empty() )
model->save( filename_to_save );
return true;
}
static bool
build_mlp_classifier( const string& data_filename,
const string& filename_to_save,
const string& filename_to_load )
{
const int class_count = 26;
Mat data;
Mat responses;
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
if( !ok )
return ok;
Ptr<ANN_MLP> model;
int nsamples_all = data.rows;
int ntrain_samples = (int)(nsamples_all*0.8);
// Create or load MLP classifier
if( !filename_to_load.empty() )
{
model = load_classifier<ANN_MLP>(filename_to_load);
if( model.empty() )
return false;
ntrain_samples = 0;
}
else
{
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//
// MLP does not support categorical variables by explicitly.
// So, instead of the output class label, we will use
// a binary vector of <class_count> components for training and,
// therefore, MLP will give us a vector of "probabilities" at the
// prediction stage
//
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Mat train_data = data.rowRange(0, ntrain_samples);
Mat train_responses = Mat::zeros( ntrain_samples, class_count, CV_32F );
// 1. unroll the responses
cout << "Unrolling the responses...\n";
for( int i = 0; i < ntrain_samples; i++ )
{
int cls_label = responses.at<int>(i) - 'A';
train_responses.at<float>(i, cls_label) = 1.f;
}
// 2. train classifier
int layer_sz[] = { data.cols, 100, 100, class_count };
int nlayers = (int)(sizeof(layer_sz)/sizeof(layer_sz[0]));
Mat layer_sizes( 1, nlayers, CV_32S, layer_sz );
#if 1
int method = ANN_MLP::BACKPROP;
double method_param = 0.001;
int max_iter = 300;
#else
int method = ANN_MLP::RPROP;
double method_param = 0.1;
int max_iter = 1000;
#endif
Ptr<TrainData> tdata = TrainData::create(train_data, ROW_SAMPLE, train_responses);
cout << "Training the classifier (may take a few minutes)...\n";
model = ANN_MLP::create();
model->setLayerSizes(layer_sizes);
model->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0, 0);
model->setTermCriteria(TC(max_iter,0));
model->setTrainMethod(method, method_param);
model->train(tdata);
cout << endl;
}
test_and_save_classifier(model, data, responses, ntrain_samples, 'A', filename_to_save);
return true;
}
static bool
build_knearest_classifier( const string& data_filename, int K )
{
Mat data;
Mat responses;
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
if( !ok )
return ok;
int nsamples_all = data.rows;
int ntrain_samples = (int)(nsamples_all*0.8);
// create classifier by using <data> and <responses>
cout << "Training the classifier ...\n";
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
Ptr<KNearest> model = KNearest::create();
model->setDefaultK(K);
model->setIsClassifier(true);
model->train(tdata);
cout << endl;
test_and_save_classifier(model, data, responses, ntrain_samples, 0, string());
return true;
}
static bool
build_nbayes_classifier( const string& data_filename )
{
Mat data;
Mat responses;
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
if( !ok )
return ok;
Ptr<NormalBayesClassifier> model;
int nsamples_all = data.rows;
int ntrain_samples = (int)(nsamples_all*0.8);
// create classifier by using <data> and <responses>
cout << "Training the classifier ...\n";
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
model = NormalBayesClassifier::create();
model->train(tdata);
cout << endl;
test_and_save_classifier(model, data, responses, ntrain_samples, 0, string());
return true;
}
static bool
build_svm_classifier( const string& data_filename,
const string& filename_to_save,
const string& filename_to_load )
{
Mat data;
Mat responses;
bool ok = read_num_class_data( data_filename, 16, &data, &responses );
if( !ok )
return ok;
Ptr<SVM> model;
int nsamples_all = data.rows;
int ntrain_samples = (int)(nsamples_all*0.8);
// Create or load Random Trees classifier
if( !filename_to_load.empty() )
{
model = load_classifier<SVM>(filename_to_load);
if( model.empty() )
return false;
ntrain_samples = 0;
}
else
{
// create classifier by using <data> and <responses>
cout << "Training the classifier ...\n";
Ptr<TrainData> tdata = prepare_train_data(data, responses, ntrain_samples);
model = SVM::create();
model->setType(SVM::C_SVC);
model->setKernel(SVM::LINEAR);
model->setC(1);
model->train(tdata);
cout << endl;
}
test_and_save_classifier(model, data, responses, ntrain_samples, 0, filename_to_save);
return true;
}
int main( int argc, char *argv[] )
{
string filename_to_save = "";
string filename_to_load = "";
string data_filename;
int method = 0;
cv::CommandLineParser parser(argc, argv, "{data|letter-recognition.data|}{save||}{load||}{boost||}"
"{mlp||}{knn knearest||}{nbayes||}{svm||}");
data_filename = samples::findFile(parser.get<string>("data"));
if (parser.has("save"))
filename_to_save = parser.get<string>("save");
if (parser.has("load"))
filename_to_load = samples::findFile(parser.get<string>("load"));
if (parser.has("boost"))
method = 1;
else if (parser.has("mlp"))
method = 2;
else if (parser.has("knearest"))
method = 3;
else if (parser.has("nbayes"))
method = 4;
else if (parser.has("svm"))
method = 5;
help(argv);
if( (method == 0 ?
build_rtrees_classifier( data_filename, filename_to_save, filename_to_load ) :
method == 1 ?
build_boost_classifier( data_filename, filename_to_save, filename_to_load ) :
method == 2 ?
build_mlp_classifier( data_filename, filename_to_save, filename_to_load ) :
method == 3 ?
build_knearest_classifier( data_filename, 10 ) :
method == 4 ?
build_nbayes_classifier( data_filename) :
method == 5 ?
build_svm_classifier( data_filename, filename_to_save, filename_to_load ):
-1) < 0)
return 0;
}

View File

@ -0,0 +1,151 @@
#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;
static void help()
{
// print a welcome message, and the OpenCV version
cout << "\nThis is a demo of Lukas-Kanade optical flow lkdemo(),\n"
"Using OpenCV version " << CV_VERSION << endl;
cout << "\nIt uses camera by default, but you can provide a path to video as an argument.\n";
cout << "\nHot keys: \n"
"\tESC - quit the program\n"
"\tr - auto-initialize tracking\n"
"\tc - delete all the points\n"
"\tn - switch the \"night\" mode on/off\n"
"To add/remove a feature point click it\n" << endl;
}
Point2f point;
bool addRemovePt = false;
static void onMouse( int event, int x, int y, int /*flags*/, void* /*param*/ )
{
if( event == EVENT_LBUTTONDOWN )
{
point = Point2f((float)x, (float)y);
addRemovePt = true;
}
}
int main( int argc, char** argv )
{
VideoCapture cap;
TermCriteria termcrit(TermCriteria::COUNT|TermCriteria::EPS,20,0.03);
Size subPixWinSize(10,10), winSize(31,31);
const int MAX_COUNT = 500;
bool needToInit = false;
bool nightMode = false;
help();
cv::CommandLineParser parser(argc, argv, "{@input|0|}");
string input = parser.get<string>("@input");
if( input.size() == 1 && isdigit(input[0]) )
cap.open(input[0] - '0');
else
cap.open(input);
if( !cap.isOpened() )
{
cout << "Could not initialize capturing...\n";
return 0;
}
namedWindow( "LK Demo", 1 );
setMouseCallback( "LK Demo", onMouse, 0 );
Mat gray, prevGray, image, frame;
vector<Point2f> points[2];
for(;;)
{
cap >> frame;
if( frame.empty() )
break;
frame.copyTo(image);
cvtColor(image, gray, COLOR_BGR2GRAY);
if( nightMode )
image = Scalar::all(0);
if( needToInit )
{
// automatic initialization
goodFeaturesToTrack(gray, points[1], MAX_COUNT, 0.01, 10, Mat(), 3, 3, 0, 0.04);
cornerSubPix(gray, points[1], subPixWinSize, Size(-1,-1), termcrit);
addRemovePt = false;
}
else if( !points[0].empty() )
{
vector<uchar> status;
vector<float> err;
if(prevGray.empty())
gray.copyTo(prevGray);
calcOpticalFlowPyrLK(prevGray, gray, points[0], points[1], status, err, winSize,
3, termcrit, 0, 0.001);
size_t i, k;
for( i = k = 0; i < points[1].size(); i++ )
{
if( addRemovePt )
{
if( norm(point - points[1][i]) <= 5 )
{
addRemovePt = false;
continue;
}
}
if( !status[i] )
continue;
points[1][k++] = points[1][i];
circle( image, points[1][i], 3, Scalar(0,255,0), -1, 8);
}
points[1].resize(k);
}
if( addRemovePt && points[1].size() < (size_t)MAX_COUNT )
{
vector<Point2f> tmp;
tmp.push_back(point);
cornerSubPix( gray, tmp, winSize, Size(-1,-1), termcrit);
points[1].push_back(tmp[0]);
addRemovePt = false;
}
needToInit = false;
imshow("LK Demo", image);
char c = (char)waitKey(10);
if( c == 27 )
break;
switch( c )
{
case 'r':
needToInit = true;
break;
case 'c':
points[0].clear();
points[1].clear();
break;
case 'n':
nightMode = !nightMode;
break;
}
std::swap(points[1], points[0]);
cv::swap(prevGray, gray);
}
return 0;
}

View File

@ -0,0 +1,127 @@
// Logistic Regression sample
// AUTHOR: Rahul Kavi rahulkavi[at]live[at]com
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/ml.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
using namespace cv::ml;
static void showImage(const Mat &data, int columns, const String &name)
{
Mat bigImage;
for(int i = 0; i < data.rows; ++i)
{
bigImage.push_back(data.row(i).reshape(0, columns));
}
imshow(name, bigImage.t());
}
static float calculateAccuracyPercent(const Mat &original, const Mat &predicted)
{
return 100 * (float)countNonZero(original == predicted) / predicted.rows;
}
int main()
{
const String filename = samples::findFile("data01.xml");
cout << "**********************************************************************" << endl;
cout << filename
<< " contains digits 0 and 1 of 20 samples each, collected on an Android device" << endl;
cout << "Each of the collected images are of size 28 x 28 re-arranged to 1 x 784 matrix"
<< endl;
cout << "**********************************************************************" << endl;
Mat data, labels;
{
cout << "loading the dataset...";
FileStorage f;
if(f.open(filename, FileStorage::READ))
{
f["datamat"] >> data;
f["labelsmat"] >> labels;
f.release();
}
else
{
cerr << "file can not be opened: " << filename << endl;
return 1;
}
data.convertTo(data, CV_32F);
labels.convertTo(labels, CV_32F);
cout << "read " << data.rows << " rows of data" << endl;
}
Mat data_train, data_test;
Mat labels_train, labels_test;
for(int i = 0; i < data.rows; i++)
{
if(i % 2 == 0)
{
data_train.push_back(data.row(i));
labels_train.push_back(labels.row(i));
}
else
{
data_test.push_back(data.row(i));
labels_test.push_back(labels.row(i));
}
}
cout << "training/testing samples count: " << data_train.rows << "/" << data_test.rows << endl;
// display sample image
showImage(data_train, 28, "train data");
showImage(data_test, 28, "test data");
// simple case with batch gradient
cout << "training...";
//! [init]
Ptr<LogisticRegression> lr1 = LogisticRegression::create();
lr1->setLearningRate(0.001);
lr1->setIterations(10);
lr1->setRegularization(LogisticRegression::REG_L2);
lr1->setTrainMethod(LogisticRegression::BATCH);
lr1->setMiniBatchSize(1);
//! [init]
lr1->train(data_train, ROW_SAMPLE, labels_train);
cout << "done!" << endl;
cout << "predicting...";
Mat responses;
lr1->predict(data_test, responses);
cout << "done!" << endl;
// show prediction report
cout << "original vs predicted:" << endl;
labels_test.convertTo(labels_test, CV_32S);
cout << labels_test.t() << endl;
cout << responses.t() << endl;
cout << "accuracy: " << calculateAccuracyPercent(labels_test, responses) << "%" << endl;
// save the classifier
const String saveFilename = "NewLR_Trained.xml";
cout << "saving the classifier to " << saveFilename << endl;
lr1->save(saveFilename);
// load the classifier onto new object
cout << "loading a new classifier from " << saveFilename << endl;
Ptr<LogisticRegression> lr2 = StatModel::load<LogisticRegression>(saveFilename);
// predict using loaded classifier
cout << "predicting the dataset using the loaded classifier...";
Mat responses2;
lr2->predict(data_test, responses2);
cout << "done!" << endl;
// calculate accuracy
cout << labels_test.t() << endl;
cout << responses2.t() << endl;
cout << "accuracy: " << calculateAccuracyPercent(labels_test, responses2) << "%" << endl;
waitKey(0);
return 0;
}

View File

@ -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;
}

View File

@ -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/master/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;
}

View File

@ -0,0 +1,186 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/highgui.hpp>
#include <vector>
#include <iostream>
using namespace std;
using namespace cv;
static void help(char* argv[])
{
cout << "\n This program demonstrates how to detect compute and match ORB BRISK and AKAZE descriptors \n"
"Usage: \n "
<< argv[0] << " --image1=<image1(basketball1.png as default)> --image2=<image2(basketball2.png as default)>\n"
"Press a key when image window is active to change algorithm or descriptor";
}
int main(int argc, char *argv[])
{
vector<String> typeDesc;
vector<String> typeAlgoMatch;
vector<String> fileName;
// This descriptor are going to be detect and compute
typeDesc.push_back("AKAZE-DESCRIPTOR_KAZE_UPRIGHT"); // see https://docs.opencv.org/master/d8/d30/classcv_1_1AKAZE.html
typeDesc.push_back("AKAZE"); // see http://docs.opencv.org/master/d8/d30/classcv_1_1AKAZE.html
typeDesc.push_back("ORB"); // see http://docs.opencv.org/master/de/dbf/classcv_1_1BRISK.html
typeDesc.push_back("BRISK"); // see http://docs.opencv.org/master/db/d95/classcv_1_1ORB.html
// This algorithm would be used to match descriptors see http://docs.opencv.org/master/db/d39/classcv_1_1DescriptorMatcher.html#ab5dc5036569ecc8d47565007fa518257
typeAlgoMatch.push_back("BruteForce");
typeAlgoMatch.push_back("BruteForce-L1");
typeAlgoMatch.push_back("BruteForce-Hamming");
typeAlgoMatch.push_back("BruteForce-Hamming(2)");
cv::CommandLineParser parser(argc, argv,
"{ @image1 | basketball1.png | }"
"{ @image2 | basketball2.png | }"
"{help h ||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
fileName.push_back(samples::findFile(parser.get<string>(0)));
fileName.push_back(samples::findFile(parser.get<string>(1)));
Mat img1 = imread(fileName[0], IMREAD_GRAYSCALE);
Mat img2 = imread(fileName[1], IMREAD_GRAYSCALE);
if (img1.empty())
{
cerr << "Image " << fileName[0] << " is empty or cannot be found" << endl;
return 1;
}
if (img2.empty())
{
cerr << "Image " << fileName[1] << " is empty or cannot be found" << endl;
return 1;
}
vector<double> desMethCmp;
Ptr<Feature2D> b;
// Descriptor loop
vector<String>::iterator itDesc;
for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
{
Ptr<DescriptorMatcher> descriptorMatcher;
// Match between img1 and img2
vector<DMatch> matches;
// keypoint for img1 and img2
vector<KeyPoint> keyImg1, keyImg2;
// Descriptor for img1 and img2
Mat descImg1, descImg2;
vector<String>::iterator itMatcher = typeAlgoMatch.end();
if (*itDesc == "AKAZE-DESCRIPTOR_KAZE_UPRIGHT"){
b = AKAZE::create(AKAZE::DESCRIPTOR_KAZE_UPRIGHT);
}
if (*itDesc == "AKAZE"){
b = AKAZE::create();
}
if (*itDesc == "ORB"){
b = ORB::create();
}
else if (*itDesc == "BRISK"){
b = BRISK::create();
}
try
{
// We can detect keypoint with detect method
b->detect(img1, keyImg1, Mat());
// and compute their descriptors with method compute
b->compute(img1, keyImg1, descImg1);
// or detect and compute descriptors in one step
b->detectAndCompute(img2, Mat(),keyImg2, descImg2,false);
// Match method loop
for (itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); ++itMatcher){
descriptorMatcher = DescriptorMatcher::create(*itMatcher);
if ((*itMatcher == "BruteForce-Hamming" || *itMatcher == "BruteForce-Hamming(2)") && (b->descriptorType() == CV_32F || b->defaultNorm() <= NORM_L2SQR))
{
cout << "**************************************************************************\n";
cout << "It's strange. You should use Hamming distance only for a binary descriptor\n";
cout << "**************************************************************************\n";
}
if ((*itMatcher == "BruteForce" || *itMatcher == "BruteForce-L1") && (b->defaultNorm() >= NORM_HAMMING))
{
cout << "**************************************************************************\n";
cout << "It's strange. You shouldn't use L1 or L2 distance for a binary descriptor\n";
cout << "**************************************************************************\n";
}
try
{
descriptorMatcher->match(descImg1, descImg2, matches, Mat());
// Keep best matches only to have a nice drawing.
// We sort distance between descriptor matches
Mat index;
int nbMatch=int(matches.size());
Mat tab(nbMatch, 1, CV_32F);
for (int i = 0; i<nbMatch; i++)
{
tab.at<float>(i, 0) = matches[i].distance;
}
sortIdx(tab, index, SORT_EVERY_COLUMN + SORT_ASCENDING);
vector<DMatch> bestMatches;
for (int i = 0; i<30; i++)
{
bestMatches.push_back(matches[index.at<int>(i, 0)]);
}
Mat result;
drawMatches(img1, keyImg1, img2, keyImg2, bestMatches, result);
namedWindow(*itDesc+": "+*itMatcher, WINDOW_AUTOSIZE);
imshow(*itDesc + ": " + *itMatcher, result);
// Saved result could be wrong due to bug 4308
FileStorage fs(*itDesc + "_" + *itMatcher + ".yml", FileStorage::WRITE);
fs<<"Matches"<<matches;
vector<DMatch>::iterator it;
cout<<"**********Match results**********\n";
cout << "Index \tIndex \tdistance\n";
cout << "in img1\tin img2\n";
// Use to compute distance between keyPoint matches and to evaluate match algorithm
double cumSumDist2=0;
for (it = bestMatches.begin(); it != bestMatches.end(); ++it)
{
cout << it->queryIdx << "\t" << it->trainIdx << "\t" << it->distance << "\n";
Point2d p=keyImg1[it->queryIdx].pt-keyImg2[it->trainIdx].pt;
cumSumDist2=p.x*p.x+p.y*p.y;
}
desMethCmp.push_back(cumSumDist2);
waitKey();
}
catch (const Exception& e)
{
cout << e.msg << endl;
cout << "Cumulative distance cannot be computed." << endl;
desMethCmp.push_back(-1);
}
}
}
catch (const Exception& e)
{
cerr << "Exception: " << e.what() << endl;
cout << "Feature : " << *itDesc << "\n";
if (itMatcher != typeAlgoMatch.end())
{
cout << "Matcher : " << *itMatcher << "\n";
}
}
}
int i=0;
cout << "Cumulative distance between keypoint match for different algorithm and feature detector \n\t";
cout << "We cannot say which is the best but we can say results are different! \n\t";
for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); ++itMatcher)
{
cout<<*itMatcher<<"\t";
}
cout << "\n";
for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
{
cout << *itDesc << "\t";
for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); ++itMatcher, ++i)
{
cout << desMethCmp[i]<<"\t";
}
cout<<"\n";
}
return 0;
}

View File

@ -0,0 +1,78 @@
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help()
{
cout << "This program demonstrates finding the minimum enclosing box, triangle or circle of a set\n"
<< "of points using functions: minAreaRect() minEnclosingTriangle() minEnclosingCircle().\n"
<< "Random points are generated and then enclosed.\n\n"
<< "Press ESC, 'q' or 'Q' to exit and any other key to regenerate the set of points.\n\n";
}
int main( int /*argc*/, char** /*argv*/ )
{
help();
Mat img(500, 500, CV_8UC3, Scalar::all(0));
RNG& rng = theRNG();
for(;;)
{
int i, count = rng.uniform(1, 101);
vector<Point> points;
// Generate a random set of points
for( i = 0; i < count; i++ )
{
Point pt;
pt.x = rng.uniform(img.cols/4, img.cols*3/4);
pt.y = rng.uniform(img.rows/4, img.rows*3/4);
points.push_back(pt);
}
// Find the minimum area enclosing bounding box
Point2f vtx[4];
RotatedRect box = minAreaRect(points);
box.points(vtx);
// Find the minimum area enclosing triangle
vector<Point2f> triangle;
minEnclosingTriangle(points, triangle);
// Find the minimum area enclosing circle
Point2f center;
float radius = 0;
minEnclosingCircle(points, center, radius);
img = Scalar::all(0);
// Draw the points
for( i = 0; i < count; i++ )
circle( img, points[i], 3, Scalar(0, 0, 255), FILLED, LINE_AA );
// Draw the bounding box
for( i = 0; i < 4; i++ )
line(img, vtx[i], vtx[(i+1)%4], Scalar(0, 255, 0), 1, LINE_AA);
// Draw the triangle
for( i = 0; i < 3; i++ )
line(img, triangle[i], triangle[(i+1)%3], Scalar(255, 255, 0), 1, LINE_AA);
// Draw the circle
circle(img, center, cvRound(radius), Scalar(0, 255, 255), 1, LINE_AA);
imshow( "Rectangle, triangle & circle", img );
char key = (char)waitKey();
if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
break;
}
return 0;
}

View File

@ -0,0 +1,109 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <string>
using namespace cv;
static void help(char** argv)
{
printf("\nShow off image morphology: erosion, dialation, open and close\n"
"Call:\n %s [image]\n"
"This program also shows use of rect, ellipse and cross kernels\n\n", argv[0]);
printf( "Hot keys: \n"
"\tESC - quit the program\n"
"\tr - use rectangle structuring element\n"
"\te - use elliptic structuring element\n"
"\tc - use cross-shaped structuring element\n"
"\tSPACE - loop through all the options\n" );
}
Mat src, dst;
int element_shape = MORPH_RECT;
//the address of variable which receives trackbar position update
int max_iters = 10;
int open_close_pos = 0;
int erode_dilate_pos = 0;
// callback function for open/close trackbar
static void OpenClose(int, void*)
{
int n = open_close_pos;
int an = abs(n);
Mat element = getStructuringElement(element_shape, Size(an*2+1, an*2+1), Point(an, an) );
if( n < 0 )
morphologyEx(src, dst, MORPH_OPEN, element);
else
morphologyEx(src, dst, MORPH_CLOSE, element);
imshow("Open/Close",dst);
}
// callback function for erode/dilate trackbar
static void ErodeDilate(int, void*)
{
int n = erode_dilate_pos;
int an = abs(n);
Mat element = getStructuringElement(element_shape, Size(an*2+1, an*2+1), Point(an, an) );
if( n < 0 )
erode(src, dst, element);
else
dilate(src, dst, element);
imshow("Erode/Dilate",dst);
}
int main( int argc, char** argv )
{
cv::CommandLineParser parser(argc, argv, "{help h||}{ @image | baboon.jpg | }");
if (parser.has("help"))
{
help(argv);
return 0;
}
std::string filename = samples::findFile(parser.get<std::string>("@image"));
if( (src = imread(filename,IMREAD_COLOR)).empty() )
{
help(argv);
return -1;
}
//create windows for output images
namedWindow("Open/Close",1);
namedWindow("Erode/Dilate",1);
open_close_pos = erode_dilate_pos = max_iters;
createTrackbar("iterations", "Open/Close",&open_close_pos,max_iters*2+1,OpenClose);
setTrackbarMin("iterations", "Open/Close", -max_iters);
setTrackbarMax("iterations", "Open/Close", max_iters);
setTrackbarPos("iterations", "Open/Close", 0);
createTrackbar("iterations", "Erode/Dilate",&erode_dilate_pos,max_iters*2+1,ErodeDilate);
setTrackbarMin("iterations", "Erode/Dilate", -max_iters);
setTrackbarMax("iterations", "Erode/Dilate", max_iters);
setTrackbarPos("iterations", "Erode/Dilate", 0);
for(;;)
{
OpenClose(open_close_pos, 0);
ErodeDilate(erode_dilate_pos, 0);
char c = (char)waitKey(0);
if( c == 27 )
break;
if( c == 'e' )
element_shape = MORPH_ELLIPSE;
else if( c == 'r' )
element_shape = MORPH_RECT;
else if( c == 'c' )
element_shape = MORPH_CROSS;
else if( c == ' ' )
element_shape = (element_shape + 1) % 3;
}
return 0;
}

View File

@ -0,0 +1,65 @@
#include <opencv2/ml/ml.hpp>
using namespace std;
using namespace cv;
using namespace cv::ml;
int main()
{
//create random training data
Mat_<float> data(100, 100);
randn(data, Mat::zeros(1, 1, data.type()), Mat::ones(1, 1, data.type()));
//half of the samples for each class
Mat_<float> responses(data.rows, 2);
for (int i = 0; i<data.rows; ++i)
{
if (i < data.rows/2)
{
responses(i, 0) = 1;
responses(i, 1) = 0;
}
else
{
responses(i, 0) = 0;
responses(i, 1) = 1;
}
}
/*
//example code for just a single response (regression)
Mat_<float> responses(data.rows, 1);
for (int i=0; i<responses.rows; ++i)
responses(i, 0) = i < responses.rows / 2 ? 0 : 1;
*/
//create the neural network
Mat_<int> layerSizes(1, 3);
layerSizes(0, 0) = data.cols;
layerSizes(0, 1) = 20;
layerSizes(0, 2) = responses.cols;
Ptr<ANN_MLP> network = ANN_MLP::create();
network->setLayerSizes(layerSizes);
network->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0.1, 0.1);
network->setTrainMethod(ANN_MLP::BACKPROP, 0.1, 0.1);
Ptr<TrainData> trainData = TrainData::create(data, ROW_SAMPLE, responses);
network->train(trainData);
if (network->isTrained())
{
printf("Predict one-vector:\n");
Mat result;
network->predict(Mat::ones(1, data.cols, data.type()), result);
cout << result << endl;
printf("Predict training data:\n");
for (int i=0; i<data.rows; ++i)
{
network->predict(data.row(i), result);
cout << result << endl;
}
}
return 0;
}

View File

@ -0,0 +1,99 @@
/*
* npr_demo.cpp
*
* Author:
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
*
* This tutorial demonstrates how to use OpenCV Non-Photorealistic Rendering Module.
* 1) Edge Preserve Smoothing
* -> Using Normalized convolution Filter
* -> Using Recursive Filter
* 2) Detail Enhancement
* 3) Pencil sketch/Color Pencil Drawing
* 4) Stylization
*
*/
#include <signal.h>
#include "opencv2/photo.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include <iostream>
#include <stdlib.h>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
cv::CommandLineParser parser(argc, argv, "{help h||show help message}{@image|lena.jpg|input image}");
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
string filename = samples::findFile(parser.get<string>("@image"));
Mat I = imread(filename);
int num,type;
if(I.empty())
{
cout << "Image not found" << endl;
return 1;
}
cout << endl;
cout << " Edge Preserve Filter" << endl;
cout << "----------------------" << endl;
cout << "Options: " << endl;
cout << endl;
cout << "1) Edge Preserve Smoothing" << endl;
cout << " -> Using Normalized convolution Filter" << endl;
cout << " -> Using Recursive Filter" << endl;
cout << "2) Detail Enhancement" << endl;
cout << "3) Pencil sketch/Color Pencil Drawing" << endl;
cout << "4) Stylization" << endl;
cout << endl;
cout << "Press number 1-4 to choose from above techniques: ";
cin >> num;
Mat img;
if(num == 1)
{
cout << endl;
cout << "Press 1 for Normalized Convolution Filter and 2 for Recursive Filter: ";
cin >> type;
edgePreservingFilter(I,img,type);
imshow("Edge Preserve Smoothing",img);
}
else if(num == 2)
{
detailEnhance(I,img);
imshow("Detail Enhanced",img);
}
else if(num == 3)
{
Mat img1;
pencilSketch(I,img1, img, 10 , 0.1f, 0.03f);
imshow("Pencil Sketch",img1);
imshow("Color Pencil Sketch",img);
}
else if(num == 4)
{
stylization(I,img);
imshow("Stylization",img);
}
waitKey(0);
}

View File

@ -0,0 +1,32 @@
// 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/core/utility.hpp>
#include <iostream>
static const std::string keys = "{ b build | | print complete build info }"
"{ h help | | print this help }";
int main(int argc, const char* argv[])
{
cv::CommandLineParser parser(argc, argv, keys);
parser.about("This sample outputs OpenCV version and build configuration.");
if (parser.has("help"))
{
parser.printMessage();
}
else if (!parser.check())
{
parser.printErrors();
}
else if (parser.has("build"))
{
std::cout << cv::getBuildInformation() << std::endl;
}
else
{
std::cout << "Welcome to OpenCV " << CV_VERSION << std::endl;
}
return 0;
}

View File

@ -0,0 +1,191 @@
/*
* pca.cpp
*
* Author:
* Kevin Hughes <kevinhughes27[at]gmail[dot]com>
*
* Special Thanks to:
* Philipp Wagner <bytefish[at]gmx[dot]de>
*
* This program demonstrates how to use OpenCV PCA with a
* specified amount of variance to retain. The effect
* is illustrated further by using a trackbar to
* change the value for retained variance.
*
* The program takes as input a text file with each line
* begin the full path to an image. PCA will be performed
* on this list of images. The author recommends using
* the first 15 faces of the AT&T face data set:
* http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html
*
* so for example your input text file would look like this:
*
* <path_to_at&t_faces>/orl_faces/s1/1.pgm
* <path_to_at&t_faces>/orl_faces/s2/1.pgm
* <path_to_at&t_faces>/orl_faces/s3/1.pgm
* <path_to_at&t_faces>/orl_faces/s4/1.pgm
* <path_to_at&t_faces>/orl_faces/s5/1.pgm
* <path_to_at&t_faces>/orl_faces/s6/1.pgm
* <path_to_at&t_faces>/orl_faces/s7/1.pgm
* <path_to_at&t_faces>/orl_faces/s8/1.pgm
* <path_to_at&t_faces>/orl_faces/s9/1.pgm
* <path_to_at&t_faces>/orl_faces/s10/1.pgm
* <path_to_at&t_faces>/orl_faces/s11/1.pgm
* <path_to_at&t_faces>/orl_faces/s12/1.pgm
* <path_to_at&t_faces>/orl_faces/s13/1.pgm
* <path_to_at&t_faces>/orl_faces/s14/1.pgm
* <path_to_at&t_faces>/orl_faces/s15/1.pgm
*
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <opencv2/core.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
///////////////////////
// Functions
static void read_imgList(const string& filename, vector<Mat>& images) {
std::ifstream file(filename.c_str(), ifstream::in);
if (!file) {
string error_message = "No valid input file was given, please check the given filename.";
CV_Error(Error::StsBadArg, error_message);
}
string line;
while (getline(file, line)) {
images.push_back(imread(line, 0));
}
}
static Mat formatImagesForPCA(const vector<Mat> &data)
{
Mat dst(static_cast<int>(data.size()), data[0].rows*data[0].cols, CV_32F);
for(unsigned int i = 0; i < data.size(); i++)
{
Mat image_row = data[i].clone().reshape(1,1);
Mat row_i = dst.row(i);
image_row.convertTo(row_i,CV_32F);
}
return dst;
}
static Mat toGrayscale(InputArray _src) {
Mat src = _src.getMat();
// only allow one channel
if(src.channels() != 1) {
CV_Error(Error::StsBadArg, "Only Matrices with one channel are supported");
}
// create and return normalized image
Mat dst;
cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
return dst;
}
struct params
{
Mat data;
int ch;
int rows;
PCA pca;
string winName;
};
static void onTrackbar(int pos, void* ptr)
{
cout << "Retained Variance = " << pos << "% ";
cout << "re-calculating PCA..." << std::flush;
double var = pos / 100.0;
struct params *p = (struct params *)ptr;
p->pca = PCA(p->data, cv::Mat(), PCA::DATA_AS_ROW, var);
Mat point = p->pca.project(p->data.row(0));
Mat reconstruction = p->pca.backProject(point);
reconstruction = reconstruction.reshape(p->ch, p->rows);
reconstruction = toGrayscale(reconstruction);
imshow(p->winName, reconstruction);
cout << "done! # of principal components: " << p->pca.eigenvectors.rows << endl;
}
///////////////////////
// Main
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv, "{@input||image list}{help h||show help message}");
if (parser.has("help"))
{
parser.printMessage();
exit(0);
}
// Get the path to your CSV.
string imgList = parser.get<string>("@input");
if (imgList.empty())
{
parser.printMessage();
exit(1);
}
// vector to hold the images
vector<Mat> images;
// Read in the data. This can fail if not valid
try {
read_imgList(imgList, images);
} catch (const cv::Exception& e) {
cerr << "Error opening file \"" << imgList << "\". Reason: " << e.msg << endl;
exit(1);
}
// Quit if there are not enough images for this demo.
if(images.size() <= 1) {
string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(Error::StsError, error_message);
}
// Reshape and stack images into a rowMatrix
Mat data = formatImagesForPCA(images);
// perform PCA
PCA pca(data, cv::Mat(), PCA::DATA_AS_ROW, 0.95); // trackbar is initially set here, also this is a common value for retainedVariance
// Demonstration of the effect of retainedVariance on the first image
Mat point = pca.project(data.row(0)); // project into the eigenspace, thus the image becomes a "point"
Mat reconstruction = pca.backProject(point); // re-create the image from the "point"
reconstruction = reconstruction.reshape(images[0].channels(), images[0].rows); // reshape from a row vector into image shape
reconstruction = toGrayscale(reconstruction); // re-scale for displaying purposes
// init highgui window
string winName = "Reconstruction | press 'q' to quit";
namedWindow(winName, WINDOW_NORMAL);
// params struct to pass to the trackbar handler
params p;
p.data = data;
p.ch = images[0].channels();
p.rows = images[0].rows;
p.pca = pca;
p.winName = winName;
// create the tracbar
int pos = 95;
createTrackbar("Retained Variance (%)", winName, &pos, 100, onTrackbar, (void*)&p);
// display until user presses q
imshow(winName, reconstruction);
char key = 0;
while(key != 'q')
key = (char)waitKey();
return 0;
}

View File

@ -0,0 +1,129 @@
// 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/objdetect.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/videoio.hpp>
#include <iostream>
#include <iomanip>
using namespace cv;
using namespace std;
class Detector
{
enum Mode { Default, Daimler } m;
HOGDescriptor hog, hog_d;
public:
Detector() : m(Default), hog(), hog_d(Size(48, 96), Size(16, 16), Size(8, 8), Size(8, 8), 9)
{
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
hog_d.setSVMDetector(HOGDescriptor::getDaimlerPeopleDetector());
}
void toggleMode() { m = (m == Default ? Daimler : Default); }
string modeName() const { return (m == Default ? "Default" : "Daimler"); }
vector<Rect> detect(InputArray img)
{
// Run the detector with default parameters. to get a higher hit-rate
// (and more false alarms, respectively), decrease the hitThreshold and
// groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
vector<Rect> found;
if (m == Default)
hog.detectMultiScale(img, found, 0, Size(8,8), Size(), 1.05, 2, false);
else if (m == Daimler)
hog_d.detectMultiScale(img, found, 0, Size(8,8), Size(), 1.05, 2, true);
return found;
}
void adjustRect(Rect & r) const
{
// The HOG detector returns slightly larger rectangles than the real objects,
// so we slightly shrink the rectangles to get a nicer output.
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.8);
r.y += cvRound(r.height*0.07);
r.height = cvRound(r.height*0.8);
}
};
static const string keys = "{ help h | | print help message }"
"{ camera c | 0 | capture video from camera (device index starting from 0) }"
"{ video v | | use video as input }";
int main(int argc, char** argv)
{
CommandLineParser parser(argc, argv, keys);
parser.about("This sample demonstrates the use of the HoG descriptor.");
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
int camera = parser.get<int>("camera");
string file = parser.get<string>("video");
if (!parser.check())
{
parser.printErrors();
return 1;
}
VideoCapture cap;
if (file.empty())
cap.open(camera);
else
{
file = samples::findFileOrKeep(file);
cap.open(file);
}
if (!cap.isOpened())
{
cout << "Can not open video stream: '" << (file.empty() ? "<camera>" : file) << "'" << endl;
return 2;
}
cout << "Press 'q' or <ESC> to quit." << endl;
cout << "Press <space> to toggle between Default and Daimler detector" << endl;
Detector detector;
Mat frame;
for (;;)
{
cap >> frame;
if (frame.empty())
{
cout << "Finished reading: empty frame" << endl;
break;
}
int64 t = getTickCount();
vector<Rect> found = detector.detect(frame);
t = getTickCount() - t;
// show the window
{
ostringstream buf;
buf << "Mode: " << detector.modeName() << " ||| "
<< "FPS: " << fixed << setprecision(1) << (getTickFrequency() / (double)t);
putText(frame, buf.str(), Point(10, 30), FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 0, 255), 2, LINE_AA);
}
for (vector<Rect>::iterator i = found.begin(); i != found.end(); ++i)
{
Rect &r = *i;
detector.adjustRect(r);
rectangle(frame, r.tl(), r.br(), cv::Scalar(0, 255, 0), 2);
}
imshow("People detector", frame);
// interact with user
const char key = (char)waitKey(1);
if (key == 27 || key == 'q') // ESC
{
cout << "Exit requested" << endl;
break;
}
else if (key == ' ')
{
detector.toggleMode();
}
}
return 0;
}

View File

@ -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;
}

View File

@ -0,0 +1,399 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/ml.hpp"
#include "opencv2/highgui.hpp"
#include <stdio.h>
using namespace std;
using namespace cv;
using namespace cv::ml;
const Scalar WHITE_COLOR = Scalar(255,255,255);
const string winName = "points";
const int testStep = 5;
Mat img, imgDst;
RNG rng;
vector<Point> trainedPoints;
vector<int> trainedPointsMarkers;
const int MAX_CLASSES = 2;
vector<Vec3b> classColors(MAX_CLASSES);
int currentClass = 0;
vector<int> classCounters(MAX_CLASSES);
#define _NBC_ 1 // normal Bayessian classifier
#define _KNN_ 1 // k nearest neighbors classifier
#define _SVM_ 1 // support vectors machine
#define _DT_ 1 // decision tree
#define _BT_ 1 // ADA Boost
#define _GBT_ 0 // gradient boosted trees
#define _RF_ 1 // random forest
#define _ANN_ 1 // artificial neural networks
#define _EM_ 1 // expectation-maximization
static void on_mouse( int event, int x, int y, int /*flags*/, void* )
{
if( img.empty() )
return;
int updateFlag = 0;
if( event == EVENT_LBUTTONUP )
{
trainedPoints.push_back( Point(x,y) );
trainedPointsMarkers.push_back( currentClass );
classCounters[currentClass]++;
updateFlag = true;
}
//draw
if( updateFlag )
{
img = Scalar::all(0);
// draw points
for( size_t i = 0; i < trainedPoints.size(); i++ )
{
Vec3b c = classColors[trainedPointsMarkers[i]];
circle( img, trainedPoints[i], 5, Scalar(c), -1 );
}
imshow( winName, img );
}
}
static Mat prepare_train_samples(const vector<Point>& pts)
{
Mat samples;
Mat(pts).reshape(1, (int)pts.size()).convertTo(samples, CV_32F);
return samples;
}
static Ptr<TrainData> prepare_train_data()
{
Mat samples = prepare_train_samples(trainedPoints);
return TrainData::create(samples, ROW_SAMPLE, Mat(trainedPointsMarkers));
}
static void predict_and_paint(const Ptr<StatModel>& model, Mat& dst)
{
Mat testSample( 1, 2, CV_32FC1 );
for( int y = 0; y < img.rows; y += testStep )
{
for( int x = 0; x < img.cols; x += testStep )
{
testSample.at<float>(0) = (float)x;
testSample.at<float>(1) = (float)y;
int response = (int)model->predict( testSample );
dst.at<Vec3b>(y, x) = classColors[response];
}
}
}
#if _NBC_
static void find_decision_boundary_NBC()
{
// learn classifier
Ptr<NormalBayesClassifier> normalBayesClassifier = StatModel::train<NormalBayesClassifier>(prepare_train_data());
predict_and_paint(normalBayesClassifier, imgDst);
}
#endif
#if _KNN_
static void find_decision_boundary_KNN( int K )
{
Ptr<KNearest> knn = KNearest::create();
knn->setDefaultK(K);
knn->setIsClassifier(true);
knn->train(prepare_train_data());
predict_and_paint(knn, imgDst);
}
#endif
#if _SVM_
static void find_decision_boundary_SVM( double C )
{
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::POLY); //SVM::LINEAR;
svm->setDegree(0.5);
svm->setGamma(1);
svm->setCoef0(1);
svm->setNu(0.5);
svm->setP(0);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1000, 0.01));
svm->setC(C);
svm->train(prepare_train_data());
predict_and_paint(svm, imgDst);
Mat sv = svm->getSupportVectors();
for( int i = 0; i < sv.rows; i++ )
{
const float* supportVector = sv.ptr<float>(i);
circle( imgDst, Point(saturate_cast<int>(supportVector[0]),saturate_cast<int>(supportVector[1])), 5, Scalar(255,255,255), -1 );
}
}
#endif
#if _DT_
static void find_decision_boundary_DT()
{
Ptr<DTrees> dtree = DTrees::create();
dtree->setMaxDepth(8);
dtree->setMinSampleCount(2);
dtree->setUseSurrogates(false);
dtree->setCVFolds(0); // the number of cross-validation folds
dtree->setUse1SERule(false);
dtree->setTruncatePrunedTree(false);
dtree->train(prepare_train_data());
predict_and_paint(dtree, imgDst);
}
#endif
#if _BT_
static void find_decision_boundary_BT()
{
Ptr<Boost> boost = Boost::create();
boost->setBoostType(Boost::DISCRETE);
boost->setWeakCount(100);
boost->setWeightTrimRate(0.95);
boost->setMaxDepth(2);
boost->setUseSurrogates(false);
boost->setPriors(Mat());
boost->train(prepare_train_data());
predict_and_paint(boost, imgDst);
}
#endif
#if _GBT_
static void find_decision_boundary_GBT()
{
GBTrees::Params params( GBTrees::DEVIANCE_LOSS, // loss_function_type
100, // weak_count
0.1f, // shrinkage
1.0f, // subsample_portion
2, // max_depth
false // use_surrogates )
);
Ptr<GBTrees> gbtrees = StatModel::train<GBTrees>(prepare_train_data(), params);
predict_and_paint(gbtrees, imgDst);
}
#endif
#if _RF_
static void find_decision_boundary_RF()
{
Ptr<RTrees> rtrees = RTrees::create();
rtrees->setMaxDepth(4);
rtrees->setMinSampleCount(2);
rtrees->setRegressionAccuracy(0.f);
rtrees->setUseSurrogates(false);
rtrees->setMaxCategories(16);
rtrees->setPriors(Mat());
rtrees->setCalculateVarImportance(false);
rtrees->setActiveVarCount(1);
rtrees->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 5, 0));
rtrees->train(prepare_train_data());
predict_and_paint(rtrees, imgDst);
}
#endif
#if _ANN_
static void find_decision_boundary_ANN( const Mat& layer_sizes )
{
Mat trainClasses = Mat::zeros( (int)trainedPoints.size(), (int)classColors.size(), CV_32FC1 );
for( int i = 0; i < trainClasses.rows; i++ )
{
trainClasses.at<float>(i, trainedPointsMarkers[i]) = 1.f;
}
Mat samples = prepare_train_samples(trainedPoints);
Ptr<TrainData> tdata = TrainData::create(samples, ROW_SAMPLE, trainClasses);
Ptr<ANN_MLP> ann = ANN_MLP::create();
ann->setLayerSizes(layer_sizes);
ann->setActivationFunction(ANN_MLP::SIGMOID_SYM, 1, 1);
ann->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 300, FLT_EPSILON));
ann->setTrainMethod(ANN_MLP::BACKPROP, 0.001);
ann->train(tdata);
predict_and_paint(ann, imgDst);
}
#endif
#if _EM_
static void find_decision_boundary_EM()
{
img.copyTo( imgDst );
Mat samples = prepare_train_samples(trainedPoints);
int i, j, nmodels = (int)classColors.size();
vector<Ptr<EM> > em_models(nmodels);
Mat modelSamples;
for( i = 0; i < nmodels; i++ )
{
const int componentCount = 3;
modelSamples.release();
for( j = 0; j < samples.rows; j++ )
{
if( trainedPointsMarkers[j] == i )
modelSamples.push_back(samples.row(j));
}
// learn models
if( !modelSamples.empty() )
{
Ptr<EM> em = EM::create();
em->setClustersNumber(componentCount);
em->setCovarianceMatrixType(EM::COV_MAT_DIAGONAL);
em->trainEM(modelSamples, noArray(), noArray(), noArray());
em_models[i] = em;
}
}
// classify coordinate plane points using the bayes classifier, i.e.
// y(x) = arg max_i=1_modelsCount likelihoods_i(x)
Mat testSample(1, 2, CV_32FC1 );
Mat logLikelihoods(1, nmodels, CV_64FC1, Scalar(-DBL_MAX));
for( int y = 0; y < img.rows; y += testStep )
{
for( int x = 0; x < img.cols; x += testStep )
{
testSample.at<float>(0) = (float)x;
testSample.at<float>(1) = (float)y;
for( i = 0; i < nmodels; i++ )
{
if( !em_models[i].empty() )
logLikelihoods.at<double>(i) = em_models[i]->predict2(testSample, noArray())[0];
}
Point maxLoc;
minMaxLoc(logLikelihoods, 0, 0, 0, &maxLoc);
imgDst.at<Vec3b>(y, x) = classColors[maxLoc.x];
}
}
}
#endif
int main()
{
cout << "Use:" << endl
<< " key '0' .. '1' - switch to class #n" << endl
<< " left mouse button - to add new point;" << endl
<< " key 'r' - to run the ML model;" << endl
<< " key 'i' - to init (clear) the data." << endl << endl;
cv::namedWindow( "points", 1 );
img.create( 480, 640, CV_8UC3 );
imgDst.create( 480, 640, CV_8UC3 );
imshow( "points", img );
setMouseCallback( "points", on_mouse );
classColors[0] = Vec3b(0, 255, 0);
classColors[1] = Vec3b(0, 0, 255);
for(;;)
{
char key = (char)waitKey();
if( key == 27 ) break;
if( key == 'i' ) // init
{
img = Scalar::all(0);
trainedPoints.clear();
trainedPointsMarkers.clear();
classCounters.assign(MAX_CLASSES, 0);
imshow( winName, img );
}
if( key == '0' || key == '1' )
{
currentClass = key - '0';
}
if( key == 'r' ) // run
{
double minVal = 0;
minMaxLoc(classCounters, &minVal, 0, 0, 0);
if( minVal == 0 )
{
printf("each class should have at least 1 point\n");
continue;
}
img.copyTo( imgDst );
#if _NBC_
find_decision_boundary_NBC();
imshow( "NormalBayesClassifier", imgDst );
#endif
#if _KNN_
find_decision_boundary_KNN( 3 );
imshow( "kNN", imgDst );
find_decision_boundary_KNN( 15 );
imshow( "kNN2", imgDst );
#endif
#if _SVM_
//(1)-(2)separable and not sets
find_decision_boundary_SVM( 1 );
imshow( "classificationSVM1", imgDst );
find_decision_boundary_SVM( 10 );
imshow( "classificationSVM2", imgDst );
#endif
#if _DT_
find_decision_boundary_DT();
imshow( "DT", imgDst );
#endif
#if _BT_
find_decision_boundary_BT();
imshow( "BT", imgDst);
#endif
#if _GBT_
find_decision_boundary_GBT();
imshow( "GBT", imgDst);
#endif
#if _RF_
find_decision_boundary_RF();
imshow( "RF", imgDst);
#endif
#if _ANN_
Mat layer_sizes1( 1, 3, CV_32SC1 );
layer_sizes1.at<int>(0) = 2;
layer_sizes1.at<int>(1) = 5;
layer_sizes1.at<int>(2) = (int)classColors.size();
find_decision_boundary_ANN( layer_sizes1 );
imshow( "ANN", imgDst );
#endif
#if _EM_
find_decision_boundary_EM();
imshow( "EM", imgDst );
#endif
}
}
return 0;
}

View File

@ -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;
}

View File

@ -0,0 +1,347 @@
#include "opencv2/objdetect.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/imgcodecs.hpp"
#include <string>
#include <iostream>
using namespace std;
using namespace cv;
static int liveQRCodeDetect();
static int imageQRCodeDetect(const string& in_file);
static bool g_modeMultiQR = false;
static bool g_detectOnly = false;
static string g_out_file_name, g_out_file_ext;
static int g_save_idx = 0;
static bool g_saveDetections = false;
static bool g_saveAll = false;
static string getQRModeString()
{
std::ostringstream out;
out << "QR"
<< (g_modeMultiQR ? " multi" : "")
<< (g_detectOnly ? " detector" : " decoder");
return out.str();
}
int main(int argc, char *argv[])
{
const string keys =
"{h help ? | | print help messages }"
"{i in | | input image path (also switches to image detection mode) }"
"{detect | false | detect QR code only (skip decoding) }"
"{m multi | | use detect for multiple qr-codes }"
"{o out | qr_code.png | path to result file }"
"{save_detections | false | save all QR detections (video mode only) }"
"{save_all | false | save all processed frames (video mode only) }"
;
CommandLineParser cmd_parser(argc, argv, keys);
cmd_parser.about("This program detects the QR-codes from camera or images using the OpenCV library.");
if (cmd_parser.has("help"))
{
cmd_parser.printMessage();
return 0;
}
string in_file_name = cmd_parser.get<string>("in"); // path to input image
if (cmd_parser.has("out"))
{
std::string fpath = cmd_parser.get<string>("out"); // path to output image
std::string::size_type idx = fpath.rfind('.');
if (idx != std::string::npos)
{
g_out_file_name = fpath.substr(0, idx);
g_out_file_ext = fpath.substr(idx);
}
else
{
g_out_file_name = fpath;
g_out_file_ext = ".png";
}
}
if (!cmd_parser.check())
{
cmd_parser.printErrors();
return -1;
}
g_modeMultiQR = cmd_parser.has("multi") && cmd_parser.get<bool>("multi");
g_detectOnly = cmd_parser.has("detect") && cmd_parser.get<bool>("detect");
g_saveDetections = cmd_parser.has("save_detections") && cmd_parser.get<bool>("save_detections");
g_saveAll = cmd_parser.has("save_all") && cmd_parser.get<bool>("save_all");
int return_code = 0;
if (in_file_name.empty())
{
return_code = liveQRCodeDetect();
}
else
{
return_code = imageQRCodeDetect(samples::findFile(in_file_name));
}
return return_code;
}
static
void drawQRCodeContour(Mat &color_image, const vector<Point>& corners)
{
if (!corners.empty())
{
double show_radius = (color_image.rows > color_image.cols)
? (2.813 * color_image.rows) / color_image.cols
: (2.813 * color_image.cols) / color_image.rows;
double contour_radius = show_radius * 0.4;
vector< vector<Point> > contours;
contours.push_back(corners);
drawContours(color_image, contours, 0, Scalar(211, 0, 148), cvRound(contour_radius));
RNG rng(1000);
for (size_t i = 0; i < 4; i++)
{
Scalar color = Scalar(rng.uniform(0,255), rng.uniform(0, 255), rng.uniform(0, 255));
circle(color_image, corners[i], cvRound(show_radius), color, -1);
}
}
}
static
void drawFPS(Mat &color_image, double fps)
{
ostringstream convert;
convert << cv::format("%.2f", fps) << " FPS (" << getQRModeString() << ")";
putText(color_image, convert.str(), Point(25, 25), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 255), 2);
}
static
void drawQRCodeResults(Mat& frame, const vector<Point>& corners, const vector<cv::String>& decode_info, double fps)
{
if (!corners.empty())
{
for (size_t i = 0; i < corners.size(); i += 4)
{
size_t qr_idx = i / 4;
vector<Point> qrcode_contour(corners.begin() + i, corners.begin() + i + 4);
drawQRCodeContour(frame, qrcode_contour);
cout << "QR[" << qr_idx << "] @ " << Mat(qrcode_contour).reshape(2, 1) << ": ";
if (decode_info.size() > qr_idx)
{
if (!decode_info[qr_idx].empty())
cout << "'" << decode_info[qr_idx] << "'" << endl;
else
cout << "can't decode QR code" << endl;
}
else
{
cout << "decode information is not available (disabled)" << endl;
}
}
}
else
{
cout << "QR code is not detected" << endl;
}
drawFPS(frame, fps);
}
static
void runQR(
QRCodeDetector& qrcode, const Mat& input,
vector<Point>& corners, vector<cv::String>& decode_info
// +global: bool g_modeMultiQR, bool g_detectOnly
)
{
if (!g_modeMultiQR)
{
if (!g_detectOnly)
{
String decode_info1 = qrcode.detectAndDecode(input, corners);
decode_info.push_back(decode_info1);
}
else
{
bool detection_result = qrcode.detect(input, corners);
CV_UNUSED(detection_result);
}
}
else
{
if (!g_detectOnly)
{
bool result_detection = qrcode.detectAndDecodeMulti(input, decode_info, corners);
CV_UNUSED(result_detection);
}
else
{
bool result_detection = qrcode.detectMulti(input, corners);
CV_UNUSED(result_detection);
}
}
}
static
double processQRCodeDetection(QRCodeDetector& qrcode, const Mat& input, Mat& result, vector<Point>& corners)
{
if (input.channels() == 1)
cvtColor(input, result, COLOR_GRAY2BGR);
else
input.copyTo(result);
cout << "Run " << getQRModeString()
<< " on image: " << input.size() << " (" << typeToString(input.type()) << ")"
<< endl;
TickMeter timer;
vector<cv::String> decode_info;
timer.start();
runQR(qrcode, input, corners, decode_info);
timer.stop();
double fps = 1 / timer.getTimeSec();
drawQRCodeResults(result, corners, decode_info, fps);
return fps;
}
int liveQRCodeDetect()
{
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "Cannot open a camera" << endl;
return 2;
}
cout << "Press 'm' to switch between detectAndDecode and detectAndDecodeMulti" << endl;
cout << "Press 'd' to switch between decoder and detector" << endl;
cout << "Press ' ' (space) to save result into images" << endl;
cout << "Press 'ESC' to exit" << endl;
QRCodeDetector qrcode;
for (;;)
{
Mat frame;
cap >> frame;
if (frame.empty())
{
cout << "End of video stream" << endl;
break;
}
bool forceSave = g_saveAll;
Mat result;
try
{
vector<Point> corners;
double fps = processQRCodeDetection(qrcode, frame, result, corners);
cout << "FPS: " << fps << endl;
forceSave |= (g_saveDetections && !corners.empty());
//forceSave |= fps < 1.0;
}
catch (const cv::Exception& e)
{
cerr << "ERROR exception: " << e.what() << endl;
forceSave = true;
}
if (!result.empty())
imshow("QR code", result);
int code = waitKey(1);
if (code < 0 && !forceSave)
continue; // timeout
char c = (char)code;
if (c == ' ' || forceSave)
{
string fsuffix = cv::format("-%05d", g_save_idx++);
string fname_input = g_out_file_name + fsuffix + "_input.png";
cout << "Saving QR code detection input: '" << fname_input << "' ..." << endl;
imwrite(fname_input, frame);
string fname = g_out_file_name + fsuffix + g_out_file_ext;
cout << "Saving QR code detection result: '" << fname << "' ..." << endl;
imwrite(fname, result);
cout << "Saved" << endl;
}
if (c == 'm')
{
g_modeMultiQR = !g_modeMultiQR;
cout << "Switching QR code mode ==> " << (g_modeMultiQR ? "detectAndDecodeMulti" : "detectAndDecode") << endl;
}
if (c == 'd')
{
g_detectOnly = !g_detectOnly;
cout << "Switching QR decoder mode ==> " << (g_detectOnly ? "detect" : "decode") << endl;
}
if (c == 27)
{
cout << "'ESC' is pressed. Exiting..." << endl;
break;
}
}
cout << "Exit." << endl;
return 0;
}
int imageQRCodeDetect(const string& in_file)
{
const int count_experiments = 10;
Mat input = imread(in_file, IMREAD_COLOR);
cout << "Run " << getQRModeString()
<< " on image: " << input.size() << " (" << typeToString(input.type()) << ")"
<< endl;
QRCodeDetector qrcode;
vector<Point> corners;
vector<cv::String> decode_info;
TickMeter timer;
for (size_t i = 0; i < count_experiments; i++)
{
corners.clear();
decode_info.clear();
timer.start();
runQR(qrcode, input, corners, decode_info);
timer.stop();
}
double fps = count_experiments / timer.getTimeSec();
cout << "FPS: " << fps << endl;
Mat result; input.copyTo(result);
drawQRCodeResults(result, corners, decode_info, fps);
imshow("QR", result); waitKey(1);
if (!g_out_file_name.empty())
{
string out_file = g_out_file_name + g_out_file_ext;
cout << "Saving result: " << out_file << endl;
imwrite(out_file, result);
}
cout << "Press any key to exit ..." << endl;
waitKey(0);
cout << "Exit." << endl;
return 0;
}

View File

@ -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;
}

View File

@ -0,0 +1,608 @@
/*
*
* select3obj.cpp With a calibration chessboard on a table, mark an object in a 3D box and
* track that object in all subsequent frames as long as the camera can see
* the chessboard. Also segments the object using the box projection. This
* program is useful for collecting large datasets of many views of an object
* on a table.
*
*/
#include "opencv2/core.hpp"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
using namespace cv;
static string helphelp(char** argv)
{
return string("\nThis program's purpose is to collect data sets of an object and its segmentation mask.\n")
+ "\n"
"It shows how to use a calibrated camera together with a calibration pattern to\n"
"compute the homography of the plane the calibration pattern is on. It also shows grabCut\n"
"segmentation etc.\n"
"\n"
+ argv[0]
+ " -w=<board_width> -h=<board_height> [-s=<square_size>]\n"
" -i=<camera_intrinsics_filename> -o=<output_prefix>\n"
"\n"
" -w=<board_width> Number of chessboard corners wide\n"
" -h=<board_height> Number of chessboard corners width\n"
" [-s=<square_size>] Optional measure of chessboard squares in meters\n"
" -i=<camera_intrinsics_filename> Camera matrix .yml file from calibration.cpp\n"
" -o=<output_prefix> Prefix the output segmentation images with this\n"
" [video_filename/cameraId] If present, read from that video file or that ID\n"
"\n"
"Using a camera's intrinsics (from calibrating a camera -- see calibration.cpp) and an\n"
"image of the object sitting on a planar surface with a calibration pattern of\n"
"(board_width x board_height) on the surface, we draw a 3D box around the object. From\n"
"then on, we can move a camera and as long as it sees the chessboard calibration pattern,\n"
"it will store a mask of where the object is. We get successive images using <output_prefix>\n"
"of the segmentation mask containing the object. This makes creating training sets easy.\n"
"It is best if the chessboard is odd x even in dimensions to avoid ambiguous poses.\n"
"\n"
"The actions one can use while the program is running are:\n"
"\n"
" Select object as 3D box with the mouse.\n"
" First draw one line on the plane to outline the projection of that object on the plane\n"
" Then extend that line into a box to encompass the projection of that object onto the plane\n"
" The use the mouse again to extend the box upwards from the plane to encase the object.\n"
" Then use the following commands\n"
" ESC - Reset the selection\n"
" SPACE - Skip the frame; move to the next frame (not in video mode)\n"
" ENTER - Confirm the selection. Grab next object in video mode.\n"
" q - Exit the program\n"
"\n\n";
}
// static void help()
// {
// puts(helphelp);
// }
struct MouseEvent
{
MouseEvent() { event = -1; buttonState = 0; }
Point pt;
int event;
int buttonState;
};
static void onMouse(int event, int x, int y, int flags, void* userdata)
{
MouseEvent* data = (MouseEvent*)userdata;
data->event = event;
data->pt = Point(x,y);
data->buttonState = flags;
}
static bool readCameraMatrix(const string& filename,
Mat& cameraMatrix, Mat& distCoeffs,
Size& calibratedImageSize )
{
FileStorage fs(filename, FileStorage::READ);
fs["image_width"] >> calibratedImageSize.width;
fs["image_height"] >> calibratedImageSize.height;
fs["distortion_coefficients"] >> distCoeffs;
fs["camera_matrix"] >> cameraMatrix;
if( distCoeffs.type() != CV_64F )
distCoeffs = Mat_<double>(distCoeffs);
if( cameraMatrix.type() != CV_64F )
cameraMatrix = Mat_<double>(cameraMatrix);
return true;
}
static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners)
{
corners.resize(0);
for( int i = 0; i < boardSize.height; i++ )
for( int j = 0; j < boardSize.width; j++ )
corners.push_back(Point3f(float(j*squareSize),
float(i*squareSize), 0));
}
static Point3f image2plane(Point2f imgpt, const Mat& R, const Mat& tvec,
const Mat& cameraMatrix, double Z)
{
Mat R1 = R.clone();
R1.col(2) = R1.col(2)*Z + tvec;
Mat_<double> v = (cameraMatrix*R1).inv()*(Mat_<double>(3,1) << imgpt.x, imgpt.y, 1);
double iw = fabs(v(2,0)) > DBL_EPSILON ? 1./v(2,0) : 0;
return Point3f((float)(v(0,0)*iw), (float)(v(1,0)*iw), (float)Z);
}
static Rect extract3DBox(const Mat& frame, Mat& shownFrame, Mat& selectedObjFrame,
const Mat& cameraMatrix, const Mat& rvec, const Mat& tvec,
const vector<Point3f>& box, int nobjpt, bool runExtraSegmentation)
{
selectedObjFrame = Mat::zeros(frame.size(), frame.type());
if( nobjpt == 0 )
return Rect();
vector<Point3f> objpt;
vector<Point2f> imgpt;
objpt.push_back(box[0]);
if( nobjpt > 1 )
objpt.push_back(box[1]);
if( nobjpt > 2 )
{
objpt.push_back(box[2]);
objpt.push_back(objpt[2] - objpt[1] + objpt[0]);
}
if( nobjpt > 3 )
for( int i = 0; i < 4; i++ )
objpt.push_back(Point3f(objpt[i].x, objpt[i].y, box[3].z));
projectPoints(Mat(objpt), rvec, tvec, cameraMatrix, Mat(), imgpt);
if( !shownFrame.empty() )
{
if( nobjpt == 1 )
circle(shownFrame, imgpt[0], 3, Scalar(0,255,0), -1, LINE_AA);
else if( nobjpt == 2 )
{
circle(shownFrame, imgpt[0], 3, Scalar(0,255,0), -1, LINE_AA);
circle(shownFrame, imgpt[1], 3, Scalar(0,255,0), -1, LINE_AA);
line(shownFrame, imgpt[0], imgpt[1], Scalar(0,255,0), 3, LINE_AA);
}
else if( nobjpt == 3 )
for( int i = 0; i < 4; i++ )
{
circle(shownFrame, imgpt[i], 3, Scalar(0,255,0), -1, LINE_AA);
line(shownFrame, imgpt[i], imgpt[(i+1)%4], Scalar(0,255,0), 3, LINE_AA);
}
else
for( int i = 0; i < 8; i++ )
{
circle(shownFrame, imgpt[i], 3, Scalar(0,255,0), -1, LINE_AA);
line(shownFrame, imgpt[i], imgpt[(i+1)%4 + (i/4)*4], Scalar(0,255,0), 3, LINE_AA);
line(shownFrame, imgpt[i], imgpt[i%4], Scalar(0,255,0), 3, LINE_AA);
}
}
if( nobjpt <= 2 )
return Rect();
vector<Point> hull;
convexHull(Mat_<Point>(Mat(imgpt)), hull);
Mat selectedObjMask = Mat::zeros(frame.size(), CV_8U);
fillConvexPoly(selectedObjMask, &hull[0], (int)hull.size(), Scalar::all(255), 8, 0);
Rect roi = boundingRect(Mat(hull)) & Rect(Point(), frame.size());
if( runExtraSegmentation )
{
selectedObjMask = Scalar::all(GC_BGD);
fillConvexPoly(selectedObjMask, &hull[0], (int)hull.size(), Scalar::all(GC_PR_FGD), 8, 0);
Mat bgdModel, fgdModel;
grabCut(frame, selectedObjMask, roi, bgdModel, fgdModel,
3, GC_INIT_WITH_RECT + GC_INIT_WITH_MASK);
bitwise_and(selectedObjMask, Scalar::all(1), selectedObjMask);
}
frame.copyTo(selectedObjFrame, selectedObjMask);
return roi;
}
static int select3DBox(const string& windowname, const string& selWinName, const Mat& frame,
const Mat& cameraMatrix, const Mat& rvec, const Mat& tvec,
vector<Point3f>& box)
{
const float eps = 1e-3f;
MouseEvent mouse;
setMouseCallback(windowname, onMouse, &mouse);
vector<Point3f> tempobj(8);
vector<Point2f> imgpt(4), tempimg(8);
vector<Point> temphull;
int nobjpt = 0;
Mat R, selectedObjMask, selectedObjFrame, shownFrame;
Rodrigues(rvec, R);
box.resize(4);
for(;;)
{
float Z = 0.f;
bool dragging = (mouse.buttonState & EVENT_FLAG_LBUTTON) != 0;
int npt = nobjpt;
if( (mouse.event == EVENT_LBUTTONDOWN ||
mouse.event == EVENT_LBUTTONUP ||
dragging) && nobjpt < 4 )
{
Point2f m = mouse.pt;
if( nobjpt < 2 )
imgpt[npt] = m;
else
{
tempobj.resize(1);
int nearestIdx = npt-1;
if( nobjpt == 3 )
{
nearestIdx = 0;
for( int i = 1; i < npt; i++ )
if( norm(m - imgpt[i]) < norm(m - imgpt[nearestIdx]) )
nearestIdx = i;
}
if( npt == 2 )
{
float dx = box[1].x - box[0].x, dy = box[1].y - box[0].y;
float len = 1.f/std::sqrt(dx*dx+dy*dy);
tempobj[0] = Point3f(dy*len + box[nearestIdx].x,
-dx*len + box[nearestIdx].y, 0.f);
}
else
tempobj[0] = Point3f(box[nearestIdx].x, box[nearestIdx].y, 1.f);
projectPoints(Mat(tempobj), rvec, tvec, cameraMatrix, Mat(), tempimg);
Point2f a = imgpt[nearestIdx], b = tempimg[0], d1 = b - a, d2 = m - a;
float n1 = (float)norm(d1), n2 = (float)norm(d2);
if( n1*n2 < eps )
imgpt[npt] = a;
else
{
Z = d1.dot(d2)/(n1*n1);
imgpt[npt] = d1*Z + a;
}
}
box[npt] = image2plane(imgpt[npt], R, tvec, cameraMatrix, npt<3 ? 0 : Z);
if( (npt == 0 && mouse.event == EVENT_LBUTTONDOWN) ||
(npt > 0 && norm(box[npt] - box[npt-1]) > eps &&
mouse.event == EVENT_LBUTTONUP) )
{
nobjpt++;
if( nobjpt < 4 )
{
imgpt[nobjpt] = imgpt[nobjpt-1];
box[nobjpt] = box[nobjpt-1];
}
}
// reset the event
mouse.event = -1;
//mouse.buttonState = 0;
npt++;
}
frame.copyTo(shownFrame);
extract3DBox(frame, shownFrame, selectedObjFrame,
cameraMatrix, rvec, tvec, box, npt, false);
imshow(windowname, shownFrame);
imshow(selWinName, selectedObjFrame);
char c = (char)waitKey(30);
if( c == 27 )
{
nobjpt = 0;
}
if( c == 'q' || c == 'Q' || c == ' ' )
{
box.clear();
return c == ' ' ? -1 : -100;
}
if( (c == '\r' || c == '\n') && nobjpt == 4 && box[3].z != 0 )
return 1;
}
}
static bool readModelViews( const string& filename, vector<Point3f>& box,
vector<string>& imagelist,
vector<Rect>& roiList, vector<Vec6f>& poseList )
{
imagelist.resize(0);
roiList.resize(0);
poseList.resize(0);
box.resize(0);
FileStorage fs(filename, FileStorage::READ);
if( !fs.isOpened() )
return false;
fs["box"] >> box;
FileNode all = fs["views"];
if( all.type() != FileNode::SEQ )
return false;
FileNodeIterator it = all.begin(), it_end = all.end();
for(; it != it_end; ++it)
{
FileNode n = *it;
imagelist.push_back((string)n["image"]);
FileNode nr = n["rect"];
roiList.push_back(Rect((int)nr[0], (int)nr[1], (int)nr[2], (int)nr[3]));
FileNode np = n["pose"];
poseList.push_back(Vec6f((float)np[0], (float)np[1], (float)np[2],
(float)np[3], (float)np[4], (float)np[5]));
}
return true;
}
static bool writeModelViews(const string& filename, const vector<Point3f>& box,
const vector<string>& imagelist,
const vector<Rect>& roiList,
const vector<Vec6f>& poseList)
{
FileStorage fs(filename, FileStorage::WRITE);
if( !fs.isOpened() )
return false;
fs << "box" << "[:";
fs << box << "]" << "views" << "[";
size_t i, nviews = imagelist.size();
CV_Assert( nviews == roiList.size() && nviews == poseList.size() );
for( i = 0; i < nviews; i++ )
{
Rect r = roiList[i];
Vec6f p = poseList[i];
fs << "{" << "image" << imagelist[i] <<
"roi" << "[:" << r.x << r.y << r.width << r.height << "]" <<
"pose" << "[:" << p[0] << p[1] << p[2] << p[3] << p[4] << p[5] << "]" << "}";
}
fs << "]";
return true;
}
static bool readStringList( const string& filename, vector<string>& l )
{
l.resize(0);
FileStorage fs(filename, FileStorage::READ);
if( !fs.isOpened() )
return false;
FileNode n = fs.getFirstTopLevelNode();
if( n.type() != FileNode::SEQ )
return false;
FileNodeIterator it = n.begin(), it_end = n.end();
for( ; it != it_end; ++it )
l.push_back((string)*it);
return true;
}
int main(int argc, char** argv)
{
string help = string("Usage: ") + argv[0] + " -w=<board_width> -h=<board_height> [-s=<square_size>]\n" +
"\t-i=<intrinsics_filename> -o=<output_prefix> [video_filename/cameraId]\n";
const char* screen_help =
"Actions: \n"
"\tSelect object as 3D box with the mouse. That's it\n"
"\tESC - Reset the selection\n"
"\tSPACE - Skip the frame; move to the next frame (not in video mode)\n"
"\tENTER - Confirm the selection. Grab next object in video mode.\n"
"\tq - Exit the program\n";
cv::CommandLineParser parser(argc, argv, "{help h||}{w||}{h||}{s|1|}{i||}{o||}{@input|0|}");
if (parser.has("help"))
{
puts(helphelp(argv).c_str());
puts(help.c_str());
return 0;
}
string intrinsicsFilename;
string outprefix = "";
string inputName = "";
int cameraId = 0;
Size boardSize;
double squareSize;
vector<string> imageList;
intrinsicsFilename = parser.get<string>("i");
outprefix = parser.get<string>("o");
boardSize.width = parser.get<int>("w");
boardSize.height = parser.get<int>("h");
squareSize = parser.get<double>("s");
if ( parser.get<string>("@input").size() == 1 && isdigit(parser.get<string>("@input")[0]) )
cameraId = parser.get<int>("@input");
else
inputName = samples::findFileOrKeep(parser.get<string>("@input"));
if (!parser.check())
{
puts(help.c_str());
parser.printErrors();
return 0;
}
if ( boardSize.width <= 0 )
{
printf("Incorrect -w parameter (must be a positive integer)\n");
puts(help.c_str());
return 0;
}
if ( boardSize.height <= 0 )
{
printf("Incorrect -h parameter (must be a positive integer)\n");
puts(help.c_str());
return 0;
}
if ( squareSize <= 0 )
{
printf("Incorrect -s parameter (must be a positive real number)\n");
puts(help.c_str());
return 0;
}
Mat cameraMatrix, distCoeffs;
Size calibratedImageSize;
readCameraMatrix(intrinsicsFilename, cameraMatrix, distCoeffs, calibratedImageSize );
VideoCapture capture;
if( !inputName.empty() )
{
if( !readStringList(inputName, imageList) &&
!capture.open(inputName))
{
fprintf( stderr, "The input file could not be opened\n" );
return -1;
}
}
else
capture.open(cameraId);
if( !capture.isOpened() && imageList.empty() )
return fprintf( stderr, "Could not initialize video capture\n" ), -2;
const char* outbarename = 0;
{
outbarename = strrchr(outprefix.c_str(), '/');
const char* tmp = strrchr(outprefix.c_str(), '\\');
char cmd[1000];
sprintf(cmd, "mkdir %s", outprefix.c_str());
if( tmp && tmp > outbarename )
outbarename = tmp;
if( outbarename )
{
cmd[6 + outbarename - outprefix.c_str()] = '\0';
int result = system(cmd);
CV_Assert(result == 0);
outbarename++;
}
else
outbarename = outprefix.c_str();
}
Mat frame, shownFrame, selectedObjFrame, mapxy;
namedWindow("View", 1);
namedWindow("Selected Object", 1);
setMouseCallback("View", onMouse, 0);
bool boardFound = false;
string indexFilename = cv::format("%s_index.yml", outprefix.c_str());
vector<string> capturedImgList;
vector<Rect> roiList;
vector<Vec6f> poseList;
vector<Point3f> box, boardPoints;
readModelViews(indexFilename, box, capturedImgList, roiList, poseList);
calcChessboardCorners(boardSize, (float)squareSize, boardPoints);
int frameIdx = 0;
bool grabNext = !imageList.empty();
puts(screen_help);
for(int i = 0;;i++)
{
Mat frame0;
if( !imageList.empty() )
{
if( i < (int)imageList.size() )
frame0 = imread(string(imageList[i]), 1);
}
else
capture >> frame0;
if( frame0.empty() )
break;
if( frame.empty() )
{
if( frame0.size() != calibratedImageSize )
{
double sx = (double)frame0.cols/calibratedImageSize.width;
double sy = (double)frame0.rows/calibratedImageSize.height;
// adjust the camera matrix for the new resolution
cameraMatrix.at<double>(0,0) *= sx;
cameraMatrix.at<double>(0,2) *= sx;
cameraMatrix.at<double>(1,1) *= sy;
cameraMatrix.at<double>(1,2) *= sy;
}
Mat dummy;
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
cameraMatrix, frame0.size(),
CV_32FC2, mapxy, dummy );
distCoeffs = Mat::zeros(5, 1, CV_64F);
}
remap(frame0, frame, mapxy, Mat(), INTER_LINEAR);
vector<Point2f> foundBoardCorners;
boardFound = findChessboardCorners(frame, boardSize, foundBoardCorners);
Mat rvec, tvec;
if( boardFound )
solvePnP(Mat(boardPoints), Mat(foundBoardCorners), cameraMatrix,
distCoeffs, rvec, tvec, false);
frame.copyTo(shownFrame);
drawChessboardCorners(shownFrame, boardSize, Mat(foundBoardCorners), boardFound);
selectedObjFrame = Mat::zeros(frame.size(), frame.type());
if( boardFound && grabNext )
{
if( box.empty() )
{
int code = select3DBox("View", "Selected Object", frame,
cameraMatrix, rvec, tvec, box);
if( code == -100 )
break;
}
if( !box.empty() )
{
Rect r = extract3DBox(frame, shownFrame, selectedObjFrame,
cameraMatrix, rvec, tvec, box, 4, true);
if( !r.empty() )
{
const int maxFrameIdx = 10000;
char path[1000];
for(;frameIdx < maxFrameIdx;frameIdx++)
{
sprintf(path, "%s%04d.jpg", outprefix.c_str(), frameIdx);
FILE* f = fopen(path, "rb");
if( !f )
break;
fclose(f);
}
if( frameIdx == maxFrameIdx )
{
printf("Can not save the image as %s<...>.jpg", outprefix.c_str());
break;
}
imwrite(path, selectedObjFrame(r));
capturedImgList.push_back(string(path));
roiList.push_back(r);
float p[6];
Mat RV(3, 1, CV_32F, p), TV(3, 1, CV_32F, p+3);
rvec.convertTo(RV, RV.type());
tvec.convertTo(TV, TV.type());
poseList.push_back(Vec6f(p[0], p[1], p[2], p[3], p[4], p[5]));
}
}
grabNext = !imageList.empty();
}
imshow("View", shownFrame);
imshow("Selected Object", selectedObjFrame);
char c = (char)waitKey(imageList.empty() && !box.empty() ? 30 : 300);
if( c == 'q' || c == 'Q' )
break;
if( c == '\r' || c == '\n' )
grabNext = true;
}
writeModelViews(indexFilename, box, capturedImgList, roiList, poseList);
return 0;
}

View File

@ -0,0 +1,49 @@
#include "opencv2/core.hpp"
#include "opencv2/core/simd_intrinsics.hpp"
using namespace cv;
int main(int /*argc*/, char** /*argv*/)
{
printf("================== macro dump ===================\n");
#ifdef CV_SIMD
printf("CV_SIMD is defined: " CVAUX_STR(CV_SIMD) "\n");
#ifdef CV_SIMD_WIDTH
printf("CV_SIMD_WIDTH is defined: " CVAUX_STR(CV_SIMD_WIDTH) "\n");
#endif
#ifdef CV_SIMD128
printf("CV_SIMD128 is defined: " CVAUX_STR(CV_SIMD128) "\n");
#endif
#ifdef CV_SIMD256
printf("CV_SIMD256 is defined: " CVAUX_STR(CV_SIMD256) "\n");
#endif
#ifdef CV_SIMD512
printf("CV_SIMD512 is defined: " CVAUX_STR(CV_SIMD512) "\n");
#endif
#ifdef CV_SIMD_64F
printf("CV_SIMD_64F is defined: " CVAUX_STR(CV_SIMD_64F) "\n");
#endif
#ifdef CV_SIMD_FP16
printf("CV_SIMD_FP16 is defined: " CVAUX_STR(CV_SIMD_FP16) "\n");
#endif
#else
printf("CV_SIMD is NOT defined\n");
#endif
#ifdef CV_SIMD
printf("================= sizeof checks =================\n");
printf("sizeof(v_uint8) = %d\n", (int)sizeof(v_uint8));
printf("sizeof(v_int32) = %d\n", (int)sizeof(v_int32));
printf("sizeof(v_float32) = %d\n", (int)sizeof(v_float32));
printf("================== arithm check =================\n");
v_uint8 a = vx_setall_u8(10);
v_uint8 c = a + vx_setall_u8(45);
printf("(vx_setall_u8(10) + vx_setall_u8(45)).get0() => %d\n", (int)c.get0());
#else
printf("\nSIMD intrinsics are not available. Check compilation target and passed build options.\n");
#endif
printf("===================== done ======================\n");
return 0;
}

View File

@ -0,0 +1,215 @@
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(const char** argv)
{
cout << "\nThis program demonstrates the smile detector.\n"
"Usage:\n" <<
argv[0] << " [--cascade=<cascade_path> this is the frontal face classifier]\n"
" [--smile-cascade=[<smile_cascade_path>]]\n"
" [--scale=<image scale greater or equal to 1, try 2.0 for example. The larger the faster the processing>]\n"
" [--try-flip]\n"
" [video_filename|camera_index]\n\n"
"Example:\n" <<
argv[0] << " --cascade=\"data/haarcascades/haarcascade_frontalface_alt.xml\" --smile-cascade=\"data/haarcascades/haarcascade_smile.xml\" --scale=2.0\n\n"
"During execution:\n\tHit any key to quit.\n"
"\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip );
string cascadeName;
string nestedCascadeName;
int main( int argc, const char** argv )
{
VideoCapture capture;
Mat frame, image;
string inputName;
bool tryflip;
help(argv);
CascadeClassifier cascade, nestedCascade;
double scale;
cv::CommandLineParser parser(argc, argv,
"{help h||}{scale|1|}"
"{cascade|data/haarcascades/haarcascade_frontalface_alt.xml|}"
"{smile-cascade|data/haarcascades/haarcascade_smile.xml|}"
"{try-flip||}{@input||}");
if (parser.has("help"))
{
help(argv);
return 0;
}
cascadeName = samples::findFile(parser.get<string>("cascade"));
nestedCascadeName = samples::findFile(parser.get<string>("smile-cascade"));
tryflip = parser.has("try-flip");
inputName = parser.get<string>("@input");
scale = parser.get<int>("scale");
if (!parser.check())
{
help(argv);
return 1;
}
if (scale < 1)
scale = 1;
if( !cascade.load( cascadeName ) )
{
cerr << "ERROR: Could not load face cascade" << endl;
help(argv);
return -1;
}
if( !nestedCascade.load( nestedCascadeName ) )
{
cerr << "ERROR: Could not load smile cascade" << endl;
help(argv);
return -1;
}
if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
{
int c = inputName.empty() ? 0 : inputName[0] - '0' ;
if(!capture.open(c))
cout << "Capture from camera #" << c << " didn't work" << endl;
}
else if( inputName.size() )
{
inputName = samples::findFileOrKeep(inputName);
if(!capture.open( inputName ))
cout << "Could not read " << inputName << endl;
}
if( capture.isOpened() )
{
cout << "Video capturing has been started ..." << endl;
cout << endl << "NOTE: Smile intensity will only be valid after a first smile has been detected" << endl;
for(;;)
{
capture >> frame;
if( frame.empty() )
break;
Mat frame1 = frame.clone();
detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
char c = (char)waitKey(10);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
else
{
cerr << "ERROR: Could not initiate capture" << endl;
help(argv);
return -1;
}
return 0;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip)
{
vector<Rect> faces, faces2;
const static Scalar colors[] =
{
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)
};
Mat gray, smallImg;
cvtColor( img, gray, COLOR_BGR2GRAY );
double fx = 1 / scale;
resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR_EXACT );
equalizeHist( smallImg, smallImg );
cascade.detectMultiScale( smallImg, faces,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
if( tryflip )
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale( smallImg, faces2,
1.1, 2, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
{
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
}
}
for ( size_t i = 0; i < faces.size(); i++ )
{
Rect r = faces[i];
Mat smallImgROI;
vector<Rect> nestedObjects;
Point center;
Scalar color = colors[i%8];
int radius;
double aspect_ratio = (double)r.width/r.height;
if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
{
center.x = cvRound((r.x + r.width*0.5)*scale);
center.y = cvRound((r.y + r.height*0.5)*scale);
radius = cvRound((r.width + r.height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
else
rectangle( img, Point(cvRound(r.x*scale), cvRound(r.y*scale)),
Point(cvRound((r.x + r.width-1)*scale), cvRound((r.y + r.height-1)*scale)),
color, 3, 8, 0);
const int half_height=cvRound((float)r.height/2);
r.y=r.y + half_height;
r.height = half_height-1;
smallImgROI = smallImg( r );
nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
1.1, 0, 0
//|CASCADE_FIND_BIGGEST_OBJECT
//|CASCADE_DO_ROUGH_SEARCH
//|CASCADE_DO_CANNY_PRUNING
|CASCADE_SCALE_IMAGE,
Size(30, 30) );
// The number of detected neighbors depends on image size (and also illumination, etc.). The
// following steps use a floating minimum and maximum of neighbors. Intensity thus estimated will be
//accurate only after a first smile has been displayed by the user.
const int smile_neighbors = (int)nestedObjects.size();
static int max_neighbors=-1;
static int min_neighbors=-1;
if (min_neighbors == -1) min_neighbors = smile_neighbors;
max_neighbors = MAX(max_neighbors, smile_neighbors);
// Draw rectangle on the left side of the image reflecting smile intensity
float intensityZeroOne = ((float)smile_neighbors - min_neighbors) / (max_neighbors - min_neighbors + 1);
int rect_height = cvRound((float)img.rows * intensityZeroOne);
Scalar col = Scalar((float)255 * intensityZeroOne, 0, 0);
rectangle(img, Point(0, img.rows), Point(img.cols/10, img.rows - rect_height), col, -1);
}
imshow( "result", img );
}

View File

@ -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;
}

View File

@ -0,0 +1,371 @@
/* This is sample from the OpenCV book. The copyright notice is below */
/* *************** License:**************************
Oct. 3, 2008
Right to use this code in any way you want without warranty, support or any guarantee of it working.
BOOK: It would be nice if you cited it:
Learning OpenCV: Computer Vision with the OpenCV Library
by Gary Bradski and Adrian Kaehler
Published by O'Reilly Media, October 3, 2008
AVAILABLE AT:
http://www.amazon.com/Learning-OpenCV-Computer-Vision-Library/dp/0596516134
Or: http://oreilly.com/catalog/9780596516130/
ISBN-10: 0596516134 or: ISBN-13: 978-0596516130
OPENCV WEBSITES:
Homepage: http://opencv.org
Online docs: http://docs.opencv.org
GitHub: https://github.com/opencv/opencv/
************************************************** */
#include "opencv2/calib3d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
using namespace cv;
using namespace std;
static int print_help(char** argv)
{
cout <<
" Given a list of chessboard images, the number of corners (nx, ny)\n"
" on the chessboards, and a flag: useCalibrated for \n"
" calibrated (0) or\n"
" uncalibrated \n"
" (1: use stereoCalibrate(), 2: compute fundamental\n"
" matrix separately) stereo. \n"
" Calibrate the cameras and display the\n"
" rectified results along with the computed disparity images. \n" << endl;
cout << "Usage:\n " << argv[0] << " -w=<board_width default=9> -h=<board_height default=6> -s=<square_size default=1.0> <image list XML/YML file default=stereo_calib.xml>\n" << endl;
return 0;
}
static void
StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, bool displayCorners = false, bool useCalibrated=true, bool showRectified=true)
{
if( imagelist.size() % 2 != 0 )
{
cout << "Error: the image list contains odd (non-even) number of elements\n";
return;
}
const int maxScale = 2;
// ARRAY AND VECTOR STORAGE:
vector<vector<Point2f> > imagePoints[2];
vector<vector<Point3f> > objectPoints;
Size imageSize;
int i, j, k, nimages = (int)imagelist.size()/2;
imagePoints[0].resize(nimages);
imagePoints[1].resize(nimages);
vector<string> goodImageList;
for( i = j = 0; i < nimages; i++ )
{
for( k = 0; k < 2; k++ )
{
const string& filename = imagelist[i*2+k];
Mat img = imread(filename, 0);
if(img.empty())
break;
if( imageSize == Size() )
imageSize = img.size();
else if( img.size() != imageSize )
{
cout << "The image " << filename << " has the size different from the first image size. Skipping the pair\n";
break;
}
bool found = false;
vector<Point2f>& corners = imagePoints[k][j];
for( int scale = 1; scale <= maxScale; scale++ )
{
Mat timg;
if( scale == 1 )
timg = img;
else
resize(img, timg, Size(), scale, scale, INTER_LINEAR_EXACT);
found = findChessboardCorners(timg, boardSize, corners,
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
if( found )
{
if( scale > 1 )
{
Mat cornersMat(corners);
cornersMat *= 1./scale;
}
break;
}
}
if( displayCorners )
{
cout << filename << endl;
Mat cimg, cimg1;
cvtColor(img, cimg, COLOR_GRAY2BGR);
drawChessboardCorners(cimg, boardSize, corners, found);
double sf = 640./MAX(img.rows, img.cols);
resize(cimg, cimg1, Size(), sf, sf, INTER_LINEAR_EXACT);
imshow("corners", cimg1);
char c = (char)waitKey(500);
if( c == 27 || c == 'q' || c == 'Q' ) //Allow ESC to quit
exit(-1);
}
else
putchar('.');
if( !found )
break;
cornerSubPix(img, corners, Size(11,11), Size(-1,-1),
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,
30, 0.01));
}
if( k == 2 )
{
goodImageList.push_back(imagelist[i*2]);
goodImageList.push_back(imagelist[i*2+1]);
j++;
}
}
cout << j << " pairs have been successfully detected.\n";
nimages = j;
if( nimages < 2 )
{
cout << "Error: too little pairs to run the calibration\n";
return;
}
imagePoints[0].resize(nimages);
imagePoints[1].resize(nimages);
objectPoints.resize(nimages);
for( i = 0; i < nimages; i++ )
{
for( j = 0; j < boardSize.height; j++ )
for( k = 0; k < boardSize.width; k++ )
objectPoints[i].push_back(Point3f(k*squareSize, j*squareSize, 0));
}
cout << "Running stereo calibration ...\n";
Mat cameraMatrix[2], distCoeffs[2];
cameraMatrix[0] = initCameraMatrix2D(objectPoints,imagePoints[0],imageSize,0);
cameraMatrix[1] = initCameraMatrix2D(objectPoints,imagePoints[1],imageSize,0);
Mat R, T, E, F;
double rms = stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1],
cameraMatrix[0], distCoeffs[0],
cameraMatrix[1], distCoeffs[1],
imageSize, R, T, E, F,
CALIB_FIX_ASPECT_RATIO +
CALIB_ZERO_TANGENT_DIST +
CALIB_USE_INTRINSIC_GUESS +
CALIB_SAME_FOCAL_LENGTH +
CALIB_RATIONAL_MODEL +
CALIB_FIX_K3 + CALIB_FIX_K4 + CALIB_FIX_K5,
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 100, 1e-5) );
cout << "done with RMS error=" << rms << endl;
// CALIBRATION QUALITY CHECK
// because the output fundamental matrix implicitly
// includes all the output information,
// we can check the quality of calibration using the
// epipolar geometry constraint: m2^t*F*m1=0
double err = 0;
int npoints = 0;
vector<Vec3f> lines[2];
for( i = 0; i < nimages; i++ )
{
int npt = (int)imagePoints[0][i].size();
Mat imgpt[2];
for( k = 0; k < 2; k++ )
{
imgpt[k] = Mat(imagePoints[k][i]);
undistortPoints(imgpt[k], imgpt[k], cameraMatrix[k], distCoeffs[k], Mat(), cameraMatrix[k]);
computeCorrespondEpilines(imgpt[k], k+1, F, lines[k]);
}
for( j = 0; j < npt; j++ )
{
double errij = fabs(imagePoints[0][i][j].x*lines[1][j][0] +
imagePoints[0][i][j].y*lines[1][j][1] + lines[1][j][2]) +
fabs(imagePoints[1][i][j].x*lines[0][j][0] +
imagePoints[1][i][j].y*lines[0][j][1] + lines[0][j][2]);
err += errij;
}
npoints += npt;
}
cout << "average epipolar err = " << err/npoints << endl;
// save intrinsic parameters
FileStorage fs("intrinsics.yml", FileStorage::WRITE);
if( fs.isOpened() )
{
fs << "M1" << cameraMatrix[0] << "D1" << distCoeffs[0] <<
"M2" << cameraMatrix[1] << "D2" << distCoeffs[1];
fs.release();
}
else
cout << "Error: can not save the intrinsic parameters\n";
Mat R1, R2, P1, P2, Q;
Rect validRoi[2];
stereoRectify(cameraMatrix[0], distCoeffs[0],
cameraMatrix[1], distCoeffs[1],
imageSize, R, T, R1, R2, P1, P2, Q,
CALIB_ZERO_DISPARITY, 1, imageSize, &validRoi[0], &validRoi[1]);
fs.open("extrinsics.yml", FileStorage::WRITE);
if( fs.isOpened() )
{
fs << "R" << R << "T" << T << "R1" << R1 << "R2" << R2 << "P1" << P1 << "P2" << P2 << "Q" << Q;
fs.release();
}
else
cout << "Error: can not save the extrinsic parameters\n";
// OpenCV can handle left-right
// or up-down camera arrangements
bool isVerticalStereo = fabs(P2.at<double>(1, 3)) > fabs(P2.at<double>(0, 3));
// COMPUTE AND DISPLAY RECTIFICATION
if( !showRectified )
return;
Mat rmap[2][2];
// IF BY CALIBRATED (BOUGUET'S METHOD)
if( useCalibrated )
{
// we already computed everything
}
// OR ELSE HARTLEY'S METHOD
else
// use intrinsic parameters of each camera, but
// compute the rectification transformation directly
// from the fundamental matrix
{
vector<Point2f> allimgpt[2];
for( k = 0; k < 2; k++ )
{
for( i = 0; i < nimages; i++ )
std::copy(imagePoints[k][i].begin(), imagePoints[k][i].end(), back_inserter(allimgpt[k]));
}
F = findFundamentalMat(Mat(allimgpt[0]), Mat(allimgpt[1]), FM_8POINT, 0, 0);
Mat H1, H2;
stereoRectifyUncalibrated(Mat(allimgpt[0]), Mat(allimgpt[1]), F, imageSize, H1, H2, 3);
R1 = cameraMatrix[0].inv()*H1*cameraMatrix[0];
R2 = cameraMatrix[1].inv()*H2*cameraMatrix[1];
P1 = cameraMatrix[0];
P2 = cameraMatrix[1];
}
//Precompute maps for cv::remap()
initUndistortRectifyMap(cameraMatrix[0], distCoeffs[0], R1, P1, imageSize, CV_16SC2, rmap[0][0], rmap[0][1]);
initUndistortRectifyMap(cameraMatrix[1], distCoeffs[1], R2, P2, imageSize, CV_16SC2, rmap[1][0], rmap[1][1]);
Mat canvas;
double sf;
int w, h;
if( !isVerticalStereo )
{
sf = 600./MAX(imageSize.width, imageSize.height);
w = cvRound(imageSize.width*sf);
h = cvRound(imageSize.height*sf);
canvas.create(h, w*2, CV_8UC3);
}
else
{
sf = 300./MAX(imageSize.width, imageSize.height);
w = cvRound(imageSize.width*sf);
h = cvRound(imageSize.height*sf);
canvas.create(h*2, w, CV_8UC3);
}
for( i = 0; i < nimages; i++ )
{
for( k = 0; k < 2; k++ )
{
Mat img = imread(goodImageList[i*2+k], 0), rimg, cimg;
remap(img, rimg, rmap[k][0], rmap[k][1], INTER_LINEAR);
cvtColor(rimg, cimg, COLOR_GRAY2BGR);
Mat canvasPart = !isVerticalStereo ? canvas(Rect(w*k, 0, w, h)) : canvas(Rect(0, h*k, w, h));
resize(cimg, canvasPart, canvasPart.size(), 0, 0, INTER_AREA);
if( useCalibrated )
{
Rect vroi(cvRound(validRoi[k].x*sf), cvRound(validRoi[k].y*sf),
cvRound(validRoi[k].width*sf), cvRound(validRoi[k].height*sf));
rectangle(canvasPart, vroi, Scalar(0,0,255), 3, 8);
}
}
if( !isVerticalStereo )
for( j = 0; j < canvas.rows; j += 16 )
line(canvas, Point(0, j), Point(canvas.cols, j), Scalar(0, 255, 0), 1, 8);
else
for( j = 0; j < canvas.cols; j += 16 )
line(canvas, Point(j, 0), Point(j, canvas.rows), Scalar(0, 255, 0), 1, 8);
imshow("rectified", canvas);
char c = (char)waitKey();
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
static bool readStringList( const string& filename, vector<string>& l )
{
l.resize(0);
FileStorage fs(filename, FileStorage::READ);
if( !fs.isOpened() )
return false;
FileNode n = fs.getFirstTopLevelNode();
if( n.type() != FileNode::SEQ )
return false;
FileNodeIterator it = n.begin(), it_end = n.end();
for( ; it != it_end; ++it )
l.push_back((string)*it);
return true;
}
int main(int argc, char** argv)
{
Size boardSize;
string imagelistfn;
bool showRectified;
cv::CommandLineParser parser(argc, argv, "{w|9|}{h|6|}{s|1.0|}{nr||}{help||}{@input|stereo_calib.xml|}");
if (parser.has("help"))
return print_help(argv);
showRectified = !parser.has("nr");
imagelistfn = samples::findFile(parser.get<string>("@input"));
boardSize.width = parser.get<int>("w");
boardSize.height = parser.get<int>("h");
float squareSize = parser.get<float>("s");
if (!parser.check())
{
parser.printErrors();
return 1;
}
vector<string> imagelist;
bool ok = readStringList(imagelistfn, imagelist);
if(!ok || imagelist.empty())
{
cout << "can not open " << imagelistfn << " or the string list is empty" << endl;
return print_help(argv);
}
StereoCalib(imagelist, boardSize, squareSize, false, true, showRectified);
return 0;
}

View File

@ -0,0 +1,328 @@
/*
* stereo_match.cpp
* calibration
*
* Created by Victor Eruhimov on 1/18/10.
* Copyright 2010 Argus Corp. All rights reserved.
*
*/
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/utility.hpp"
#include <stdio.h>
#include <sstream>
using namespace cv;
static void print_help(char** argv)
{
printf("\nDemo stereo matching converting L and R images into disparity and point clouds\n");
printf("\nUsage: %s <left_image> <right_image> [--algorithm=bm|sgbm|hh|hh4|sgbm3way] [--blocksize=<block_size>]\n"
"[--max-disparity=<max_disparity>] [--scale=scale_factor>] [-i=<intrinsic_filename>] [-e=<extrinsic_filename>]\n"
"[--no-display] [--color] [-o=<disparity_image>] [-p=<point_cloud_file>]\n", argv[0]);
}
static void saveXYZ(const char* filename, const Mat& mat)
{
const double max_z = 1.0e4;
FILE* fp = fopen(filename, "wt");
for(int y = 0; y < mat.rows; y++)
{
for(int x = 0; x < mat.cols; x++)
{
Vec3f point = mat.at<Vec3f>(y, x);
if(fabs(point[2] - max_z) < FLT_EPSILON || fabs(point[2]) > max_z) continue;
fprintf(fp, "%f %f %f\n", point[0], point[1], point[2]);
}
}
fclose(fp);
}
int main(int argc, char** argv)
{
std::string img1_filename = "";
std::string img2_filename = "";
std::string intrinsic_filename = "";
std::string extrinsic_filename = "";
std::string disparity_filename = "";
std::string point_cloud_filename = "";
enum { STEREO_BM=0, STEREO_SGBM=1, STEREO_HH=2, STEREO_VAR=3, STEREO_3WAY=4, STEREO_HH4=5 };
int alg = STEREO_SGBM;
int SADWindowSize, numberOfDisparities;
bool no_display;
bool color_display;
float scale;
Ptr<StereoBM> bm = StereoBM::create(16,9);
Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,16,3);
cv::CommandLineParser parser(argc, argv,
"{@arg1||}{@arg2||}{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{color||}{scale|1|}{i||}{e||}{o||}{p||}");
if(parser.has("help"))
{
print_help(argv);
return 0;
}
img1_filename = samples::findFile(parser.get<std::string>(0));
img2_filename = samples::findFile(parser.get<std::string>(1));
if (parser.has("algorithm"))
{
std::string _alg = parser.get<std::string>("algorithm");
alg = _alg == "bm" ? STEREO_BM :
_alg == "sgbm" ? STEREO_SGBM :
_alg == "hh" ? STEREO_HH :
_alg == "var" ? STEREO_VAR :
_alg == "hh4" ? STEREO_HH4 :
_alg == "sgbm3way" ? STEREO_3WAY : -1;
}
numberOfDisparities = parser.get<int>("max-disparity");
SADWindowSize = parser.get<int>("blocksize");
scale = parser.get<float>("scale");
no_display = parser.has("no-display");
color_display = parser.has("color");
if( parser.has("i") )
intrinsic_filename = parser.get<std::string>("i");
if( parser.has("e") )
extrinsic_filename = parser.get<std::string>("e");
if( parser.has("o") )
disparity_filename = parser.get<std::string>("o");
if( parser.has("p") )
point_cloud_filename = parser.get<std::string>("p");
if (!parser.check())
{
parser.printErrors();
return 1;
}
if( alg < 0 )
{
printf("Command-line parameter error: Unknown stereo algorithm\n\n");
print_help(argv);
return -1;
}
if ( numberOfDisparities < 1 || numberOfDisparities % 16 != 0 )
{
printf("Command-line parameter error: The max disparity (--maxdisparity=<...>) must be a positive integer divisible by 16\n");
print_help(argv);
return -1;
}
if (scale < 0)
{
printf("Command-line parameter error: The scale factor (--scale=<...>) must be a positive floating-point number\n");
return -1;
}
if (SADWindowSize < 1 || SADWindowSize % 2 != 1)
{
printf("Command-line parameter error: The block size (--blocksize=<...>) must be a positive odd number\n");
return -1;
}
if( img1_filename.empty() || img2_filename.empty() )
{
printf("Command-line parameter error: both left and right images must be specified\n");
return -1;
}
if( (!intrinsic_filename.empty()) ^ (!extrinsic_filename.empty()) )
{
printf("Command-line parameter error: either both intrinsic and extrinsic parameters must be specified, or none of them (when the stereo pair is already rectified)\n");
return -1;
}
if( extrinsic_filename.empty() && !point_cloud_filename.empty() )
{
printf("Command-line parameter error: extrinsic and intrinsic parameters must be specified to compute the point cloud\n");
return -1;
}
int color_mode = alg == STEREO_BM ? 0 : -1;
Mat img1 = imread(img1_filename, color_mode);
Mat img2 = imread(img2_filename, color_mode);
if (img1.empty())
{
printf("Command-line parameter error: could not load the first input image file\n");
return -1;
}
if (img2.empty())
{
printf("Command-line parameter error: could not load the second input image file\n");
return -1;
}
if (scale != 1.f)
{
Mat temp1, temp2;
int method = scale < 1 ? INTER_AREA : INTER_CUBIC;
resize(img1, temp1, Size(), scale, scale, method);
img1 = temp1;
resize(img2, temp2, Size(), scale, scale, method);
img2 = temp2;
}
Size img_size = img1.size();
Rect roi1, roi2;
Mat Q;
if( !intrinsic_filename.empty() )
{
// reading intrinsic parameters
FileStorage fs(intrinsic_filename, FileStorage::READ);
if(!fs.isOpened())
{
printf("Failed to open file %s\n", intrinsic_filename.c_str());
return -1;
}
Mat M1, D1, M2, D2;
fs["M1"] >> M1;
fs["D1"] >> D1;
fs["M2"] >> M2;
fs["D2"] >> D2;
M1 *= scale;
M2 *= scale;
fs.open(extrinsic_filename, FileStorage::READ);
if(!fs.isOpened())
{
printf("Failed to open file %s\n", extrinsic_filename.c_str());
return -1;
}
Mat R, T, R1, P1, R2, P2;
fs["R"] >> R;
fs["T"] >> T;
stereoRectify( M1, D1, M2, D2, img_size, R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY, -1, img_size, &roi1, &roi2 );
Mat map11, map12, map21, map22;
initUndistortRectifyMap(M1, D1, R1, P1, img_size, CV_16SC2, map11, map12);
initUndistortRectifyMap(M2, D2, R2, P2, img_size, CV_16SC2, map21, map22);
Mat img1r, img2r;
remap(img1, img1r, map11, map12, INTER_LINEAR);
remap(img2, img2r, map21, map22, INTER_LINEAR);
img1 = img1r;
img2 = img2r;
}
numberOfDisparities = numberOfDisparities > 0 ? numberOfDisparities : ((img_size.width/8) + 15) & -16;
bm->setROI1(roi1);
bm->setROI2(roi2);
bm->setPreFilterCap(31);
bm->setBlockSize(SADWindowSize > 0 ? SADWindowSize : 9);
bm->setMinDisparity(0);
bm->setNumDisparities(numberOfDisparities);
bm->setTextureThreshold(10);
bm->setUniquenessRatio(15);
bm->setSpeckleWindowSize(100);
bm->setSpeckleRange(32);
bm->setDisp12MaxDiff(1);
sgbm->setPreFilterCap(63);
int sgbmWinSize = SADWindowSize > 0 ? SADWindowSize : 3;
sgbm->setBlockSize(sgbmWinSize);
int cn = img1.channels();
sgbm->setP1(8*cn*sgbmWinSize*sgbmWinSize);
sgbm->setP2(32*cn*sgbmWinSize*sgbmWinSize);
sgbm->setMinDisparity(0);
sgbm->setNumDisparities(numberOfDisparities);
sgbm->setUniquenessRatio(10);
sgbm->setSpeckleWindowSize(100);
sgbm->setSpeckleRange(32);
sgbm->setDisp12MaxDiff(1);
if(alg==STEREO_HH)
sgbm->setMode(StereoSGBM::MODE_HH);
else if(alg==STEREO_SGBM)
sgbm->setMode(StereoSGBM::MODE_SGBM);
else if(alg==STEREO_HH4)
sgbm->setMode(StereoSGBM::MODE_HH4);
else if(alg==STEREO_3WAY)
sgbm->setMode(StereoSGBM::MODE_SGBM_3WAY);
Mat disp, disp8;
//Mat img1p, img2p, dispp;
//copyMakeBorder(img1, img1p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
//copyMakeBorder(img2, img2p, 0, 0, numberOfDisparities, 0, IPL_BORDER_REPLICATE);
int64 t = getTickCount();
float disparity_multiplier = 1.0f;
if( alg == STEREO_BM )
{
bm->compute(img1, img2, disp);
if (disp.type() == CV_16S)
disparity_multiplier = 16.0f;
}
else if( alg == STEREO_SGBM || alg == STEREO_HH || alg == STEREO_HH4 || alg == STEREO_3WAY )
{
sgbm->compute(img1, img2, disp);
if (disp.type() == CV_16S)
disparity_multiplier = 16.0f;
}
t = getTickCount() - t;
printf("Time elapsed: %fms\n", t*1000/getTickFrequency());
//disp = dispp.colRange(numberOfDisparities, img1p.cols);
if( alg != STEREO_VAR )
disp.convertTo(disp8, CV_8U, 255/(numberOfDisparities*16.));
else
disp.convertTo(disp8, CV_8U);
Mat disp8_3c;
if (color_display)
cv::applyColorMap(disp8, disp8_3c, COLORMAP_TURBO);
if(!disparity_filename.empty())
imwrite(disparity_filename, color_display ? disp8_3c : disp8);
if(!point_cloud_filename.empty())
{
printf("storing the point cloud...");
fflush(stdout);
Mat xyz;
Mat floatDisp;
disp.convertTo(floatDisp, CV_32F, 1.0f / disparity_multiplier);
reprojectImageTo3D(floatDisp, xyz, Q, true);
saveXYZ(point_cloud_filename.c_str(), xyz);
printf("\n");
}
if( !no_display )
{
std::ostringstream oss;
oss << "disparity " << (alg==STEREO_BM ? "bm" :
alg==STEREO_SGBM ? "sgbm" :
alg==STEREO_HH ? "hh" :
alg==STEREO_VAR ? "var" :
alg==STEREO_HH4 ? "hh4" :
alg==STEREO_3WAY ? "sgbm3way" : "");
oss << " blocksize:" << (alg==STEREO_BM ? SADWindowSize : sgbmWinSize);
oss << " max-disparity:" << numberOfDisparities;
std::string disp_name = oss.str();
namedWindow("left", cv::WINDOW_NORMAL);
imshow("left", img1);
namedWindow("right", cv::WINDOW_NORMAL);
imshow("right", img2);
namedWindow(disp_name, cv::WINDOW_AUTOSIZE);
imshow(disp_name, color_display ? disp8_3c : disp8);
printf("press ESC key or CTRL+C to close...");
fflush(stdout);
printf("\n");
while(1)
{
if(waitKey() == 27) //ESC (prevents closing on actions like taking screenshots)
break;
}
}
return 0;
}

View File

@ -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;
}

View File

@ -0,0 +1,937 @@
#include <iostream>
#include <fstream>
#include <string>
#include "opencv2/opencv_modules.hpp"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/stitching/detail/autocalib.hpp"
#include "opencv2/stitching/detail/blenders.hpp"
#include "opencv2/stitching/detail/timelapsers.hpp"
#include "opencv2/stitching/detail/camera.hpp"
#include "opencv2/stitching/detail/exposure_compensate.hpp"
#include "opencv2/stitching/detail/matchers.hpp"
#include "opencv2/stitching/detail/motion_estimators.hpp"
#include "opencv2/stitching/detail/seam_finders.hpp"
#include "opencv2/stitching/detail/warpers.hpp"
#include "opencv2/stitching/warpers.hpp"
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/xfeatures2d/nonfree.hpp"
#endif
#define ENABLE_LOG 1
#define LOG(msg) std::cout << msg
#define LOGLN(msg) std::cout << msg << std::endl
using namespace std;
using namespace cv;
using namespace cv::detail;
static void printUsage(char** argv)
{
cout <<
"Rotation model images stitcher.\n\n"
<< argv[0] << " img1 img2 [...imgN] [flags]\n\n"
"Flags:\n"
" --preview\n"
" Run stitching in the preview mode. Works faster than usual mode,\n"
" but output image will have lower resolution.\n"
" --try_cuda (yes|no)\n"
" Try to use CUDA. The default value is 'no'. All default values\n"
" are for CPU mode.\n"
"\nMotion Estimation Flags:\n"
" --work_megapix <float>\n"
" Resolution for image registration step. The default is 0.6 Mpx.\n"
" --features (surf|orb|sift|akaze)\n"
" Type of features used for images matching.\n"
" The default is surf if available, orb otherwise.\n"
" --matcher (homography|affine)\n"
" Matcher used for pairwise image matching.\n"
" --estimator (homography|affine)\n"
" Type of estimator used for transformation estimation.\n"
" --match_conf <float>\n"
" Confidence for feature matching step. The default is 0.65 for surf and 0.3 for orb.\n"
" --conf_thresh <float>\n"
" Threshold for two images are from the same panorama confidence.\n"
" The default is 1.0.\n"
" --ba (no|reproj|ray|affine)\n"
" Bundle adjustment cost function. The default is ray.\n"
" --ba_refine_mask (mask)\n"
" Set refinement mask for bundle adjustment. It looks like 'x_xxx',\n"
" where 'x' means refine respective parameter and '_' means don't\n"
" refine one, and has the following format:\n"
" <fx><skew><ppx><aspect><ppy>. The default mask is 'xxxxx'. If bundle\n"
" adjustment doesn't support estimation of selected parameter then\n"
" the respective flag is ignored.\n"
" --wave_correct (no|horiz|vert)\n"
" Perform wave effect correction. The default is 'horiz'.\n"
" --save_graph <file_name>\n"
" Save matches graph represented in DOT language to <file_name> file.\n"
" Labels description: Nm is number of matches, Ni is number of inliers,\n"
" C is confidence.\n"
"\nCompositing Flags:\n"
" --warp (affine|plane|cylindrical|spherical|fisheye|stereographic|compressedPlaneA2B1|compressedPlaneA1.5B1|compressedPlanePortraitA2B1|compressedPlanePortraitA1.5B1|paniniA2B1|paniniA1.5B1|paniniPortraitA2B1|paniniPortraitA1.5B1|mercator|transverseMercator)\n"
" Warp surface type. The default is 'spherical'.\n"
" --seam_megapix <float>\n"
" Resolution for seam estimation step. The default is 0.1 Mpx.\n"
" --seam (no|voronoi|gc_color|gc_colorgrad)\n"
" Seam estimation method. The default is 'gc_color'.\n"
" --compose_megapix <float>\n"
" Resolution for compositing step. Use -1 for original resolution.\n"
" The default is -1.\n"
" --expos_comp (no|gain|gain_blocks|channels|channels_blocks)\n"
" Exposure compensation method. The default is 'gain_blocks'.\n"
" --expos_comp_nr_feeds <int>\n"
" Number of exposure compensation feed. The default is 1.\n"
" --expos_comp_nr_filtering <int>\n"
" Number of filtering iterations of the exposure compensation gains.\n"
" Only used when using a block exposure compensation method.\n"
" The default is 2.\n"
" --expos_comp_block_size <int>\n"
" BLock size in pixels used by the exposure compensator.\n"
" Only used when using a block exposure compensation method.\n"
" The default is 32.\n"
" --blend (no|feather|multiband)\n"
" Blending method. The default is 'multiband'.\n"
" --blend_strength <float>\n"
" Blending strength from [0,100] range. The default is 5.\n"
" --output <result_img>\n"
" The default is 'result.jpg'.\n"
" --timelapse (as_is|crop) \n"
" Output warped images separately as frames of a time lapse movie, with 'fixed_' prepended to input file names.\n"
" --rangewidth <int>\n"
" uses range_width to limit number of images to match with.\n";
}
// Default command line args
vector<String> img_names;
bool preview = false;
bool try_cuda = false;
double work_megapix = 0.6;
double seam_megapix = 0.1;
double compose_megapix = -1;
float conf_thresh = 1.f;
#ifdef HAVE_OPENCV_XFEATURES2D
string features_type = "surf";
float match_conf = 0.65f;
#else
string features_type = "orb";
float match_conf = 0.3f;
#endif
string matcher_type = "homography";
string estimator_type = "homography";
string ba_cost_func = "ray";
string ba_refine_mask = "xxxxx";
bool do_wave_correct = true;
WaveCorrectKind wave_correct = detail::WAVE_CORRECT_HORIZ;
bool save_graph = false;
std::string save_graph_to;
string warp_type = "spherical";
int expos_comp_type = ExposureCompensator::GAIN_BLOCKS;
int expos_comp_nr_feeds = 1;
int expos_comp_nr_filtering = 2;
int expos_comp_block_size = 32;
string seam_find_type = "gc_color";
int blend_type = Blender::MULTI_BAND;
int timelapse_type = Timelapser::AS_IS;
float blend_strength = 5;
string result_name = "result.jpg";
bool timelapse = false;
int range_width = -1;
static int parseCmdArgs(int argc, char** argv)
{
if (argc == 1)
{
printUsage(argv);
return -1;
}
for (int i = 1; i < argc; ++i)
{
if (string(argv[i]) == "--help" || string(argv[i]) == "/?")
{
printUsage(argv);
return -1;
}
else if (string(argv[i]) == "--preview")
{
preview = true;
}
else if (string(argv[i]) == "--try_cuda")
{
if (string(argv[i + 1]) == "no")
try_cuda = false;
else if (string(argv[i + 1]) == "yes")
try_cuda = true;
else
{
cout << "Bad --try_cuda flag value\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--work_megapix")
{
work_megapix = atof(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--seam_megapix")
{
seam_megapix = atof(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--compose_megapix")
{
compose_megapix = atof(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--result")
{
result_name = argv[i + 1];
i++;
}
else if (string(argv[i]) == "--features")
{
features_type = argv[i + 1];
if (string(features_type) == "orb")
match_conf = 0.3f;
i++;
}
else if (string(argv[i]) == "--matcher")
{
if (string(argv[i + 1]) == "homography" || string(argv[i + 1]) == "affine")
matcher_type = argv[i + 1];
else
{
cout << "Bad --matcher flag value\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--estimator")
{
if (string(argv[i + 1]) == "homography" || string(argv[i + 1]) == "affine")
estimator_type = argv[i + 1];
else
{
cout << "Bad --estimator flag value\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--match_conf")
{
match_conf = static_cast<float>(atof(argv[i + 1]));
i++;
}
else if (string(argv[i]) == "--conf_thresh")
{
conf_thresh = static_cast<float>(atof(argv[i + 1]));
i++;
}
else if (string(argv[i]) == "--ba")
{
ba_cost_func = argv[i + 1];
i++;
}
else if (string(argv[i]) == "--ba_refine_mask")
{
ba_refine_mask = argv[i + 1];
if (ba_refine_mask.size() != 5)
{
cout << "Incorrect refinement mask length.\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--wave_correct")
{
if (string(argv[i + 1]) == "no")
do_wave_correct = false;
else if (string(argv[i + 1]) == "horiz")
{
do_wave_correct = true;
wave_correct = detail::WAVE_CORRECT_HORIZ;
}
else if (string(argv[i + 1]) == "vert")
{
do_wave_correct = true;
wave_correct = detail::WAVE_CORRECT_VERT;
}
else
{
cout << "Bad --wave_correct flag value\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--save_graph")
{
save_graph = true;
save_graph_to = argv[i + 1];
i++;
}
else if (string(argv[i]) == "--warp")
{
warp_type = string(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--expos_comp")
{
if (string(argv[i + 1]) == "no")
expos_comp_type = ExposureCompensator::NO;
else if (string(argv[i + 1]) == "gain")
expos_comp_type = ExposureCompensator::GAIN;
else if (string(argv[i + 1]) == "gain_blocks")
expos_comp_type = ExposureCompensator::GAIN_BLOCKS;
else if (string(argv[i + 1]) == "channels")
expos_comp_type = ExposureCompensator::CHANNELS;
else if (string(argv[i + 1]) == "channels_blocks")
expos_comp_type = ExposureCompensator::CHANNELS_BLOCKS;
else
{
cout << "Bad exposure compensation method\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--expos_comp_nr_feeds")
{
expos_comp_nr_feeds = atoi(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--expos_comp_nr_filtering")
{
expos_comp_nr_filtering = atoi(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--expos_comp_block_size")
{
expos_comp_block_size = atoi(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--seam")
{
if (string(argv[i + 1]) == "no" ||
string(argv[i + 1]) == "voronoi" ||
string(argv[i + 1]) == "gc_color" ||
string(argv[i + 1]) == "gc_colorgrad" ||
string(argv[i + 1]) == "dp_color" ||
string(argv[i + 1]) == "dp_colorgrad")
seam_find_type = argv[i + 1];
else
{
cout << "Bad seam finding method\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--blend")
{
if (string(argv[i + 1]) == "no")
blend_type = Blender::NO;
else if (string(argv[i + 1]) == "feather")
blend_type = Blender::FEATHER;
else if (string(argv[i + 1]) == "multiband")
blend_type = Blender::MULTI_BAND;
else
{
cout << "Bad blending method\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--timelapse")
{
timelapse = true;
if (string(argv[i + 1]) == "as_is")
timelapse_type = Timelapser::AS_IS;
else if (string(argv[i + 1]) == "crop")
timelapse_type = Timelapser::CROP;
else
{
cout << "Bad timelapse method\n";
return -1;
}
i++;
}
else if (string(argv[i]) == "--rangewidth")
{
range_width = atoi(argv[i + 1]);
i++;
}
else if (string(argv[i]) == "--blend_strength")
{
blend_strength = static_cast<float>(atof(argv[i + 1]));
i++;
}
else if (string(argv[i]) == "--output")
{
result_name = argv[i + 1];
i++;
}
else
img_names.push_back(argv[i]);
}
if (preview)
{
compose_megapix = 0.6;
}
return 0;
}
int main(int argc, char* argv[])
{
#if ENABLE_LOG
int64 app_start_time = getTickCount();
#endif
#if 0
cv::setBreakOnError(true);
#endif
int retval = parseCmdArgs(argc, argv);
if (retval)
return retval;
// Check if have enough images
int num_images = static_cast<int>(img_names.size());
if (num_images < 2)
{
LOGLN("Need more images");
return -1;
}
double work_scale = 1, seam_scale = 1, compose_scale = 1;
bool is_work_scale_set = false, is_seam_scale_set = false, is_compose_scale_set = false;
LOGLN("Finding features...");
#if ENABLE_LOG
int64 t = getTickCount();
#endif
Ptr<Feature2D> finder;
if (features_type == "orb")
{
finder = ORB::create();
}
else if (features_type == "akaze")
{
finder = AKAZE::create();
}
#ifdef HAVE_OPENCV_XFEATURES2D
else if (features_type == "surf")
{
finder = xfeatures2d::SURF::create();
}
#endif
else if (features_type == "sift")
{
finder = SIFT::create();
}
else
{
cout << "Unknown 2D features type: '" << features_type << "'.\n";
return -1;
}
Mat full_img, img;
vector<ImageFeatures> features(num_images);
vector<Mat> images(num_images);
vector<Size> full_img_sizes(num_images);
double seam_work_aspect = 1;
for (int i = 0; i < num_images; ++i)
{
full_img = imread(samples::findFile(img_names[i]));
full_img_sizes[i] = full_img.size();
if (full_img.empty())
{
LOGLN("Can't open image " << img_names[i]);
return -1;
}
if (work_megapix < 0)
{
img = full_img;
work_scale = 1;
is_work_scale_set = true;
}
else
{
if (!is_work_scale_set)
{
work_scale = min(1.0, sqrt(work_megapix * 1e6 / full_img.size().area()));
is_work_scale_set = true;
}
resize(full_img, img, Size(), work_scale, work_scale, INTER_LINEAR_EXACT);
}
if (!is_seam_scale_set)
{
seam_scale = min(1.0, sqrt(seam_megapix * 1e6 / full_img.size().area()));
seam_work_aspect = seam_scale / work_scale;
is_seam_scale_set = true;
}
computeImageFeatures(finder, img, features[i]);
features[i].img_idx = i;
LOGLN("Features in image #" << i+1 << ": " << features[i].keypoints.size());
resize(full_img, img, Size(), seam_scale, seam_scale, INTER_LINEAR_EXACT);
images[i] = img.clone();
}
full_img.release();
img.release();
LOGLN("Finding features, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
LOG("Pairwise matching");
#if ENABLE_LOG
t = getTickCount();
#endif
vector<MatchesInfo> pairwise_matches;
Ptr<FeaturesMatcher> matcher;
if (matcher_type == "affine")
matcher = makePtr<AffineBestOf2NearestMatcher>(false, try_cuda, match_conf);
else if (range_width==-1)
matcher = makePtr<BestOf2NearestMatcher>(try_cuda, match_conf);
else
matcher = makePtr<BestOf2NearestRangeMatcher>(range_width, try_cuda, match_conf);
(*matcher)(features, pairwise_matches);
matcher->collectGarbage();
LOGLN("Pairwise matching, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
// Check if we should save matches graph
if (save_graph)
{
LOGLN("Saving matches graph...");
ofstream f(save_graph_to.c_str());
f << matchesGraphAsString(img_names, pairwise_matches, conf_thresh);
}
// Leave only images we are sure are from the same panorama
vector<int> indices = leaveBiggestComponent(features, pairwise_matches, conf_thresh);
vector<Mat> img_subset;
vector<String> img_names_subset;
vector<Size> full_img_sizes_subset;
for (size_t i = 0; i < indices.size(); ++i)
{
img_names_subset.push_back(img_names[indices[i]]);
img_subset.push_back(images[indices[i]]);
full_img_sizes_subset.push_back(full_img_sizes[indices[i]]);
}
images = img_subset;
img_names = img_names_subset;
full_img_sizes = full_img_sizes_subset;
// Check if we still have enough images
num_images = static_cast<int>(img_names.size());
if (num_images < 2)
{
LOGLN("Need more images");
return -1;
}
Ptr<Estimator> estimator;
if (estimator_type == "affine")
estimator = makePtr<AffineBasedEstimator>();
else
estimator = makePtr<HomographyBasedEstimator>();
vector<CameraParams> cameras;
if (!(*estimator)(features, pairwise_matches, cameras))
{
cout << "Homography estimation failed.\n";
return -1;
}
for (size_t i = 0; i < cameras.size(); ++i)
{
Mat R;
cameras[i].R.convertTo(R, CV_32F);
cameras[i].R = R;
LOGLN("Initial camera intrinsics #" << indices[i]+1 << ":\nK:\n" << cameras[i].K() << "\nR:\n" << cameras[i].R);
}
Ptr<detail::BundleAdjusterBase> adjuster;
if (ba_cost_func == "reproj") adjuster = makePtr<detail::BundleAdjusterReproj>();
else if (ba_cost_func == "ray") adjuster = makePtr<detail::BundleAdjusterRay>();
else if (ba_cost_func == "affine") adjuster = makePtr<detail::BundleAdjusterAffinePartial>();
else if (ba_cost_func == "no") adjuster = makePtr<NoBundleAdjuster>();
else
{
cout << "Unknown bundle adjustment cost function: '" << ba_cost_func << "'.\n";
return -1;
}
adjuster->setConfThresh(conf_thresh);
Mat_<uchar> refine_mask = Mat::zeros(3, 3, CV_8U);
if (ba_refine_mask[0] == 'x') refine_mask(0,0) = 1;
if (ba_refine_mask[1] == 'x') refine_mask(0,1) = 1;
if (ba_refine_mask[2] == 'x') refine_mask(0,2) = 1;
if (ba_refine_mask[3] == 'x') refine_mask(1,1) = 1;
if (ba_refine_mask[4] == 'x') refine_mask(1,2) = 1;
adjuster->setRefinementMask(refine_mask);
if (!(*adjuster)(features, pairwise_matches, cameras))
{
cout << "Camera parameters adjusting failed.\n";
return -1;
}
// Find median focal length
vector<double> focals;
for (size_t i = 0; i < cameras.size(); ++i)
{
LOGLN("Camera #" << indices[i]+1 << ":\nK:\n" << cameras[i].K() << "\nR:\n" << cameras[i].R);
focals.push_back(cameras[i].focal);
}
sort(focals.begin(), focals.end());
float warped_image_scale;
if (focals.size() % 2 == 1)
warped_image_scale = static_cast<float>(focals[focals.size() / 2]);
else
warped_image_scale = static_cast<float>(focals[focals.size() / 2 - 1] + focals[focals.size() / 2]) * 0.5f;
if (do_wave_correct)
{
vector<Mat> rmats;
for (size_t i = 0; i < cameras.size(); ++i)
rmats.push_back(cameras[i].R.clone());
waveCorrect(rmats, wave_correct);
for (size_t i = 0; i < cameras.size(); ++i)
cameras[i].R = rmats[i];
}
LOGLN("Warping images (auxiliary)... ");
#if ENABLE_LOG
t = getTickCount();
#endif
vector<Point> corners(num_images);
vector<UMat> masks_warped(num_images);
vector<UMat> images_warped(num_images);
vector<Size> sizes(num_images);
vector<UMat> masks(num_images);
// Prepare images masks
for (int i = 0; i < num_images; ++i)
{
masks[i].create(images[i].size(), CV_8U);
masks[i].setTo(Scalar::all(255));
}
// Warp images and their masks
Ptr<WarperCreator> warper_creator;
#ifdef HAVE_OPENCV_CUDAWARPING
if (try_cuda && cuda::getCudaEnabledDeviceCount() > 0)
{
if (warp_type == "plane")
warper_creator = makePtr<cv::PlaneWarperGpu>();
else if (warp_type == "cylindrical")
warper_creator = makePtr<cv::CylindricalWarperGpu>();
else if (warp_type == "spherical")
warper_creator = makePtr<cv::SphericalWarperGpu>();
}
else
#endif
{
if (warp_type == "plane")
warper_creator = makePtr<cv::PlaneWarper>();
else if (warp_type == "affine")
warper_creator = makePtr<cv::AffineWarper>();
else if (warp_type == "cylindrical")
warper_creator = makePtr<cv::CylindricalWarper>();
else if (warp_type == "spherical")
warper_creator = makePtr<cv::SphericalWarper>();
else if (warp_type == "fisheye")
warper_creator = makePtr<cv::FisheyeWarper>();
else if (warp_type == "stereographic")
warper_creator = makePtr<cv::StereographicWarper>();
else if (warp_type == "compressedPlaneA2B1")
warper_creator = makePtr<cv::CompressedRectilinearWarper>(2.0f, 1.0f);
else if (warp_type == "compressedPlaneA1.5B1")
warper_creator = makePtr<cv::CompressedRectilinearWarper>(1.5f, 1.0f);
else if (warp_type == "compressedPlanePortraitA2B1")
warper_creator = makePtr<cv::CompressedRectilinearPortraitWarper>(2.0f, 1.0f);
else if (warp_type == "compressedPlanePortraitA1.5B1")
warper_creator = makePtr<cv::CompressedRectilinearPortraitWarper>(1.5f, 1.0f);
else if (warp_type == "paniniA2B1")
warper_creator = makePtr<cv::PaniniWarper>(2.0f, 1.0f);
else if (warp_type == "paniniA1.5B1")
warper_creator = makePtr<cv::PaniniWarper>(1.5f, 1.0f);
else if (warp_type == "paniniPortraitA2B1")
warper_creator = makePtr<cv::PaniniPortraitWarper>(2.0f, 1.0f);
else if (warp_type == "paniniPortraitA1.5B1")
warper_creator = makePtr<cv::PaniniPortraitWarper>(1.5f, 1.0f);
else if (warp_type == "mercator")
warper_creator = makePtr<cv::MercatorWarper>();
else if (warp_type == "transverseMercator")
warper_creator = makePtr<cv::TransverseMercatorWarper>();
}
if (!warper_creator)
{
cout << "Can't create the following warper '" << warp_type << "'\n";
return 1;
}
Ptr<RotationWarper> warper = warper_creator->create(static_cast<float>(warped_image_scale * seam_work_aspect));
for (int i = 0; i < num_images; ++i)
{
Mat_<float> K;
cameras[i].K().convertTo(K, CV_32F);
float swa = (float)seam_work_aspect;
K(0,0) *= swa; K(0,2) *= swa;
K(1,1) *= swa; K(1,2) *= swa;
corners[i] = warper->warp(images[i], K, cameras[i].R, INTER_LINEAR, BORDER_REFLECT, images_warped[i]);
sizes[i] = images_warped[i].size();
warper->warp(masks[i], K, cameras[i].R, INTER_NEAREST, BORDER_CONSTANT, masks_warped[i]);
}
vector<UMat> images_warped_f(num_images);
for (int i = 0; i < num_images; ++i)
images_warped[i].convertTo(images_warped_f[i], CV_32F);
LOGLN("Warping images, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
LOGLN("Compensating exposure...");
#if ENABLE_LOG
t = getTickCount();
#endif
Ptr<ExposureCompensator> compensator = ExposureCompensator::createDefault(expos_comp_type);
if (dynamic_cast<GainCompensator*>(compensator.get()))
{
GainCompensator* gcompensator = dynamic_cast<GainCompensator*>(compensator.get());
gcompensator->setNrFeeds(expos_comp_nr_feeds);
}
if (dynamic_cast<ChannelsCompensator*>(compensator.get()))
{
ChannelsCompensator* ccompensator = dynamic_cast<ChannelsCompensator*>(compensator.get());
ccompensator->setNrFeeds(expos_comp_nr_feeds);
}
if (dynamic_cast<BlocksCompensator*>(compensator.get()))
{
BlocksCompensator* bcompensator = dynamic_cast<BlocksCompensator*>(compensator.get());
bcompensator->setNrFeeds(expos_comp_nr_feeds);
bcompensator->setNrGainsFilteringIterations(expos_comp_nr_filtering);
bcompensator->setBlockSize(expos_comp_block_size, expos_comp_block_size);
}
compensator->feed(corners, images_warped, masks_warped);
LOGLN("Compensating exposure, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
LOGLN("Finding seams...");
#if ENABLE_LOG
t = getTickCount();
#endif
Ptr<SeamFinder> seam_finder;
if (seam_find_type == "no")
seam_finder = makePtr<detail::NoSeamFinder>();
else if (seam_find_type == "voronoi")
seam_finder = makePtr<detail::VoronoiSeamFinder>();
else if (seam_find_type == "gc_color")
{
#ifdef HAVE_OPENCV_CUDALEGACY
if (try_cuda && cuda::getCudaEnabledDeviceCount() > 0)
seam_finder = makePtr<detail::GraphCutSeamFinderGpu>(GraphCutSeamFinderBase::COST_COLOR);
else
#endif
seam_finder = makePtr<detail::GraphCutSeamFinder>(GraphCutSeamFinderBase::COST_COLOR);
}
else if (seam_find_type == "gc_colorgrad")
{
#ifdef HAVE_OPENCV_CUDALEGACY
if (try_cuda && cuda::getCudaEnabledDeviceCount() > 0)
seam_finder = makePtr<detail::GraphCutSeamFinderGpu>(GraphCutSeamFinderBase::COST_COLOR_GRAD);
else
#endif
seam_finder = makePtr<detail::GraphCutSeamFinder>(GraphCutSeamFinderBase::COST_COLOR_GRAD);
}
else if (seam_find_type == "dp_color")
seam_finder = makePtr<detail::DpSeamFinder>(DpSeamFinder::COLOR);
else if (seam_find_type == "dp_colorgrad")
seam_finder = makePtr<detail::DpSeamFinder>(DpSeamFinder::COLOR_GRAD);
if (!seam_finder)
{
cout << "Can't create the following seam finder '" << seam_find_type << "'\n";
return 1;
}
seam_finder->find(images_warped_f, corners, masks_warped);
LOGLN("Finding seams, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
// Release unused memory
images.clear();
images_warped.clear();
images_warped_f.clear();
masks.clear();
LOGLN("Compositing...");
#if ENABLE_LOG
t = getTickCount();
#endif
Mat img_warped, img_warped_s;
Mat dilated_mask, seam_mask, mask, mask_warped;
Ptr<Blender> blender;
Ptr<Timelapser> timelapser;
//double compose_seam_aspect = 1;
double compose_work_aspect = 1;
for (int img_idx = 0; img_idx < num_images; ++img_idx)
{
LOGLN("Compositing image #" << indices[img_idx]+1);
// Read image and resize it if necessary
full_img = imread(samples::findFile(img_names[img_idx]));
if (!is_compose_scale_set)
{
if (compose_megapix > 0)
compose_scale = min(1.0, sqrt(compose_megapix * 1e6 / full_img.size().area()));
is_compose_scale_set = true;
// Compute relative scales
//compose_seam_aspect = compose_scale / seam_scale;
compose_work_aspect = compose_scale / work_scale;
// Update warped image scale
warped_image_scale *= static_cast<float>(compose_work_aspect);
warper = warper_creator->create(warped_image_scale);
// Update corners and sizes
for (int i = 0; i < num_images; ++i)
{
// Update intrinsics
cameras[i].focal *= compose_work_aspect;
cameras[i].ppx *= compose_work_aspect;
cameras[i].ppy *= compose_work_aspect;
// Update corner and size
Size sz = full_img_sizes[i];
if (std::abs(compose_scale - 1) > 1e-1)
{
sz.width = cvRound(full_img_sizes[i].width * compose_scale);
sz.height = cvRound(full_img_sizes[i].height * compose_scale);
}
Mat K;
cameras[i].K().convertTo(K, CV_32F);
Rect roi = warper->warpRoi(sz, K, cameras[i].R);
corners[i] = roi.tl();
sizes[i] = roi.size();
}
}
if (abs(compose_scale - 1) > 1e-1)
resize(full_img, img, Size(), compose_scale, compose_scale, INTER_LINEAR_EXACT);
else
img = full_img;
full_img.release();
Size img_size = img.size();
Mat K;
cameras[img_idx].K().convertTo(K, CV_32F);
// Warp the current image
warper->warp(img, K, cameras[img_idx].R, INTER_LINEAR, BORDER_REFLECT, img_warped);
// Warp the current image mask
mask.create(img_size, CV_8U);
mask.setTo(Scalar::all(255));
warper->warp(mask, K, cameras[img_idx].R, INTER_NEAREST, BORDER_CONSTANT, mask_warped);
// Compensate exposure
compensator->apply(img_idx, corners[img_idx], img_warped, mask_warped);
img_warped.convertTo(img_warped_s, CV_16S);
img_warped.release();
img.release();
mask.release();
dilate(masks_warped[img_idx], dilated_mask, Mat());
resize(dilated_mask, seam_mask, mask_warped.size(), 0, 0, INTER_LINEAR_EXACT);
mask_warped = seam_mask & mask_warped;
if (!blender && !timelapse)
{
blender = Blender::createDefault(blend_type, try_cuda);
Size dst_sz = resultRoi(corners, sizes).size();
float blend_width = sqrt(static_cast<float>(dst_sz.area())) * blend_strength / 100.f;
if (blend_width < 1.f)
blender = Blender::createDefault(Blender::NO, try_cuda);
else if (blend_type == Blender::MULTI_BAND)
{
MultiBandBlender* mb = dynamic_cast<MultiBandBlender*>(blender.get());
mb->setNumBands(static_cast<int>(ceil(log(blend_width)/log(2.)) - 1.));
LOGLN("Multi-band blender, number of bands: " << mb->numBands());
}
else if (blend_type == Blender::FEATHER)
{
FeatherBlender* fb = dynamic_cast<FeatherBlender*>(blender.get());
fb->setSharpness(1.f/blend_width);
LOGLN("Feather blender, sharpness: " << fb->sharpness());
}
blender->prepare(corners, sizes);
}
else if (!timelapser && timelapse)
{
timelapser = Timelapser::createDefault(timelapse_type);
timelapser->initialize(corners, sizes);
}
// Blend the current image
if (timelapse)
{
timelapser->process(img_warped_s, Mat::ones(img_warped_s.size(), CV_8UC1), corners[img_idx]);
String fixedFileName;
size_t pos_s = String(img_names[img_idx]).find_last_of("/\\");
if (pos_s == String::npos)
{
fixedFileName = "fixed_" + img_names[img_idx];
}
else
{
fixedFileName = "fixed_" + String(img_names[img_idx]).substr(pos_s + 1, String(img_names[img_idx]).length() - pos_s);
}
imwrite(fixedFileName, timelapser->getDst());
}
else
{
blender->feed(img_warped_s, mask_warped, corners[img_idx]);
}
}
if (!timelapse)
{
Mat result, result_mask;
blender->blend(result, result_mask);
LOGLN("Compositing, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
imwrite(result_name, result);
}
LOGLN("Finished, total time: " << ((getTickCount() - app_start_time) / getTickFrequency()) << " sec");
return 0;
}

View File

@ -0,0 +1,74 @@
/*
This tutorial demonstrates how to correct the skewness in a text.
The program takes as input a skewed source image and shows non skewed text.
*/
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <iomanip>
#include <string>
using namespace cv;
using namespace std;
int main( int argc, char** argv )
{
CommandLineParser parser(argc, argv, "{@input | imageTextR.png | input image}");
// Load image from the disk
Mat image = imread( samples::findFile( parser.get<String>("@input") ), IMREAD_COLOR);
if (image.empty())
{
cout << "Cannot load the image " + parser.get<String>("@input") << endl;
return -1;
}
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
//Threshold the image, setting all foreground pixels to 255 and all background pixels to 0
Mat thresh;
threshold(gray, thresh, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
// Applying erode filter to remove random noise
int erosion_size = 1;
Mat element = getStructuringElement( MORPH_RECT, Size(2*erosion_size+1, 2*erosion_size+1), Point(erosion_size, erosion_size) );
erode(thresh, thresh, element);
cv::Mat coords;
findNonZero(thresh, coords);
RotatedRect box = minAreaRect(coords);
float angle = box.angle;
// The cv::minAreaRect function returns values in the range [-90, 0)
// if the angle is less than -45 we need to add 90 to it
if (angle < -45.0f)
{
angle = (90.0f + angle);
}
//Obtaining the rotation matrix
Point2f center((image.cols) / 2.0f, (image.rows) / 2.0f);
Mat M = getRotationMatrix2D(center, angle, 1.0f);
Mat rotated;
// Rotating the image by required angle
stringstream angle_to_str;
angle_to_str << fixed << setprecision(2) << angle;
warpAffine(image, rotated, M, image.size(), INTER_CUBIC, BORDER_REPLICATE);
putText(rotated, "Angle " + angle_to_str.str() + " degrees", Point(10, 30), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 0, 255), 2);
cout << "[INFO] angle: " << angle_to_str.str() << endl;
//Show the image
imshow("Input", image);
imshow("Rotated", rotated);
waitKey(0);
return 0;
}

View File

@ -0,0 +1,392 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ml.hpp"
#include "opencv2/objdetect.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
#include <time.h>
using namespace cv;
using namespace cv::ml;
using namespace std;
vector< float > get_svm_detector( const Ptr< SVM >& svm );
void convert_to_ml( const std::vector< Mat > & train_samples, Mat& trainData );
void load_images( const String & dirname, vector< Mat > & img_lst, bool showImages );
void sample_neg( const vector< Mat > & full_neg_lst, vector< Mat > & neg_lst, const Size & size );
void computeHOGs( const Size wsize, const vector< Mat > & img_lst, vector< Mat > & gradient_lst, bool use_flip );
void test_trained_detector( String obj_det_filename, String test_dir, String videofilename );
vector< float > get_svm_detector( const Ptr< SVM >& svm )
{
// get the support vectors
Mat sv = svm->getSupportVectors();
const int sv_total = sv.rows;
// get the decision function
Mat alpha, svidx;
double rho = svm->getDecisionFunction( 0, alpha, svidx );
CV_Assert( alpha.total() == 1 && svidx.total() == 1 && sv_total == 1 );
CV_Assert( (alpha.type() == CV_64F && alpha.at<double>(0) == 1.) ||
(alpha.type() == CV_32F && alpha.at<float>(0) == 1.f) );
CV_Assert( sv.type() == CV_32F );
vector< float > hog_detector( sv.cols + 1 );
memcpy( &hog_detector[0], sv.ptr(), sv.cols*sizeof( hog_detector[0] ) );
hog_detector[sv.cols] = (float)-rho;
return hog_detector;
}
/*
* Convert training/testing set to be used by OpenCV Machine Learning algorithms.
* TrainData is a matrix of size (#samples x max(#cols,#rows) per samples), in 32FC1.
* Transposition of samples are made if needed.
*/
void convert_to_ml( const vector< Mat > & train_samples, Mat& trainData )
{
//--Convert data
const int rows = (int)train_samples.size();
const int cols = (int)std::max( train_samples[0].cols, train_samples[0].rows );
Mat tmp( 1, cols, CV_32FC1 ); //< used for transposition if needed
trainData = Mat( rows, cols, CV_32FC1 );
for( size_t i = 0 ; i < train_samples.size(); ++i )
{
CV_Assert( train_samples[i].cols == 1 || train_samples[i].rows == 1 );
if( train_samples[i].cols == 1 )
{
transpose( train_samples[i], tmp );
tmp.copyTo( trainData.row( (int)i ) );
}
else if( train_samples[i].rows == 1 )
{
train_samples[i].copyTo( trainData.row( (int)i ) );
}
}
}
void load_images( const String & dirname, vector< Mat > & img_lst, bool showImages = false )
{
vector< String > files;
glob( dirname, files );
for ( size_t i = 0; i < files.size(); ++i )
{
Mat img = imread( files[i] ); // load the image
if ( img.empty() )
{
cout << files[i] << " is invalid!" << endl; // invalid image, skip it.
continue;
}
if ( showImages )
{
imshow( "image", img );
waitKey( 1 );
}
img_lst.push_back( img );
}
}
void sample_neg( const vector< Mat > & full_neg_lst, vector< Mat > & neg_lst, const Size & size )
{
Rect box;
box.width = size.width;
box.height = size.height;
srand( (unsigned int)time( NULL ) );
for ( size_t i = 0; i < full_neg_lst.size(); i++ )
if ( full_neg_lst[i].cols > box.width && full_neg_lst[i].rows > box.height )
{
box.x = rand() % ( full_neg_lst[i].cols - box.width );
box.y = rand() % ( full_neg_lst[i].rows - box.height );
Mat roi = full_neg_lst[i]( box );
neg_lst.push_back( roi.clone() );
}
}
void computeHOGs( const Size wsize, const vector< Mat > & img_lst, vector< Mat > & gradient_lst, bool use_flip )
{
HOGDescriptor hog;
hog.winSize = wsize;
Mat gray;
vector< float > descriptors;
for( size_t i = 0 ; i < img_lst.size(); i++ )
{
if ( img_lst[i].cols >= wsize.width && img_lst[i].rows >= wsize.height )
{
Rect r = Rect(( img_lst[i].cols - wsize.width ) / 2,
( img_lst[i].rows - wsize.height ) / 2,
wsize.width,
wsize.height);
cvtColor( img_lst[i](r), gray, COLOR_BGR2GRAY );
hog.compute( gray, descriptors, Size( 8, 8 ), Size( 0, 0 ) );
gradient_lst.push_back( Mat( descriptors ).clone() );
if ( use_flip )
{
flip( gray, gray, 1 );
hog.compute( gray, descriptors, Size( 8, 8 ), Size( 0, 0 ) );
gradient_lst.push_back( Mat( descriptors ).clone() );
}
}
}
}
void test_trained_detector( String obj_det_filename, String test_dir, String videofilename )
{
cout << "Testing trained detector..." << endl;
HOGDescriptor hog;
hog.load( obj_det_filename );
vector< String > files;
glob( test_dir, files );
int delay = 0;
VideoCapture cap;
if ( videofilename != "" )
{
if ( videofilename.size() == 1 && isdigit( videofilename[0] ) )
cap.open( videofilename[0] - '0' );
else
cap.open( videofilename );
}
obj_det_filename = "testing " + obj_det_filename;
namedWindow( obj_det_filename, WINDOW_NORMAL );
for( size_t i=0;; i++ )
{
Mat img;
if ( cap.isOpened() )
{
cap >> img;
delay = 1;
}
else if( i < files.size() )
{
img = imread( files[i] );
}
if ( img.empty() )
{
return;
}
vector< Rect > detections;
vector< double > foundWeights;
hog.detectMultiScale( img, detections, foundWeights );
for ( size_t j = 0; j < detections.size(); j++ )
{
Scalar color = Scalar( 0, foundWeights[j] * foundWeights[j] * 200, 0 );
rectangle( img, detections[j], color, img.cols / 400 + 1 );
}
imshow( obj_det_filename, img );
if( waitKey( delay ) == 27 )
{
return;
}
}
}
int main( int argc, char** argv )
{
const char* keys =
{
"{help h| | show help message}"
"{pd | | path of directory contains positive images}"
"{nd | | path of directory contains negative images}"
"{td | | path of directory contains test images}"
"{tv | | test video file name}"
"{dw | | width of the detector}"
"{dh | | height of the detector}"
"{f |false| indicates if the program will generate and use mirrored samples or not}"
"{d |false| train twice}"
"{t |false| test a trained detector}"
"{v |false| visualize training steps}"
"{fn |my_detector.yml| file name of trained SVM}"
};
CommandLineParser parser( argc, argv, keys );
if ( parser.has( "help" ) )
{
parser.printMessage();
exit( 0 );
}
String pos_dir = parser.get< String >( "pd" );
String neg_dir = parser.get< String >( "nd" );
String test_dir = parser.get< String >( "td" );
String obj_det_filename = parser.get< String >( "fn" );
String videofilename = parser.get< String >( "tv" );
int detector_width = parser.get< int >( "dw" );
int detector_height = parser.get< int >( "dh" );
bool test_detector = parser.get< bool >( "t" );
bool train_twice = parser.get< bool >( "d" );
bool visualization = parser.get< bool >( "v" );
bool flip_samples = parser.get< bool >( "f" );
if ( test_detector )
{
test_trained_detector( obj_det_filename, test_dir, videofilename );
exit( 0 );
}
if( pos_dir.empty() || neg_dir.empty() )
{
parser.printMessage();
cout << "Wrong number of parameters.\n\n"
<< "Example command line:\n" << argv[0] << " -dw=64 -dh=128 -pd=/INRIAPerson/96X160H96/Train/pos -nd=/INRIAPerson/neg -td=/INRIAPerson/Test/pos -fn=HOGpedestrian64x128.xml -d\n"
<< "\nExample command line for testing trained detector:\n" << argv[0] << " -t -fn=HOGpedestrian64x128.xml -td=/INRIAPerson/Test/pos";
exit( 1 );
}
vector< Mat > pos_lst, full_neg_lst, neg_lst, gradient_lst;
vector< int > labels;
clog << "Positive images are being loaded..." ;
load_images( pos_dir, pos_lst, visualization );
if ( pos_lst.size() > 0 )
{
clog << "...[done] " << pos_lst.size() << " files." << endl;
}
else
{
clog << "no image in " << pos_dir <<endl;
return 1;
}
Size pos_image_size = pos_lst[0].size();
if ( detector_width && detector_height )
{
pos_image_size = Size( detector_width, detector_height );
}
else
{
for ( size_t i = 0; i < pos_lst.size(); ++i )
{
if( pos_lst[i].size() != pos_image_size )
{
cout << "All positive images should be same size!" << endl;
exit( 1 );
}
}
pos_image_size = pos_image_size / 8 * 8;
}
clog << "Negative images are being loaded...";
load_images( neg_dir, full_neg_lst, visualization );
clog << "...[done] " << full_neg_lst.size() << " files." << endl;
clog << "Negative images are being processed...";
sample_neg( full_neg_lst, neg_lst, pos_image_size );
clog << "...[done] " << neg_lst.size() << " files." << endl;
clog << "Histogram of Gradients are being calculated for positive images...";
computeHOGs( pos_image_size, pos_lst, gradient_lst, flip_samples );
size_t positive_count = gradient_lst.size();
labels.assign( positive_count, +1 );
clog << "...[done] ( positive images count : " << positive_count << " )" << endl;
clog << "Histogram of Gradients are being calculated for negative images...";
computeHOGs( pos_image_size, neg_lst, gradient_lst, flip_samples );
size_t negative_count = gradient_lst.size() - positive_count;
labels.insert( labels.end(), negative_count, -1 );
CV_Assert( positive_count < labels.size() );
clog << "...[done] ( negative images count : " << negative_count << " )" << endl;
Mat train_data;
convert_to_ml( gradient_lst, train_data );
clog << "Training SVM...";
Ptr< SVM > svm = SVM::create();
/* Default values to train SVM */
svm->setCoef0( 0.0 );
svm->setDegree( 3 );
svm->setTermCriteria( TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 1e-3 ) );
svm->setGamma( 0 );
svm->setKernel( SVM::LINEAR );
svm->setNu( 0.5 );
svm->setP( 0.1 ); // for EPSILON_SVR, epsilon in loss function?
svm->setC( 0.01 ); // From paper, soft classifier
svm->setType( SVM::EPS_SVR ); // C_SVC; // EPSILON_SVR; // may be also NU_SVR; // do regression task
svm->train( train_data, ROW_SAMPLE, labels );
clog << "...[done]" << endl;
if ( train_twice )
{
clog << "Testing trained detector on negative images. This might take a few minutes...";
HOGDescriptor my_hog;
my_hog.winSize = pos_image_size;
// Set the trained svm to my_hog
my_hog.setSVMDetector( get_svm_detector( svm ) );
vector< Rect > detections;
vector< double > foundWeights;
for ( size_t i = 0; i < full_neg_lst.size(); i++ )
{
if ( full_neg_lst[i].cols >= pos_image_size.width && full_neg_lst[i].rows >= pos_image_size.height )
my_hog.detectMultiScale( full_neg_lst[i], detections, foundWeights );
else
detections.clear();
for ( size_t j = 0; j < detections.size(); j++ )
{
Mat detection = full_neg_lst[i]( detections[j] ).clone();
resize( detection, detection, pos_image_size, 0, 0, INTER_LINEAR_EXACT);
neg_lst.push_back( detection );
}
if ( visualization )
{
for ( size_t j = 0; j < detections.size(); j++ )
{
rectangle( full_neg_lst[i], detections[j], Scalar( 0, 255, 0 ), 2 );
}
imshow( "testing trained detector on negative images", full_neg_lst[i] );
waitKey( 5 );
}
}
clog << "...[done]" << endl;
gradient_lst.clear();
clog << "Histogram of Gradients are being calculated for positive images...";
computeHOGs( pos_image_size, pos_lst, gradient_lst, flip_samples );
positive_count = gradient_lst.size();
clog << "...[done] ( positive count : " << positive_count << " )" << endl;
clog << "Histogram of Gradients are being calculated for negative images...";
computeHOGs( pos_image_size, neg_lst, gradient_lst, flip_samples );
negative_count = gradient_lst.size() - positive_count;
clog << "...[done] ( negative count : " << negative_count << " )" << endl;
labels.clear();
labels.assign(positive_count, +1);
labels.insert(labels.end(), negative_count, -1);
clog << "Training SVM again...";
convert_to_ml( gradient_lst, train_data );
svm->train( train_data, ROW_SAMPLE, labels );
clog << "...[done]" << endl;
}
HOGDescriptor hog;
hog.winSize = pos_image_size;
hog.setSVMDetector( get_svm_detector( svm ) );
hog.save( obj_det_filename );
test_trained_detector( obj_det_filename, test_dir, videofilename );
return 0;
}

View File

@ -0,0 +1,211 @@
#include "opencv2/core.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ml.hpp"
using namespace cv;
using namespace cv::ml;
struct Data
{
Mat img;
Mat samples; //Set of train samples. Contains points on image
Mat responses; //Set of responses for train samples
Data()
{
const int WIDTH = 841;
const int HEIGHT = 594;
img = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);
imshow("Train svmsgd", img);
}
};
//Train with SVMSGD algorithm
//(samples, responses) is a train set
//weights is a required vector for decision function of SVMSGD algorithm
bool doTrain(const Mat samples, const Mat responses, Mat &weights, float &shift);
//function finds two points for drawing line (wx = 0)
bool findPointsForLine(const Mat &weights, float shift, Point points[], int width, int height);
// function finds cross point of line (wx = 0) and segment ( (y = HEIGHT, 0 <= x <= WIDTH) or (x = WIDTH, 0 <= y <= HEIGHT) )
bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair<Point,Point> &segment, Point &crossPoint);
//segments' initialization ( (y = HEIGHT, 0 <= x <= WIDTH) and (x = WIDTH, 0 <= y <= HEIGHT) )
void fillSegments(std::vector<std::pair<Point,Point> > &segments, int width, int height);
//redraw points' set and line (wx = 0)
void redraw(Data data, const Point points[2]);
//add point in train set, train SVMSGD algorithm and draw results on image
void addPointRetrainAndRedraw(Data &data, int x, int y, int response);
bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift)
{
cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
cv::Ptr<TrainData> trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses);
svmsgd->train( trainData );
if (svmsgd->isTrained())
{
weights = svmsgd->getWeights();
shift = svmsgd->getShift();
return true;
}
return false;
}
void fillSegments(std::vector<std::pair<Point,Point> > &segments, int width, int height)
{
std::pair<Point,Point> currentSegment;
currentSegment.first = Point(width, 0);
currentSegment.second = Point(width, height);
segments.push_back(currentSegment);
currentSegment.first = Point(0, height);
currentSegment.second = Point(width, height);
segments.push_back(currentSegment);
currentSegment.first = Point(0, 0);
currentSegment.second = Point(width, 0);
segments.push_back(currentSegment);
currentSegment.first = Point(0, 0);
currentSegment.second = Point(0, height);
segments.push_back(currentSegment);
}
bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair<Point,Point> &segment, Point &crossPoint)
{
int x = 0;
int y = 0;
int xMin = std::min(segment.first.x, segment.second.x);
int xMax = std::max(segment.first.x, segment.second.x);
int yMin = std::min(segment.first.y, segment.second.y);
int yMax = std::max(segment.first.y, segment.second.y);
CV_Assert(weights.type() == CV_32FC1);
CV_Assert(xMin == xMax || yMin == yMax);
if (xMin == xMax && weights.at<float>(1) != 0)
{
x = xMin;
y = static_cast<int>(std::floor( - (weights.at<float>(0) * x + shift) / weights.at<float>(1)));
if (y >= yMin && y <= yMax)
{
crossPoint.x = x;
crossPoint.y = y;
return true;
}
}
else if (yMin == yMax && weights.at<float>(0) != 0)
{
y = yMin;
x = static_cast<int>(std::floor( - (weights.at<float>(1) * y + shift) / weights.at<float>(0)));
if (x >= xMin && x <= xMax)
{
crossPoint.x = x;
crossPoint.y = y;
return true;
}
}
return false;
}
bool findPointsForLine(const Mat &weights, float shift, Point points[2], int width, int height)
{
if (weights.empty())
{
return false;
}
int foundPointsCount = 0;
std::vector<std::pair<Point,Point> > segments;
fillSegments(segments, width, height);
for (uint i = 0; i < segments.size(); i++)
{
if (findCrossPointWithBorders(weights, shift, segments[i], points[foundPointsCount]))
foundPointsCount++;
if (foundPointsCount >= 2)
break;
}
return true;
}
void redraw(Data data, const Point points[2])
{
data.img.setTo(0);
Point center;
int radius = 3;
Scalar color;
CV_Assert((data.samples.type() == CV_32FC1) && (data.responses.type() == CV_32FC1));
for (int i = 0; i < data.samples.rows; i++)
{
center.x = static_cast<int>(data.samples.at<float>(i,0));
center.y = static_cast<int>(data.samples.at<float>(i,1));
color = (data.responses.at<float>(i) > 0) ? Scalar(128,128,0) : Scalar(0,128,128);
circle(data.img, center, radius, color, 5);
}
line(data.img, points[0], points[1],cv::Scalar(1,255,1));
imshow("Train svmsgd", data.img);
}
void addPointRetrainAndRedraw(Data &data, int x, int y, int response)
{
Mat currentSample(1, 2, CV_32FC1);
currentSample.at<float>(0,0) = (float)x;
currentSample.at<float>(0,1) = (float)y;
data.samples.push_back(currentSample);
data.responses.push_back(static_cast<float>(response));
Mat weights(1, 2, CV_32FC1);
float shift = 0;
if (doTrain(data.samples, data.responses, weights, shift))
{
Point points[2];
findPointsForLine(weights, shift, points, data.img.cols, data.img.rows);
redraw(data, points);
}
}
static void onMouse( int event, int x, int y, int, void* pData)
{
Data &data = *(Data*)pData;
switch( event )
{
case EVENT_LBUTTONUP:
addPointRetrainAndRedraw(data, x, y, 1);
break;
case EVENT_RBUTTONDOWN:
addPointRetrainAndRedraw(data, x, y, -1);
break;
}
}
int main()
{
Data data;
setMouseCallback( "Train svmsgd", onMouse, &data );
waitKey();
return 0;
}

View File

@ -0,0 +1,109 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
using namespace cv;
class TravelSalesman
{
private :
const std::vector<Point>& posCity;
std::vector<int>& next;
RNG rng;
int d0,d1,d2,d3;
public:
TravelSalesman(std::vector<Point> &p, std::vector<int> &n) :
posCity(p), next(n)
{
rng = theRNG();
}
/** Give energy value for a state of system.*/
double energy() const;
/** Function which change the state of system (random perturbation).*/
void changeState();
/** Function to reverse to the previous state.*/
void reverseState();
};
void TravelSalesman::changeState()
{
d0 = rng.uniform(0,static_cast<int>(posCity.size()));
d1 = next[d0];
d2 = next[d1];
d3 = next[d2];
next[d0] = d2;
next[d2] = d1;
next[d1] = d3;
}
void TravelSalesman::reverseState()
{
next[d0] = d1;
next[d1] = d2;
next[d2] = d3;
}
double TravelSalesman::energy() const
{
double e = 0;
for (size_t i = 0; i < next.size(); i++)
{
e += norm(posCity[i]-posCity[next[i]]);
}
return e;
}
static void DrawTravelMap(Mat &img, std::vector<Point> &p, std::vector<int> &n)
{
for (size_t i = 0; i < n.size(); i++)
{
circle(img,p[i],5,Scalar(0,0,255),2);
line(img,p[i],p[n[i]],Scalar(0,255,0),2);
}
}
int main(void)
{
int nbCity=40;
Mat img(500,500,CV_8UC3,Scalar::all(0));
RNG rng(123456);
int radius=static_cast<int>(img.cols*0.45);
Point center(img.cols/2,img.rows/2);
std::vector<Point> posCity(nbCity);
std::vector<int> next(nbCity);
for (size_t i = 0; i < posCity.size(); i++)
{
double theta = rng.uniform(0., 2 * CV_PI);
posCity[i].x = static_cast<int>(radius*cos(theta)) + center.x;
posCity[i].y = static_cast<int>(radius*sin(theta)) + center.y;
next[i]=(i+1)%nbCity;
}
TravelSalesman ts_system(posCity, next);
DrawTravelMap(img,posCity,next);
imshow("Map",img);
waitKey(10);
double currentTemperature = 100.0;
for (int i = 0, zeroChanges = 0; zeroChanges < 10; i++)
{
int changesApplied = ml::simulatedAnnealingSolver(ts_system, currentTemperature, currentTemperature*0.97, 0.99, 10000*nbCity, &currentTemperature, rng);
img.setTo(Scalar::all(0));
DrawTravelMap(img, posCity, next);
imshow("Map", img);
int k = waitKey(10);
std::cout << "i=" << i << " changesApplied=" << changesApplied << " temp=" << currentTemperature << " result=" << ts_system.energy() << std::endl;
if (k == 27 || k == 'q' || k == 'Q')
return 0;
if (changesApplied == 0)
zeroChanges++;
}
std::cout << "Done" << std::endl;
waitKey(0);
return 0;
}

View File

@ -0,0 +1,116 @@
#include "opencv2/ml.hpp"
#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include <stdio.h>
#include <string>
#include <map>
using namespace cv;
using namespace cv::ml;
static void help(char** argv)
{
printf(
"\nThis sample demonstrates how to use different decision trees and forests including boosting and random trees.\n"
"Usage:\n\t%s [-r=<response_column>] [-ts=type_spec] <csv filename>\n"
"where -r=<response_column> specified the 0-based index of the response (0 by default)\n"
"-ts= specifies the var type spec in the form ord[n1,n2-n3,n4-n5,...]cat[m1-m2,m3,m4-m5,...]\n"
"<csv filename> is the name of training data file in comma-separated value format\n\n", argv[0]);
}
static void train_and_print_errs(Ptr<StatModel> model, const Ptr<TrainData>& data)
{
bool ok = model->train(data);
if( !ok )
{
printf("Training failed\n");
}
else
{
printf( "train error: %f\n", model->calcError(data, false, noArray()) );
printf( "test error: %f\n\n", model->calcError(data, true, noArray()) );
}
}
int main(int argc, char** argv)
{
cv::CommandLineParser parser(argc, argv, "{ help h | | }{r | 0 | }{ts | | }{@input | | }");
if (parser.has("help"))
{
help(argv);
return 0;
}
std::string filename = parser.get<std::string>("@input");
int response_idx;
std::string typespec;
response_idx = parser.get<int>("r");
typespec = parser.get<std::string>("ts");
if( filename.empty() || !parser.check() )
{
parser.printErrors();
help(argv);
return 0;
}
printf("\nReading in %s...\n\n",filename.c_str());
const double train_test_split_ratio = 0.5;
Ptr<TrainData> data = TrainData::loadFromCSV(filename, 0, response_idx, response_idx+1, typespec);
if( data.empty() )
{
printf("ERROR: File %s can not be read\n", filename.c_str());
return 0;
}
data->setTrainTestSplitRatio(train_test_split_ratio);
std::cout << "Test/Train: " << data->getNTestSamples() << "/" << data->getNTrainSamples();
printf("======DTREE=====\n");
Ptr<DTrees> dtree = DTrees::create();
dtree->setMaxDepth(10);
dtree->setMinSampleCount(2);
dtree->setRegressionAccuracy(0);
dtree->setUseSurrogates(false);
dtree->setMaxCategories(16);
dtree->setCVFolds(0);
dtree->setUse1SERule(false);
dtree->setTruncatePrunedTree(false);
dtree->setPriors(Mat());
train_and_print_errs(dtree, data);
if( (int)data->getClassLabels().total() <= 2 ) // regression or 2-class classification problem
{
printf("======BOOST=====\n");
Ptr<Boost> boost = Boost::create();
boost->setBoostType(Boost::GENTLE);
boost->setWeakCount(100);
boost->setWeightTrimRate(0.95);
boost->setMaxDepth(2);
boost->setUseSurrogates(false);
boost->setPriors(Mat());
train_and_print_errs(boost, data);
}
printf("======RTREES=====\n");
Ptr<RTrees> rtrees = RTrees::create();
rtrees->setMaxDepth(10);
rtrees->setMinSampleCount(2);
rtrees->setRegressionAccuracy(0);
rtrees->setUseSurrogates(false);
rtrees->setMaxCategories(16);
rtrees->setPriors(Mat());
rtrees->setCalculateVarImportance(true);
rtrees->setActiveVarCount(0);
rtrees->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 0));
train_and_print_errs(rtrees, data);
cv::Mat ref_labels = data->getClassLabels();
cv::Mat test_data = data->getTestSampleIdx();
cv::Mat predict_labels;
rtrees->predict(data->getSamples(), predict_labels);
cv::Mat variable_importance = rtrees->getVarImportance();
std::cout << "Estimated variable importance" << std::endl;
for (int i = 0; i < variable_importance.rows; i++) {
std::cout << "Variable " << i << ": " << variable_importance.at<float>(i, 0) << std::endl;
}
return 0;
}

View File

@ -0,0 +1,73 @@
/**
* @file AddingImagesTrackbar.cpp
* @brief Simple linear blender ( dst = alpha*src1 + beta*src2 )
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using std::cout;
/** Global Variables */
const int alpha_slider_max = 100;
int alpha_slider;
double alpha;
double beta;
/** Matrices to store images */
Mat src1;
Mat src2;
Mat dst;
//![on_trackbar]
/**
* @function on_trackbar
* @brief Callback for trackbar
*/
static void on_trackbar( int, void* )
{
alpha = (double) alpha_slider/alpha_slider_max ;
beta = ( 1.0 - alpha );
addWeighted( src1, alpha, src2, beta, 0.0, dst);
imshow( "Linear Blend", dst );
}
//![on_trackbar]
/**
* @function main
* @brief Main function
*/
int main( void )
{
//![load]
/// Read images ( both have to be of the same size and type )
src1 = imread( samples::findFile("LinuxLogo.jpg") );
src2 = imread( samples::findFile("WindowsLogo.jpg") );
//![load]
if( src1.empty() ) { cout << "Error loading src1 \n"; return -1; }
if( src2.empty() ) { cout << "Error loading src2 \n"; return -1; }
/// Initialize values
alpha_slider = 0;
//![window]
namedWindow("Linear Blend", WINDOW_AUTOSIZE); // Create Window
//![window]
//![create_trackbar]
char TrackbarName[50];
sprintf( TrackbarName, "Alpha x %d", alpha_slider_max );
createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar );
//![create_trackbar]
/// Show some stuff
on_trackbar( alpha_slider, 0 );
/// Wait until user press some key
waitKey(0);
return 0;
}

View File

@ -0,0 +1,73 @@
/**
* @file BasicLinearTransformsTrackbar.cpp
* @brief Simple program to change contrast and brightness
* @date Mon, June 6, 2011
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
// we're NOT "using namespace std;" here, to avoid collisions between the beta variable and std::beta in c++17
using namespace cv;
/** Global Variables */
const int alpha_max = 5;
const int beta_max = 125;
int alpha; /**< Simple contrast control */
int beta; /**< Simple brightness control*/
/** Matrices to store images */
Mat image;
/**
* @function on_trackbar
* @brief Called whenever any of alpha or beta changes
*/
static void on_trackbar( int, void* )
{
Mat new_image = Mat::zeros( image.size(), image.type() );
for( int y = 0; y < image.rows; y++ )
for( int x = 0; x < image.cols; x++ )
for( int c = 0; c < 3; c++ )
new_image.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );
imshow("New Image", new_image);
}
/**
* @function main
* @brief Main function
*/
int main( int argc, char** argv )
{
/// Read image given by user
String imageName("lena.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
image = imread( samples::findFile( imageName ) );
/// Initialize values
alpha = 1;
beta = 0;
/// Create Windows
namedWindow("Original Image", 1);
namedWindow("New Image", 1);
/// Create Trackbars
createTrackbar( "Contrast", "New Image", &alpha, alpha_max, on_trackbar );
createTrackbar( "Brightness", "New Image", &beta, beta_max, on_trackbar );
/// Show some stuff
imshow("Original Image", image);
imshow("New Image", image);
/// Wait until user press some key
waitKey();
return 0;
}

View File

@ -0,0 +1,51 @@
/**
* @function EqualizeHist_Demo.cpp
* @brief Demo code for equalizeHist function
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/**
* @function main
*/
int main( int argc, char** argv )
{
//! [Load image]
CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
//! [Load image]
//! [Convert to grayscale]
cvtColor( src, src, COLOR_BGR2GRAY );
//! [Convert to grayscale]
//! [Apply Histogram Equalization]
Mat dst;
equalizeHist( src, dst );
//! [Apply Histogram Equalization]
//! [Display results]
imshow( "Source image", src );
imshow( "Equalized Image", dst );
//! [Display results]
//! [Wait until user exits the program]
waitKey();
//! [Wait until user exits the program]
return 0;
}

View File

@ -0,0 +1,137 @@
/**
* @file MatchTemplate_Demo.cpp
* @brief Sample code to use the function MatchTemplate
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
//! [declare]
/// Global Variables
bool use_mask;
Mat img; Mat templ; Mat mask; Mat result;
const char* image_window = "Source Image";
const char* result_window = "Result window";
int match_method;
int max_Trackbar = 5;
//! [declare]
/// Function Headers
void MatchingMethod( int, void* );
/**
* @function main
*/
int main( int argc, char** argv )
{
if (argc < 3)
{
cout << "Not enough parameters" << endl;
cout << "Usage:\n" << argv[0] << " <image_name> <template_name> [<mask_name>]" << endl;
return -1;
}
//! [load_image]
/// Load image and template
img = imread( argv[1], IMREAD_COLOR );
templ = imread( argv[2], IMREAD_COLOR );
if(argc > 3) {
use_mask = true;
mask = imread( argv[3], IMREAD_COLOR );
}
if(img.empty() || templ.empty() || (use_mask && mask.empty()))
{
cout << "Can't read one of the images" << endl;
return EXIT_FAILURE;
}
//! [load_image]
//! [create_windows]
/// Create windows
namedWindow( image_window, WINDOW_AUTOSIZE );
namedWindow( result_window, WINDOW_AUTOSIZE );
//! [create_windows]
//! [create_trackbar]
/// Create Trackbar
const char* trackbar_label = "Method: \n 0: SQDIFF \n 1: SQDIFF NORMED \n 2: TM CCORR \n 3: TM CCORR NORMED \n 4: TM COEFF \n 5: TM COEFF NORMED";
createTrackbar( trackbar_label, image_window, &match_method, max_Trackbar, MatchingMethod );
//! [create_trackbar]
MatchingMethod( 0, 0 );
//! [wait_key]
waitKey(0);
return EXIT_SUCCESS;
//! [wait_key]
}
/**
* @function MatchingMethod
* @brief Trackbar callback
*/
void MatchingMethod( int, void* )
{
//! [copy_source]
/// Source image to display
Mat img_display;
img.copyTo( img_display );
//! [copy_source]
//! [create_result_matrix]
/// Create the result matrix
int result_cols = img.cols - templ.cols + 1;
int result_rows = img.rows - templ.rows + 1;
result.create( result_rows, result_cols, CV_32FC1 );
//! [create_result_matrix]
//! [match_template]
/// Do the Matching and Normalize
bool method_accepts_mask = (TM_SQDIFF == match_method || match_method == TM_CCORR_NORMED);
if (use_mask && method_accepts_mask)
{ matchTemplate( img, templ, result, match_method, mask); }
else
{ matchTemplate( img, templ, result, match_method); }
//! [match_template]
//! [normalize]
normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
//! [normalize]
//! [best_match]
/// Localizing the best match with minMaxLoc
double minVal; double maxVal; Point minLoc; Point maxLoc;
Point matchLoc;
minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
//! [best_match]
//! [match_loc]
/// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
if( match_method == TM_SQDIFF || match_method == TM_SQDIFF_NORMED )
{ matchLoc = minLoc; }
else
{ matchLoc = maxLoc; }
//! [match_loc]
//! [imshow]
/// Show me what you got
rectangle( img_display, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
rectangle( result, matchLoc, Point( matchLoc.x + templ.cols , matchLoc.y + templ.rows ), Scalar::all(0), 2, 8, 0 );
imshow( image_window, img_display );
imshow( result_window, result );
//! [imshow]
return;
}

View File

@ -0,0 +1,106 @@
/**
* @file BackProject_Demo1.cpp
* @brief Sample code for backproject function usage
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/// Global Variables
Mat hue;
int bins = 25;
/// Function Headers
void Hist_and_Backproj(int, void* );
/**
* @function main
*/
int main( int argc, char* argv[] )
{
//! [Read the image]
CommandLineParser parser( argc, argv, "{@input | | input image}" );
Mat src = imread( parser.get<String>( "@input" ) );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
//! [Read the image]
//! [Transform it to HSV]
Mat hsv;
cvtColor( src, hsv, COLOR_BGR2HSV );
//! [Transform it to HSV]
//! [Use only the Hue value]
hue.create(hsv.size(), hsv.depth());
int ch[] = { 0, 0 };
mixChannels( &hsv, 1, &hue, 1, ch, 1 );
//! [Use only the Hue value]
//! [Create Trackbar to enter the number of bins]
const char* window_image = "Source image";
namedWindow( window_image );
createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj );
Hist_and_Backproj(0, 0);
//! [Create Trackbar to enter the number of bins]
//! [Show the image]
imshow( window_image, src );
// Wait until user exits the program
waitKey();
//! [Show the image]
return 0;
}
/**
* @function Hist_and_Backproj
* @brief Callback to Trackbar
*/
void Hist_and_Backproj(int, void* )
{
//! [initialize]
int histSize = MAX( bins, 2 );
float hue_range[] = { 0, 180 };
const float* ranges[] = { hue_range };
//! [initialize]
//! [Get the Histogram and normalize it]
Mat hist;
calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, ranges, true, false );
normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );
//! [Get the Histogram and normalize it]
//! [Get Backprojection]
Mat backproj;
calcBackProject( &hue, 1, 0, hist, backproj, ranges, 1, true );
//! [Get Backprojection]
//! [Draw the backproj]
imshow( "BackProj", backproj );
//! [Draw the backproj]
//! [Draw the histogram]
int w = 400, h = 400;
int bin_w = cvRound( (double) w / histSize );
Mat histImg = Mat::zeros( h, w, CV_8UC3 );
for (int i = 0; i < bins; i++)
{
rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at<float>(i)*h/255.0 ) ),
Scalar( 0, 0, 255 ), FILLED );
}
imshow( "Histogram", histImg );
//! [Draw the histogram]
}

View File

@ -0,0 +1,105 @@
/**
* @file BackProject_Demo2.cpp
* @brief Sample code for backproject function usage ( a bit more elaborated )
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/// Global Variables
Mat src, hsv, mask;
int low = 20, up = 20;
const char* window_image = "Source image";
/// Function Headers
void Hist_and_Backproj( );
void pickPoint (int event, int x, int y, int, void* );
/**
* @function main
*/
int main( int, char** argv )
{
/// Read the image
src = imread( argv[1] );
/// Transform it to HSV
cvtColor( src, hsv, COLOR_BGR2HSV );
/// Show the image
namedWindow( window_image );
imshow( window_image, src );
/// Set Trackbars for floodfill thresholds
createTrackbar( "Low thresh", window_image, &low, 255, 0 );
createTrackbar( "High thresh", window_image, &up, 255, 0 );
/// Set a Mouse Callback
setMouseCallback( window_image, pickPoint, 0 );
waitKey();
return 0;
}
/**
* @function pickPoint
*/
void pickPoint (int event, int x, int y, int, void* )
{
if( event != EVENT_LBUTTONDOWN )
{
return;
}
// Fill and get the mask
Point seed = Point( x, y );
int newMaskVal = 255;
Scalar newVal = Scalar( 120, 120, 120 );
int connectivity = 8;
int flags = connectivity + (newMaskVal << 8 ) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
Mat mask2 = Mat::zeros( src.rows + 2, src.cols + 2, CV_8U );
floodFill( src, mask2, seed, newVal, 0, Scalar( low, low, low ), Scalar( up, up, up), flags );
mask = mask2( Range( 1, mask2.rows - 1 ), Range( 1, mask2.cols - 1 ) );
imshow( "Mask", mask );
Hist_and_Backproj( );
}
/**
* @function Hist_and_Backproj
*/
void Hist_and_Backproj( )
{
Mat hist;
int h_bins = 30; int s_bins = 32;
int histSize[] = { h_bins, s_bins };
float h_range[] = { 0, 180 };
float s_range[] = { 0, 256 };
const float* ranges[] = { h_range, s_range };
int channels[] = { 0, 1 };
/// Get the Histogram and normalize it
calcHist( &hsv, 1, channels, mask, hist, 2, histSize, ranges, true, false );
normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );
/// Get Backprojection
Mat backproj;
calcBackProject( &hsv, 1, channels, hist, backproj, ranges, 1, true );
/// Draw the backproj
imshow( "BackProj", backproj );
}

View File

@ -0,0 +1,89 @@
/**
* @function calcHist_Demo.cpp
* @brief Demo code to use the function calcHist
* @author
*/
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
/**
* @function main
*/
int main(int argc, char** argv)
{
//! [Load image]
CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
if( src.empty() )
{
return EXIT_FAILURE;
}
//! [Load image]
//! [Separate the image in 3 places ( B, G and R )]
vector<Mat> bgr_planes;
split( src, bgr_planes );
//! [Separate the image in 3 places ( B, G and R )]
//! [Establish the number of bins]
int histSize = 256;
//! [Establish the number of bins]
//! [Set the ranges ( for B,G,R) )]
float range[] = { 0, 256 }; //the upper boundary is exclusive
const float* histRange[] = { range };
//! [Set the ranges ( for B,G,R) )]
//! [Set histogram param]
bool uniform = true, accumulate = false;
//! [Set histogram param]
//! [Compute the histograms]
Mat b_hist, g_hist, r_hist;
calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, histRange, uniform, accumulate );
calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, histRange, uniform, accumulate );
calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, histRange, uniform, accumulate );
//! [Compute the histograms]
//! [Draw the histograms for B, G and R]
int hist_w = 512, hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );
//! [Draw the histograms for B, G and R]
//! [Normalize the result to ( 0, histImage.rows )]
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
//! [Normalize the result to ( 0, histImage.rows )]
//! [Draw for each channel]
for( int i = 1; i < histSize; i++ )
{
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),
Scalar( 255, 0, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),
Scalar( 0, 255, 0), 2, 8, 0 );
line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ),
Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),
Scalar( 0, 0, 255), 2, 8, 0 );
}
//! [Draw for each channel]
//! [Display]
imshow("Source image", src );
imshow("calcHist Demo", histImage );
waitKey();
//! [Display]
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,95 @@
/**
* @file compareHist_Demo.cpp
* @brief Sample code to use the function compareHist
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
const char* keys =
"{ help h| | Print help message. }"
"{ @input1 | | Path to input image 1. }"
"{ @input2 | | Path to input image 2. }"
"{ @input3 | | Path to input image 3. }";
/**
* @function main
*/
int main( int argc, char** argv )
{
//! [Load three images with different environment settings]
CommandLineParser parser( argc, argv, keys );
Mat src_base = imread( parser.get<String>("input1") );
Mat src_test1 = imread( parser.get<String>("input2") );
Mat src_test2 = imread( parser.get<String>("input3") );
if( src_base.empty() || src_test1.empty() || src_test2.empty() )
{
cout << "Could not open or find the images!\n" << endl;
parser.printMessage();
return -1;
}
//! [Load three images with different environment settings]
//! [Convert to HSV]
Mat hsv_base, hsv_test1, hsv_test2;
cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
cvtColor( src_test1, hsv_test1, COLOR_BGR2HSV );
cvtColor( src_test2, hsv_test2, COLOR_BGR2HSV );
//! [Convert to HSV]
//! [Convert to HSV half]
Mat hsv_half_down = hsv_base( Range( hsv_base.rows/2, hsv_base.rows ), Range( 0, hsv_base.cols ) );
//! [Convert to HSV half]
//! [Using 50 bins for hue and 60 for saturation]
int h_bins = 50, s_bins = 60;
int histSize[] = { h_bins, s_bins };
// hue varies from 0 to 179, saturation from 0 to 255
float h_ranges[] = { 0, 180 };
float s_ranges[] = { 0, 256 };
const float* ranges[] = { h_ranges, s_ranges };
// Use the 0-th and 1-st channels
int channels[] = { 0, 1 };
//! [Using 50 bins for hue and 60 for saturation]
//! [Calculate the histograms for the HSV images]
Mat hist_base, hist_half_down, hist_test1, hist_test2;
calcHist( &hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false );
normalize( hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat() );
calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false );
normalize( hist_half_down, hist_half_down, 0, 1, NORM_MINMAX, -1, Mat() );
calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false );
normalize( hist_test1, hist_test1, 0, 1, NORM_MINMAX, -1, Mat() );
calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false );
normalize( hist_test2, hist_test2, 0, 1, NORM_MINMAX, -1, Mat() );
//! [Calculate the histograms for the HSV images]
//! [Apply the histogram comparison methods]
for( int compare_method = 0; compare_method < 4; compare_method++ )
{
double base_base = compareHist( hist_base, hist_base, compare_method );
double base_half = compareHist( hist_base, hist_half_down, compare_method );
double base_test1 = compareHist( hist_base, hist_test1, compare_method );
double base_test2 = compareHist( hist_base, hist_test2, compare_method );
cout << "Method " << compare_method << " Perfect, Base-Half, Base-Test(1), Base-Test(2) : "
<< base_base << " / " << base_half << " / " << base_test1 << " / " << base_test2 << endl;
}
//! [Apply the histogram comparison methods]
cout << "Done \n";
return 0;
}

View File

@ -0,0 +1,74 @@
/**
* @file BasicLinearTransforms.cpp
* @brief Simple program to change contrast and brightness
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
// we're NOT "using namespace std;" here, to avoid collisions between the beta variable and std::beta in c++17
using std::cin;
using std::cout;
using std::endl;
using namespace cv;
/**
* @function main
* @brief Main function
*/
int main( int argc, char** argv )
{
/// Read image given by user
//! [basic-linear-transform-load]
CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
Mat image = imread( samples::findFile( parser.get<String>( "@input" ) ) );
if( image.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
//! [basic-linear-transform-load]
//! [basic-linear-transform-output]
Mat new_image = Mat::zeros( image.size(), image.type() );
//! [basic-linear-transform-output]
//! [basic-linear-transform-parameters]
double alpha = 1.0; /*< Simple contrast control */
int beta = 0; /*< Simple brightness control */
/// Initialize values
cout << " Basic Linear Transforms " << endl;
cout << "-------------------------" << endl;
cout << "* Enter the alpha value [1.0-3.0]: "; cin >> alpha;
cout << "* Enter the beta value [0-100]: "; cin >> beta;
//! [basic-linear-transform-parameters]
/// Do the operation new_image(i,j) = alpha*image(i,j) + beta
/// Instead of these 'for' loops we could have used simply:
/// image.convertTo(new_image, -1, alpha, beta);
/// but we wanted to show you how to access the pixels :)
//! [basic-linear-transform-operation]
for( int y = 0; y < image.rows; y++ ) {
for( int x = 0; x < image.cols; x++ ) {
for( int c = 0; c < image.channels(); c++ ) {
new_image.at<Vec3b>(y,x)[c] =
saturate_cast<uchar>( alpha*image.at<Vec3b>(y,x)[c] + beta );
}
}
}
//! [basic-linear-transform-operation]
//! [basic-linear-transform-display]
/// Show stuff
imshow("Original Image", image);
imshow("New Image", new_image);
/// Wait until the user press a key
waitKey();
//! [basic-linear-transform-display]
return 0;
}

View File

@ -0,0 +1,44 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
int main(){
Mat input_image = (Mat_<uchar>(8, 8) <<
0, 0, 0, 0, 0, 0, 0, 0,
0, 255, 255, 255, 0, 0, 0, 255,
0, 255, 255, 255, 0, 0, 0, 0,
0, 255, 255, 255, 0, 255, 0, 0,
0, 0, 255, 0, 0, 0, 0, 0,
0, 0, 255, 0, 0, 255, 255, 0,
0, 255, 0, 255, 0, 0, 255, 0,
0, 255, 255, 255, 0, 0, 0, 0);
Mat kernel = (Mat_<int>(3, 3) <<
0, 1, 0,
1, -1, 1,
0, 1, 0);
Mat output_image;
morphologyEx(input_image, output_image, MORPH_HITMISS, kernel);
const int rate = 50;
kernel = (kernel + 1) * 127;
kernel.convertTo(kernel, CV_8U);
resize(kernel, kernel, Size(), rate, rate, INTER_NEAREST);
imshow("kernel", kernel);
moveWindow("kernel", 0, 0);
resize(input_image, input_image, Size(), rate, rate, INTER_NEAREST);
imshow("Original", input_image);
moveWindow("Original", 0, 200);
resize(output_image, output_image, Size(), rate, rate, INTER_NEAREST);
imshow("Hit or Miss", output_image);
moveWindow("Hit or Miss", 500, 200);
waitKey(0);
return 0;
}

View File

@ -0,0 +1,118 @@
/**
* @file Morphology_1.cpp
* @brief Erosion and Dilation sample code
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/// Global variables
Mat src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
/** Function Headers */
void Erosion( int, void* );
void Dilation( int, void* );
//![main]
/**
* @function main
*/
int main( int argc, char** argv )
{
/// Load an image
CommandLineParser parser( argc, argv, "{@input | LinuxLogo.jpg | input image}" );
src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
if( src.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
/// Create windows
namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );
namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );
moveWindow( "Dilation Demo", src.cols, 0 );
/// Create Erosion Trackbar
createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",
&erosion_elem, max_elem,
Erosion );
createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo",
&erosion_size, max_kernel_size,
Erosion );
/// Create Dilation Trackbar
createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",
&dilation_elem, max_elem,
Dilation );
createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo",
&dilation_size, max_kernel_size,
Dilation );
/// Default start
Erosion( 0, 0 );
Dilation( 0, 0 );
waitKey(0);
return 0;
}
//![main]
//![erosion]
/**
* @function Erosion
*/
void Erosion( int, void* )
{
int erosion_type = 0;
if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
//![kernel]
Mat element = getStructuringElement( erosion_type,
Size( 2*erosion_size + 1, 2*erosion_size+1 ),
Point( erosion_size, erosion_size ) );
//![kernel]
/// Apply the erosion operation
erode( src, erosion_dst, element );
imshow( "Erosion Demo", erosion_dst );
}
//![erosion]
//![dilation]
/**
* @function Dilation
*/
void Dilation( int, void* )
{
int dilation_type = 0;
if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
Mat element = getStructuringElement( dilation_type,
Size( 2*dilation_size + 1, 2*dilation_size+1 ),
Point( dilation_size, dilation_size ) );
/// Apply the dilation operation
dilate( src, dilation_dst, element );
imshow( "Dilation Demo", dilation_dst );
}
//![dilation]

View File

@ -0,0 +1,93 @@
/**
* @file Morphology_2.cpp
* @brief Advanced morphology Transformations sample code
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
/// Global variables
Mat src, dst;
int morph_elem = 0;
int morph_size = 0;
int morph_operator = 0;
int const max_operator = 4;
int const max_elem = 2;
int const max_kernel_size = 21;
const char* window_name = "Morphology Transformations Demo";
/** Function Headers */
void Morphology_Operations( int, void* );
/**
* @function main
*/
int main( int argc, char** argv )
{
//![load]
CommandLineParser parser( argc, argv, "{@input | baboon.jpg | input image}" );
src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );
if (src.empty())
{
std::cout << "Could not open or find the image!\n" << std::endl;
std::cout << "Usage: " << argv[0] << " <Input image>" << std::endl;
return EXIT_FAILURE;
}
//![load]
//![window]
namedWindow( window_name, WINDOW_AUTOSIZE ); // Create window
//![window]
//![create_trackbar1]
/// Create Trackbar to select Morphology operation
createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );
//![create_trackbar1]
//![create_trackbar2]
/// Create Trackbar to select kernel type
createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
&morph_elem, max_elem,
Morphology_Operations );
//![create_trackbar2]
//![create_trackbar3]
/// Create Trackbar to choose kernel size
createTrackbar( "Kernel size:\n 2n +1", window_name,
&morph_size, max_kernel_size,
Morphology_Operations );
//![create_trackbar3]
/// Default start
Morphology_Operations( 0, 0 );
waitKey(0);
return 0;
}
//![morphology_operations]
/**
* @function Morphology_Operations
*/
void Morphology_Operations( int, void* )
{
// Since MORPH_X : 2,3,4,5 and 6
//![operation]
int operation = morph_operator + 2;
//![operation]
Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
/// Apply the specified morphology operation
morphologyEx( src, dst, operation, element );
imshow( window_name, dst );
}
//![morphology_operations]

View File

@ -0,0 +1,69 @@
/**
* @file Pyramids.cpp
* @brief Sample code of image pyramids (pyrDown and pyrUp)
* @author OpenCV team
*/
#include "iostream"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
const char* window_name = "Pyramids Demo";
/**
* @function main
*/
int main( int argc, char** argv )
{
/// General instructions
cout << "\n Zoom In-Out demo \n "
"------------------ \n"
" * [i] -> Zoom in \n"
" * [o] -> Zoom out \n"
" * [ESC] -> Close program \n" << endl;
//![load]
const char* filename = argc >=2 ? argv[1] : "chicky_512.png";
// Loads an image
Mat src = imread( samples::findFile( filename ) );
// Check if image is loaded fine
if(src.empty()){
printf(" Error opening image\n");
printf(" Program Arguments: [image_name -- default chicky_512.png] \n");
return EXIT_FAILURE;
}
//![load]
//![loop]
for(;;)
{
//![show_image]
imshow( window_name, src );
//![show_image]
char c = (char)waitKey(0);
if( c == 27 )
{ break; }
//![pyrup]
else if( c == 'i' )
{ pyrUp( src, src, Size( src.cols*2, src.rows*2 ) );
printf( "** Zoom In: Image x 2 \n" );
}
//![pyrup]
//![pyrdown]
else if( c == 'o' )
{ pyrDown( src, src, Size( src.cols/2, src.rows/2 ) );
printf( "** Zoom Out: Image / 2 \n" );
}
//![pyrdown]
}
//![loop]
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,153 @@
/**
* file Smoothing.cpp
* brief Sample code for simple filters
* author OpenCV team
*/
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
/// Global Variables
int DELAY_CAPTION = 1500;
int DELAY_BLUR = 100;
int MAX_KERNEL_LENGTH = 31;
Mat src; Mat dst;
char window_name[] = "Smoothing Demo";
/// Function headers
int display_caption( const char* caption );
int display_dst( int delay );
/**
* function main
*/
int main( int argc, char ** argv )
{
namedWindow( window_name, WINDOW_AUTOSIZE );
/// Load the source image
const char* filename = argc >=2 ? argv[1] : "lena.jpg";
src = imread( samples::findFile( filename ), IMREAD_COLOR );
if (src.empty())
{
printf(" Error opening image\n");
printf(" Usage:\n %s [image_name-- default lena.jpg] \n", argv[0]);
return EXIT_FAILURE;
}
if( display_caption( "Original Image" ) != 0 )
{
return 0;
}
dst = src.clone();
if( display_dst( DELAY_CAPTION ) != 0 )
{
return 0;
}
/// Applying Homogeneous blur
if( display_caption( "Homogeneous Blur" ) != 0 )
{
return 0;
}
//![blur]
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
blur( src, dst, Size( i, i ), Point(-1,-1) );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
//![blur]
/// Applying Gaussian blur
if( display_caption( "Gaussian Blur" ) != 0 )
{
return 0;
}
//![gaussianblur]
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
GaussianBlur( src, dst, Size( i, i ), 0, 0 );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
//![gaussianblur]
/// Applying Median blur
if( display_caption( "Median Blur" ) != 0 )
{
return 0;
}
//![medianblur]
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
medianBlur ( src, dst, i );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
//![medianblur]
/// Applying Bilateral Filter
if( display_caption( "Bilateral Blur" ) != 0 )
{
return 0;
}
//![bilateralfilter]
for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
{
bilateralFilter ( src, dst, i, i*2, i/2 );
if( display_dst( DELAY_BLUR ) != 0 )
{
return 0;
}
}
//![bilateralfilter]
/// Done
display_caption( "Done!" );
return 0;
}
/**
* @function display_caption
*/
int display_caption( const char* caption )
{
dst = Mat::zeros( src.size(), src.type() );
putText( dst, caption,
Point( src.cols/4, src.rows/2),
FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
return display_dst(DELAY_CAPTION);
}
/**
* @function display_dst
*/
int display_dst( int delay )
{
imshow( window_name, dst );
int c = waitKey ( delay );
if( c >= 0 ) { return -1; }
return 0;
}

View File

@ -0,0 +1,87 @@
/**
* @file Threshold.cpp
* @brief Sample code that shows how to use the diverse threshold options offered by OpenCV
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using std::cout;
/// Global variables
int threshold_value = 0;
int threshold_type = 3;
int const max_value = 255;
int const max_type = 4;
int const max_binary_value = 255;
Mat src, src_gray, dst;
const char* window_name = "Threshold Demo";
const char* trackbar_type = "Type: \n 0: Binary \n 1: Binary Inverted \n 2: Truncate \n 3: To Zero \n 4: To Zero Inverted";
const char* trackbar_value = "Value";
//![Threshold_Demo]
/**
* @function Threshold_Demo
*/
static void Threshold_Demo( int, void* )
{
/* 0: Binary
1: Binary Inverted
2: Threshold Truncated
3: Threshold to Zero
4: Threshold to Zero Inverted
*/
threshold( src_gray, dst, threshold_value, max_binary_value, threshold_type );
imshow( window_name, dst );
}
//![Threshold_Demo]
/**
* @function main
*/
int main( int argc, char** argv )
{
//! [load]
String imageName("stuff.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image
if (src.empty())
{
cout << "Cannot read the image: " << imageName << std::endl;
return -1;
}
cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to Gray
//! [load]
//! [window]
namedWindow( window_name, WINDOW_AUTOSIZE ); // Create a window to display results
//! [window]
//! [trackbar]
createTrackbar( trackbar_type,
window_name, &threshold_type,
max_type, Threshold_Demo ); // Create a Trackbar to choose type of Threshold
createTrackbar( trackbar_value,
window_name, &threshold_value,
max_value, Threshold_Demo ); // Create a Trackbar to choose Threshold value
//! [trackbar]
Threshold_Demo( 0, 0 ); // Call the function to initialize
/// Wait until the user finishes the program
waitKey();
return 0;
}

View File

@ -0,0 +1,105 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace cv;
/** Global Variables */
const int max_value_H = 360/2;
const int max_value = 255;
const String window_capture_name = "Video Capture";
const String window_detection_name = "Object Detection";
int low_H = 0, low_S = 0, low_V = 0;
int high_H = max_value_H, high_S = max_value, high_V = max_value;
//! [low]
static void on_low_H_thresh_trackbar(int, void *)
{
low_H = min(high_H-1, low_H);
setTrackbarPos("Low H", window_detection_name, low_H);
}
//! [low]
//! [high]
static void on_high_H_thresh_trackbar(int, void *)
{
high_H = max(high_H, low_H+1);
setTrackbarPos("High H", window_detection_name, high_H);
}
//! [high]
static void on_low_S_thresh_trackbar(int, void *)
{
low_S = min(high_S-1, low_S);
setTrackbarPos("Low S", window_detection_name, low_S);
}
static void on_high_S_thresh_trackbar(int, void *)
{
high_S = max(high_S, low_S+1);
setTrackbarPos("High S", window_detection_name, high_S);
}
static void on_low_V_thresh_trackbar(int, void *)
{
low_V = min(high_V-1, low_V);
setTrackbarPos("Low V", window_detection_name, low_V);
}
static void on_high_V_thresh_trackbar(int, void *)
{
high_V = max(high_V, low_V+1);
setTrackbarPos("High V", window_detection_name, high_V);
}
int main(int argc, char* argv[])
{
//! [cap]
VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0);
//! [cap]
//! [window]
namedWindow(window_capture_name);
namedWindow(window_detection_name);
//! [window]
//! [trackbar]
// Trackbars to set thresholds for HSV values
createTrackbar("Low H", window_detection_name, &low_H, max_value_H, on_low_H_thresh_trackbar);
createTrackbar("High H", window_detection_name, &high_H, max_value_H, on_high_H_thresh_trackbar);
createTrackbar("Low S", window_detection_name, &low_S, max_value, on_low_S_thresh_trackbar);
createTrackbar("High S", window_detection_name, &high_S, max_value, on_high_S_thresh_trackbar);
createTrackbar("Low V", window_detection_name, &low_V, max_value, on_low_V_thresh_trackbar);
createTrackbar("High V", window_detection_name, &high_V, max_value, on_high_V_thresh_trackbar);
//! [trackbar]
Mat frame, frame_HSV, frame_threshold;
while (true) {
//! [while]
cap >> frame;
if(frame.empty())
{
break;
}
// Convert from BGR to HSV colorspace
cvtColor(frame, frame_HSV, COLOR_BGR2HSV);
// Detect the object based on HSV Range Values
inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold);
//! [while]
//! [show]
// Show the frames
imshow(window_capture_name, frame);
imshow(window_detection_name, frame_threshold);
//! [show]
char key = (char) waitKey(30);
if (key == 'q' || key == 27)
{
break;
}
}
return 0;
}

View File

@ -0,0 +1,113 @@
/**
* @brief You will learn how to segment an anisotropic image with a single local orientation by a gradient structure tensor (GST)
* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin
*/
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
using namespace cv;
using namespace std;
//! [calcGST_proto]
void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w);
//! [calcGST_proto]
int main()
{
int W = 52; // window size is WxW
double C_Thr = 0.43; // threshold for coherency
int LowThr = 35; // threshold1 for orientation, it ranges from 0 to 180
int HighThr = 57; // threshold2 for orientation, it ranges from 0 to 180
Mat imgIn = imread("input.jpg", IMREAD_GRAYSCALE);
if (imgIn.empty()) //check whether the image is loaded or not
{
cout << "ERROR : Image cannot be loaded..!!" << endl;
return -1;
}
//! [main_extra]
//! [main]
Mat imgCoherency, imgOrientation;
calcGST(imgIn, imgCoherency, imgOrientation, W);
//! [thresholding]
Mat imgCoherencyBin;
imgCoherencyBin = imgCoherency > C_Thr;
Mat imgOrientationBin;
inRange(imgOrientation, Scalar(LowThr), Scalar(HighThr), imgOrientationBin);
//! [thresholding]
//! [combining]
Mat imgBin;
imgBin = imgCoherencyBin & imgOrientationBin;
//! [combining]
//! [main]
normalize(imgCoherency, imgCoherency, 0, 255, NORM_MINMAX);
normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAX);
imwrite("result.jpg", 0.5*(imgIn + imgBin));
imwrite("Coherency.jpg", imgCoherency);
imwrite("Orientation.jpg", imgOrientation);
//! [main_extra]
return 0;
}
//! [calcGST]
//! [calcJ_header]
void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w)
{
Mat img;
inputImg.convertTo(img, CV_32F);
// GST components calculation (start)
// J = (J11 J12; J12 J22) - GST
Mat imgDiffX, imgDiffY, imgDiffXY;
Sobel(img, imgDiffX, CV_32F, 1, 0, 3);
Sobel(img, imgDiffY, CV_32F, 0, 1, 3);
multiply(imgDiffX, imgDiffY, imgDiffXY);
//! [calcJ_header]
Mat imgDiffXX, imgDiffYY;
multiply(imgDiffX, imgDiffX, imgDiffXX);
multiply(imgDiffY, imgDiffY, imgDiffYY);
Mat J11, J22, J12; // J11, J22 and J12 are GST components
boxFilter(imgDiffXX, J11, CV_32F, Size(w, w));
boxFilter(imgDiffYY, J22, CV_32F, Size(w, w));
boxFilter(imgDiffXY, J12, CV_32F, Size(w, w));
// GST components calculation (stop)
// eigenvalue calculation (start)
// lambda1 = 0.5*(J11 + J22 + sqrt((J11-J22)^2 + 4*J12^2))
// lambda2 = 0.5*(J11 + J22 - sqrt((J11-J22)^2 + 4*J12^2))
Mat tmp1, tmp2, tmp3, tmp4;
tmp1 = J11 + J22;
tmp2 = J11 - J22;
multiply(tmp2, tmp2, tmp2);
multiply(J12, J12, tmp3);
sqrt(tmp2 + 4.0 * tmp3, tmp4);
Mat lambda1, lambda2;
lambda1 = tmp1 + tmp4;
lambda1 = 0.5*lambda1; // biggest eigenvalue
lambda2 = tmp1 - tmp4;
lambda2 = 0.5*lambda2; // smallest eigenvalue
// eigenvalue calculation (stop)
// Coherency calculation (start)
// Coherency = (lambda1 - lambda2)/(lambda1 + lambda2)) - measure of anisotropism
// Coherency is anisotropy degree (consistency of local orientation)
divide(lambda1 - lambda2, lambda1 + lambda2, imgCoherencyOut);
// Coherency calculation (stop)
// orientation angle calculation (start)
// tan(2*Alpha) = 2*J12/(J22 - J11)
// Alpha = 0.5 atan2(2*J12/(J22 - J11))
phase(J22 - J11, 2.0*J12, imgOrientationOut, true);
imgOrientationOut = 0.5*imgOrientationOut;
// orientation angle calculation (stop)
}
//! [calcGST]

View File

@ -0,0 +1,185 @@
/**
* @file Drawing_1.cpp
* @brief Simple geometric drawing
* @author OpenCV team
*/
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#define w 400
using namespace cv;
/// Function headers
void MyEllipse( Mat img, double angle );
void MyFilledCircle( Mat img, Point center );
void MyPolygon( Mat img );
void MyLine( Mat img, Point start, Point end );
/**
* @function main
* @brief Main function
*/
int main( void ){
//![create_images]
/// Windows names
char atom_window[] = "Drawing 1: Atom";
char rook_window[] = "Drawing 2: Rook";
/// Create black empty images
Mat atom_image = Mat::zeros( w, w, CV_8UC3 );
Mat rook_image = Mat::zeros( w, w, CV_8UC3 );
//![create_images]
/// 1. Draw a simple atom:
/// -----------------------
//![draw_atom]
/// 1.a. Creating ellipses
MyEllipse( atom_image, 90 );
MyEllipse( atom_image, 0 );
MyEllipse( atom_image, 45 );
MyEllipse( atom_image, -45 );
/// 1.b. Creating circles
MyFilledCircle( atom_image, Point( w/2, w/2) );
//![draw_atom]
/// 2. Draw a rook
/// ------------------
//![draw_rook]
/// 2.a. Create a convex polygon
MyPolygon( rook_image );
//![rectangle]
/// 2.b. Creating rectangles
rectangle( rook_image,
Point( 0, 7*w/8 ),
Point( w, w),
Scalar( 0, 255, 255 ),
FILLED,
LINE_8 );
//![rectangle]
/// 2.c. Create a few lines
MyLine( rook_image, Point( 0, 15*w/16 ), Point( w, 15*w/16 ) );
MyLine( rook_image, Point( w/4, 7*w/8 ), Point( w/4, w ) );
MyLine( rook_image, Point( w/2, 7*w/8 ), Point( w/2, w ) );
MyLine( rook_image, Point( 3*w/4, 7*w/8 ), Point( 3*w/4, w ) );
//![draw_rook]
/// 3. Display your stuff!
imshow( atom_window, atom_image );
moveWindow( atom_window, 0, 200 );
imshow( rook_window, rook_image );
moveWindow( rook_window, w, 200 );
waitKey( 0 );
return(0);
}
/// Function Declaration
/**
* @function MyEllipse
* @brief Draw a fixed-size ellipse with different angles
*/
//![my_ellipse]
void MyEllipse( Mat img, double angle )
{
int thickness = 2;
int lineType = 8;
ellipse( img,
Point( w/2, w/2 ),
Size( w/4, w/16 ),
angle,
0,
360,
Scalar( 255, 0, 0 ),
thickness,
lineType );
}
//![my_ellipse]
/**
* @function MyFilledCircle
* @brief Draw a fixed-size filled circle
*/
//![my_filled_circle]
void MyFilledCircle( Mat img, Point center )
{
circle( img,
center,
w/32,
Scalar( 0, 0, 255 ),
FILLED,
LINE_8 );
}
//![my_filled_circle]
/**
* @function MyPolygon
* @brief Draw a simple concave polygon (rook)
*/
//![my_polygon]
void MyPolygon( Mat img )
{
int lineType = LINE_8;
/** Create some points */
Point rook_points[1][20];
rook_points[0][0] = Point( w/4, 7*w/8 );
rook_points[0][1] = Point( 3*w/4, 7*w/8 );
rook_points[0][2] = Point( 3*w/4, 13*w/16 );
rook_points[0][3] = Point( 11*w/16, 13*w/16 );
rook_points[0][4] = Point( 19*w/32, 3*w/8 );
rook_points[0][5] = Point( 3*w/4, 3*w/8 );
rook_points[0][6] = Point( 3*w/4, w/8 );
rook_points[0][7] = Point( 26*w/40, w/8 );
rook_points[0][8] = Point( 26*w/40, w/4 );
rook_points[0][9] = Point( 22*w/40, w/4 );
rook_points[0][10] = Point( 22*w/40, w/8 );
rook_points[0][11] = Point( 18*w/40, w/8 );
rook_points[0][12] = Point( 18*w/40, w/4 );
rook_points[0][13] = Point( 14*w/40, w/4 );
rook_points[0][14] = Point( 14*w/40, w/8 );
rook_points[0][15] = Point( w/4, w/8 );
rook_points[0][16] = Point( w/4, 3*w/8 );
rook_points[0][17] = Point( 13*w/32, 3*w/8 );
rook_points[0][18] = Point( 5*w/16, 13*w/16 );
rook_points[0][19] = Point( w/4, 13*w/16 );
const Point* ppt[1] = { rook_points[0] };
int npt[] = { 20 };
fillPoly( img,
ppt,
npt,
1,
Scalar( 255, 255, 255 ),
lineType );
}
//![my_polygon]
/**
* @function MyLine
* @brief Draw a simple line
*/
//![my_line]
void MyLine( Mat img, Point start, Point end )
{
int thickness = 2;
int lineType = LINE_8;
line( img,
start,
end,
Scalar( 0, 0, 0 ),
thickness,
lineType );
}
//![my_line]

Some files were not shown because too many files have changed in this diff Show More