vendor: OpenCV 5.0.0 snapshot at 40738fb16ceddb5fb3fea747585f7ce6abb0605b

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:10:33 +08:00
commit f7f077da11
6933 changed files with 2335208 additions and 0 deletions
+363
View File
@@ -0,0 +1,363 @@
/*
* 3calibration.cpp -- Calibrate 3 cameras in a horizontal line together.
*/
#include "opencv2/geometry.hpp"
#include "opencv2/stereo.hpp"
#include "opencv2/calib.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/objdetect.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], IMREAD_COLOR);
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], IMREAD_COLOR);
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;
}
+79
View File
@@ -0,0 +1,79 @@
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_video
opencv_objdetect
opencv_photo
opencv_features
opencv_geometry
opencv_stereo
opencv_calib
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_photo)
set(DEPS_example_cpp_intelligent_scissors opencv_core opencv_photo 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)
ocv_target_link_libraries(${tgt} PRIVATE "${OPENGL_LIBRARIES}")
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)
add_subdirectory("example_cmake")
endif()
if(OpenCV_FOUND AND NOT OPENCV_EXAMPLES_SKIP_PARALLEL_BACKEND)
add_subdirectory("tutorial_code/core/parallel_backend")
endif()
+95
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;
}
+350
View File
@@ -0,0 +1,350 @@
#include <opencv2/objdetect/aruco_detector.hpp>
#include <iostream>
using namespace cv;
using namespace std;
static int _getSelfDistance(const Mat &marker) {
Mat bytes = aruco::Dictionary::getByteListFromBits(marker);
double minHamming = (double)marker.total() + 1;
for(int r = 1; r < 4; r++) {
cv::Mat tmp1(1, bytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < bytes.cols; ++i) {
rot0[i] = bytes.ptr()[i];
rot1[i] = bytes.ptr()[bytes.cols*r + i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if (currentHamming < minHamming) minHamming = currentHamming;
}
Mat b;
flip(marker, b, 0);
Mat flipBytes = aruco::Dictionary::getByteListFromBits(b);
for(int r = 0; r < 4; r++) {
cv::Mat tmp1(1, flipBytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < bytes.cols; ++i) {
rot0[i] = flipBytes.ptr()[i];
rot1[i] = bytes.ptr()[bytes.cols*r + i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if(currentHamming < minHamming) minHamming = currentHamming;
}
flip(marker, b, 1);
flipBytes = aruco::Dictionary::getByteListFromBits(b);
for(int r = 0; r < 4; r++) {
cv::Mat tmp1(1, flipBytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, bytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < bytes.cols; ++i) {
rot0[i] = flipBytes.ptr()[i];
rot1[i] = bytes.ptr()[bytes.cols*r + i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if(currentHamming < minHamming) minHamming = currentHamming;
}
return cvRound(minHamming);
}
static inline int getFlipDistanceToId(const aruco::Dictionary& dict, InputArray bits, int id, bool allRotations = true) {
Mat bytesList = dict.bytesList;
CV_Assert(id >= 0 && id < bytesList.rows);
unsigned int nRotations = 4;
if(!allRotations) nRotations = 1;
Mat candidateBytes = aruco::Dictionary::getByteListFromBits(bits.getMat());
double currentMinDistance = int(bits.total() * bits.total());
for(unsigned int r = 0; r < nRotations; r++) {
cv::Mat tmp1(1, candidateBytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, candidateBytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < candidateBytes.cols; ++i) {
rot0[i] = bytesList.ptr(id)[r*candidateBytes.cols + i];
rot1[i] = candidateBytes.ptr()[i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if(currentHamming < currentMinDistance) {
currentMinDistance = currentHamming;
}
}
Mat b;
flip(bits.getMat(), b, 0);
candidateBytes = aruco::Dictionary::getByteListFromBits(b);
for(unsigned int r = 0; r < nRotations; r++) {
cv::Mat tmp1(1, candidateBytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, candidateBytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < candidateBytes.cols; ++i) {
rot0[i] = bytesList.ptr(id)[r*candidateBytes.cols + i];
rot1[i] = candidateBytes.ptr()[i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if (currentHamming < currentMinDistance) {
currentMinDistance = currentHamming;
}
}
flip(bits.getMat(), b, 1);
candidateBytes = aruco::Dictionary::getByteListFromBits(b);
for(unsigned int r = 0; r < nRotations; r++) {
cv::Mat tmp1(1, candidateBytes.cols, CV_8UC1, Scalar::all(0));
cv::Mat tmp2(1, candidateBytes.cols, CV_8UC1, Scalar::all(0));
uchar* rot0 = tmp1.ptr();
uchar* rot1 = tmp2.ptr();
for (int i = 0; i < candidateBytes.cols; ++i) {
rot0[i] = bytesList.ptr(id)[r*candidateBytes.cols + i];
rot1[i] = candidateBytes.ptr()[i];
}
double currentHamming = cv::norm(tmp1, tmp2, cv::NORM_HAMMING);
if (currentHamming < currentMinDistance) {
currentMinDistance = currentHamming;
}
}
return cvRound(currentMinDistance);
}
static inline aruco::Dictionary generateCustomAsymmetricDictionary(int nMarkers, int markerSize,
const aruco::Dictionary &baseDictionary,
int randomSeed) {
RNG rng((uint64)(randomSeed));
aruco::Dictionary out;
out.markerSize = markerSize;
// theoretical maximum intermarker distance
// See S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014.
// "Automatic generation and detection of highly reliable fiducial markers under occlusion".
// Pattern Recogn. 47, 6 (June 2014), 2280-2292. DOI=10.1016/j.patcog.2014.01.005
int C = (int)std::floor(float(markerSize * markerSize) / 4.f);
int tau = 2 * (int)std::floor(float(C) * 4.f / 3.f);
// if baseDictionary is provided, calculate its intermarker distance
if(baseDictionary.bytesList.rows > 0) {
CV_Assert(baseDictionary.markerSize == markerSize);
out.bytesList = baseDictionary.bytesList.clone();
int minDistance = markerSize * markerSize + 1;
for(int i = 0; i < out.bytesList.rows; i++) {
Mat markerBytes = out.bytesList.rowRange(i, i + 1);
Mat markerBits = aruco::Dictionary::getBitsFromByteList(markerBytes, markerSize);
minDistance = min(minDistance, _getSelfDistance(markerBits));
for(int j = i + 1; j < out.bytesList.rows; j++) {
minDistance = min(minDistance, getFlipDistanceToId(out, markerBits, j));
}
}
tau = minDistance;
}
// current best option
int bestTau = 0;
Mat bestMarker;
// after these number of unproductive iterations, the best option is accepted
const int maxUnproductiveIterations = 5000;
int unproductiveIterations = 0;
while(out.bytesList.rows < nMarkers) {
Mat currentMarker(markerSize, markerSize, CV_8UC1, Scalar::all(0));
rng.fill(currentMarker, RNG::UNIFORM, 0, 2);
int selfDistance = _getSelfDistance(currentMarker);
int minDistance = selfDistance;
// if self distance is better or equal than current best option, calculate distance
// to previous accepted markers
if(selfDistance >= bestTau) {
for(int i = 0; i < out.bytesList.rows; i++) {
int currentDistance = getFlipDistanceToId(out, currentMarker, i);
minDistance = min(currentDistance, minDistance);
if(minDistance <= bestTau) {
break;
}
}
}
// if distance is high enough, accept the marker
if(minDistance >= tau) {
unproductiveIterations = 0;
bestTau = 0;
Mat bytes = aruco::Dictionary::getByteListFromBits(currentMarker);
out.bytesList.push_back(bytes);
} else {
unproductiveIterations++;
// if distance is not enough, but is better than the current best option
if(minDistance > bestTau) {
bestTau = minDistance;
bestMarker = currentMarker;
}
// if number of unproductive iterarions has been reached, accept the current best option
if(unproductiveIterations == maxUnproductiveIterations) {
unproductiveIterations = 0;
tau = bestTau;
bestTau = 0;
Mat bytes = aruco::Dictionary::getByteListFromBits(bestMarker);
out.bytesList.push_back(bytes);
}
}
}
// update the maximum number of correction bits for the generated dictionary
out.maxCorrectionBits = (tau - 1) / 2;
return out;
}
static inline int getMinDistForDict(const aruco::Dictionary& dict) {
const int dict_size = dict.bytesList.rows;
const int marker_size = dict.markerSize;
int minDist = marker_size * marker_size;
for (int i = 0; i < dict_size; i++) {
Mat row = dict.bytesList.row(i);
Mat marker = dict.getBitsFromByteList(row, marker_size);
for (int j = 0; j < dict_size; j++) {
if (j != i) {
minDist = min(dict.getDistanceToId(marker, j), minDist);
}
}
}
return minDist;
}
static inline int getMinAsymDistForDict(const aruco::Dictionary& dict) {
const int dict_size = dict.bytesList.rows;
const int marker_size = dict.markerSize;
int minDist = marker_size * marker_size;
for (int i = 0; i < dict_size; i++)
{
Mat row = dict.bytesList.row(i);
Mat marker = dict.getBitsFromByteList(row, marker_size);
for (int j = 0; j < dict_size; j++)
{
if (j != i)
{
minDist = min(getFlipDistanceToId(dict, marker, j), minDist);
}
}
}
return minDist;
}
const char* keys =
"{@outfile |<none> | Output file with custom dict }"
"{r | false | Calculate the metric considering flipped markers }"
"{d | | Dictionary Name: DICT_4X4_50, DICT_4X4_100, DICT_4X4_250,"
"DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, "
"DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50,"
"DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL,"
"DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10,"
"DICT_APRILTAG_36h11, DICT_ARUCO_MIP_36h12}"
"{nMarkers | | Number of markers in the dictionary }"
"{markerSize | | Marker size }"
"{cd | | Input file with custom dictionary }";
const char* about =
"This program can be used to calculate the ArUco dictionary metric.\n"
"To calculate the metric considering flipped markers use -'r' flag.\n"
"This program can be used to create and write the custom ArUco dictionary.\n";
int main(int argc, char *argv[])
{
CommandLineParser parser(argc, argv, keys);
parser.about(about);
if(argc < 2) {
parser.printMessage();
return 0;
}
string outputFile = parser.get<String>(0);
int nMarkers = parser.get<int>("nMarkers");
int markerSize = parser.get<int>("markerSize");
bool checkFlippedMarkers = parser.get<bool>("r");
aruco::Dictionary dictionary = aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50);
if (parser.has("d")) {
string arucoDictName = parser.get<string>("d");
cv::aruco::PredefinedDictionaryType arucoDict;
if (arucoDictName == "DICT_4X4_50") { arucoDict = cv::aruco::DICT_4X4_50; }
else if (arucoDictName == "DICT_4X4_100") { arucoDict = cv::aruco::DICT_4X4_100; }
else if (arucoDictName == "DICT_4X4_250") { arucoDict = cv::aruco::DICT_4X4_250; }
else if (arucoDictName == "DICT_4X4_1000") { arucoDict = cv::aruco::DICT_4X4_1000; }
else if (arucoDictName == "DICT_5X5_50") { arucoDict = cv::aruco::DICT_5X5_50; }
else if (arucoDictName == "DICT_5X5_100") { arucoDict = cv::aruco::DICT_5X5_100; }
else if (arucoDictName == "DICT_5X5_250") { arucoDict = cv::aruco::DICT_5X5_250; }
else if (arucoDictName == "DICT_5X5_1000") { arucoDict = cv::aruco::DICT_5X5_1000; }
else if (arucoDictName == "DICT_6X6_50") { arucoDict = cv::aruco::DICT_6X6_50; }
else if (arucoDictName == "DICT_6X6_100") { arucoDict = cv::aruco::DICT_6X6_100; }
else if (arucoDictName == "DICT_6X6_250") { arucoDict = cv::aruco::DICT_6X6_250; }
else if (arucoDictName == "DICT_6X6_1000") { arucoDict = cv::aruco::DICT_6X6_1000; }
else if (arucoDictName == "DICT_7X7_50") { arucoDict = cv::aruco::DICT_7X7_50; }
else if (arucoDictName == "DICT_7X7_100") { arucoDict = cv::aruco::DICT_7X7_100; }
else if (arucoDictName == "DICT_7X7_250") { arucoDict = cv::aruco::DICT_7X7_250; }
else if (arucoDictName == "DICT_7X7_1000") { arucoDict = cv::aruco::DICT_7X7_1000; }
else if (arucoDictName == "DICT_ARUCO_ORIGINAL") { arucoDict = cv::aruco::DICT_ARUCO_ORIGINAL; }
else if (arucoDictName == "DICT_APRILTAG_16h5") { arucoDict = cv::aruco::DICT_APRILTAG_16h5; }
else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; }
else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; }
else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; }
else if (arucoDictName == "DICT_ARUCO_MIP_36h12") { arucoDict = cv::aruco::DICT_ARUCO_MIP_36h12; }
else {
cout << "incorrect name of aruco dictionary \n";
return 1;
}
dictionary = aruco::getPredefinedDictionary(arucoDict);
}
else if (parser.has("cd")) {
FileStorage fs(parser.get<std::string>("cd"), FileStorage::READ);
bool readOk = dictionary.readDictionary(fs.root());
if(!readOk) {
cerr << "Invalid dictionary file" << endl;
return 0;
}
}
else if (outputFile.empty() || nMarkers == 0 || markerSize == 0) {
cerr << "Dictionary not specified" << endl;
return 0;
}
if (!outputFile.empty() && nMarkers > 0 && markerSize > 0)
{
FileStorage fs(outputFile, FileStorage::WRITE);
if (checkFlippedMarkers)
dictionary = generateCustomAsymmetricDictionary(nMarkers, markerSize, dictionary, 0);
else
dictionary = aruco::extendDictionary(nMarkers, markerSize, dictionary, 0);
dictionary.writeDictionary(fs);
}
if (checkFlippedMarkers) {
cout << "Hamming distance: " << getMinAsymDistForDict(dictionary) << endl;
}
else {
cout << "Hamming distance: " << getMinDistForDict(dictionary) << endl;
}
return 0;
}
+207
View File
@@ -0,0 +1,207 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/features.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/geometry/3d.hpp>
#include <iostream>
#include <iomanip>
#ifdef HAVE_OPENCV_XFEATURES2D
#include "opencv2/xfeatures2d.hpp"
#endif
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|orb|}"
"{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")
{
#ifdef HAVE_OPENCV_XFEATURES2D
backend = xfeatures2d::BRISK::create();
if (useFlann)
matcher = makePtr<FlannBasedMatcher>(makePtr<flann::LshIndexParams>(6, 12, 1));
else
matcher = DescriptorMatcher::create("BruteForce-Hamming");
#else
cout << "OpenCV is built without opencv_contrib modules. BRISK algorithm is not available!" << std::endl;
return -1;
#endif
}
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;
}
File diff suppressed because it is too large Load Diff
+221
View File
@@ -0,0 +1,221 @@
#include <iostream>
#include "opencv2/objdetect.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
static const Scalar greenColor(0, 255, 0);
static const Scalar redColor(0, 0, 255);
static const Scalar yellowColor(0, 255, 255);
static Scalar randColor()
{
RNG &rng = theRNG();
return Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
}
//==============================================================================
struct TheApp
{
Ptr<barcode::BarcodeDetector> bardet;
//! [output]
vector<Point> corners;
vector<string> decode_info;
vector<string> decode_type;
//! [output]
bool detectOnly;
void cleanup()
{
corners.clear();
decode_info.clear();
decode_type.clear();
}
inline string modeString() const
{
return detectOnly ? "<detect>" : "<detectAndDecode>";
}
void drawResults(Mat &frame) const
{
//! [visualize]
for (size_t i = 0; i < corners.size(); i += 4)
{
const size_t idx = i / 4;
const bool isDecodable = idx < decode_info.size()
&& idx < decode_type.size()
&& !decode_type[idx].empty();
const Scalar lineColor = isDecodable ? greenColor : redColor;
// draw barcode rectangle
vector<Point> contour(corners.begin() + i, corners.begin() + i + 4);
const vector< vector<Point> > contours {contour};
drawContours(frame, contours, 0, lineColor, 1);
// draw vertices
for (size_t j = 0; j < 4; j++)
circle(frame, contour[j], 2, randColor(), -1);
// write decoded text
if (isDecodable)
{
ostringstream buf;
buf << "[" << decode_type[idx] << "] " << decode_info[idx];
putText(frame, buf.str(), contour[1], FONT_HERSHEY_COMPLEX, 0.8, yellowColor, 1);
}
}
//! [visualize]
}
void drawFPS(Mat &frame, double fps) const
{
ostringstream buf;
buf << modeString()
<< " (" << corners.size() / 4 << "/" << decode_type.size() << "/" << decode_info.size() << ") "
<< cv::format("%.2f", fps) << " FPS ";
putText(frame, buf.str(), Point(25, 25), FONT_HERSHEY_COMPLEX, 0.8, redColor, 2);
}
inline void call_decode(Mat &frame)
{
cleanup();
if (detectOnly)
{
//! [detect]
bardet->detectMulti(frame, corners);
//! [detect]
}
else
{
//! [detectAndDecode]
bardet->detectAndDecodeWithType(frame, decode_info, decode_type, corners);
//! [detectAndDecode]
}
}
int liveBarCodeDetect()
{
VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "Cannot open a camera" << endl;
return 2;
}
Mat frame;
Mat result;
cap >> frame;
cout << "Image size: " << frame.size() << endl;
cout << "Press 'd' to switch between <detect> and <detectAndDecode> modes" << endl;
cout << "Press 'ESC' to exit" << endl;
for (;;)
{
cap >> frame;
if (frame.empty())
{
cout << "End of video stream" << endl;
break;
}
if (frame.channels() == 1)
cvtColor(frame, frame, COLOR_GRAY2BGR);
TickMeter timer;
timer.start();
call_decode(frame);
timer.stop();
drawResults(frame);
drawFPS(frame, timer.getFPS());
imshow("barcode", frame);
const char c = (char)waitKey(1);
if (c == 'd')
{
detectOnly = !detectOnly;
cout << "Mode switched to " << modeString() << endl;
}
else if (c == 27)
{
cout << "'ESC' is pressed. Exiting..." << endl;
break;
}
}
return 0;
}
int imageBarCodeDetect(const string &in_file, const string &out_file)
{
Mat frame = imread(in_file, IMREAD_COLOR);
cout << "Image size: " << frame.size() << endl;
cout << "Mode is " << modeString() << endl;
const int count_experiments = 100;
TickMeter timer;
for (size_t i = 0; i < count_experiments; i++)
{
timer.start();
call_decode(frame);
timer.stop();
}
cout << "FPS: " << timer.getFPS() << endl;
drawResults(frame);
if (!out_file.empty())
{
cout << "Saving result: " << out_file << endl;
imwrite(out_file, frame);
}
imshow("barcode", frame);
cout << "Press any key to exit ..." << endl;
waitKey(0);
return 0;
}
};
//==============================================================================
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 1D barcode only (skip decoding) }"
"{o out | | path to result file (only for single image decode) }"
"{sr_model | | optional super resolution ONNX model path (e.g. sr.onnx) }";
CommandLineParser cmd_parser(argc, argv, keys);
cmd_parser.about("This program detects the 1D barcodes from camera or images using the OpenCV library.");
if (cmd_parser.has("help"))
{
cmd_parser.printMessage();
return 0;
}
const string in_file = cmd_parser.get<string>("in");
const string out_file = cmd_parser.get<string>("out");
const string sr_model = cmd_parser.get<string>("sr_model");
if (!cmd_parser.check())
{
cmd_parser.printErrors();
return -1;
}
TheApp app;
app.detectOnly = cmd_parser.has("detect") && cmd_parser.get<bool>("detect");
//! [initialize]
try
{
app.bardet = makePtr<barcode::BarcodeDetector>(sr_model);
}
catch (const std::exception& e)
{
cout <<
"\n---------------------------------------------------------------\n"
"Failed to initialize super resolution.\n"
"Please, download 'sr.onnx' from\n"
"https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
"and put it into the current directory.\n"
"Or you can leave sr_model unspecified.\n"
"---------------------------------------------------------------\n";
cout << e.what() << endl;
return -1;
}
//! [initialize]
if (in_file.empty())
return app.liveBarCodeDetect();
else
return app.imageBarCodeDetect(in_file, out_file);
}
+124
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;
}
+754
View File
@@ -0,0 +1,754 @@
#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/geometry.hpp"
#include "opencv2/calib.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/objdetect.hpp"
#include "opencv2/objdetect/charuco_detector.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 calibration board horizontal size in inner corners "
"for chessboard and in squares or circles for others like ChArUco or circles grid\n"
" -h=<board_height> # the calibration board verical size in inner corners "
"for chessboard and in squares or circles for others like ChArUco or circles grid\n"
" [-pt=<pattern>] # the type of pattern: chessboard, charuco, circles, acircles\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"
" [-ms=<markerSize>] # marker size in some user-defined units (0.5 by default)\n"
" [-ad=<arucoDict>] # Aruco dictionary name for ChArUco board. "
"Available ArUco dictionaries: DICT_4X4_50, DICT_4X4_100, DICT_4X4_250, "
"DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, "
"DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, "
"DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, "
"DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11, DICT_ARUCO_MIP_36h12\n"
" [-adf=<dictFilename>] # Custom aruco dictionary file for ChArUco board\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"
" [-fx=<X focal length>] # focal length in X-dir as an initial intrinsic guess (if this flag is used, fx, fy, cx, cy must be set)\n"
" [-fy=<Y focal length>] # focal length in Y-dir as an initial intrinsic guess (if this flag is used, fx, fy, cx, cy must be set)\n"
" [-cx=<X center point>] # camera center point in X-dir as an initial intrinsic guess (if this flag is used, fx, fy, cx, cy must be set)\n"
" [-cy=<Y center point>] # camera center point in Y-dir as an initial intrinsic guess (if this flag is used, fx, fy, cx, cy must be set)\n"
" [-imshow-scale # image resize scaling factor when displaying the results (must be >= 1)\n"
" [-enable-k3=<0/1> # to enable (1) or disable (0) K3 coefficient for the distortion model\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"
" [-imread-apply-exif-rot] # use this flag to apply the exif orientation when reading images from list\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, CHARUCOBOARD};
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;
case CHARUCOBOARD:
for( int i = 0; i < boardSize.height-1; i++ )
for( int j = 0; j < boardSize.width-1; j++ )
corners.push_back(Point3f(float(j*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)
{
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);
// Board imperfectness correction introduced in PR #12772
// The correction does not make sense for asymmetric and assymetric circles grids
if (patternType == CHESSBOARD)
{
int offset = boardSize.width - 1;
objectPoints[0][offset].x = objectPoints[0][0].x + grid_width;
}
else if (patternType == CHARUCOBOARD)
{
int offset = boardSize.width - 2;
objectPoints[0][offset].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_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 )
{
snprintf( buf, sizeof(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, markerSize, aspectRatio = 1;
Mat cameraMatrix, distCoeffs;
string outputFilename;
string inputFilename = "";
int arucoDict;
string dictFilename;
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|}{ms|0.5|}{ad|DICT_4X4_50|}{adf|None|}{o|out_camera_data.yml|}"
"{op||}{oe||}{zt||}{a||}{p||}{v||}{V||}{su||}"
"{oo||}{ws|11|}{dt||}"
"{fx||}{fy||}{cx||}{cy||}"
"{imshow-scale|1|}{enable-k3|0|}"
"{imread-apply-exif-rot||}"
"{@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 if( val == "charuco" )
pattern = CHARUCOBOARD;
else
return fprintf( stderr, "Invalid pattern type: must be chessboard or circles\n" ), -1;
}
squareSize = parser.get<float>("s");
markerSize = parser.get<float>("ms");
string arucoDictName = parser.get<string>("ad");
if (arucoDictName == "DICT_4X4_50") { arucoDict = cv::aruco::DICT_4X4_50; }
else if (arucoDictName == "DICT_4X4_100") { arucoDict = cv::aruco::DICT_4X4_100; }
else if (arucoDictName == "DICT_4X4_250") { arucoDict = cv::aruco::DICT_4X4_250; }
else if (arucoDictName == "DICT_4X4_1000") { arucoDict = cv::aruco::DICT_4X4_1000; }
else if (arucoDictName == "DICT_5X5_50") { arucoDict = cv::aruco::DICT_5X5_50; }
else if (arucoDictName == "DICT_5X5_100") { arucoDict = cv::aruco::DICT_5X5_100; }
else if (arucoDictName == "DICT_5X5_250") { arucoDict = cv::aruco::DICT_5X5_250; }
else if (arucoDictName == "DICT_5X5_1000") { arucoDict = cv::aruco::DICT_5X5_1000; }
else if (arucoDictName == "DICT_6X6_50") { arucoDict = cv::aruco::DICT_6X6_50; }
else if (arucoDictName == "DICT_6X6_100") { arucoDict = cv::aruco::DICT_6X6_100; }
else if (arucoDictName == "DICT_6X6_250") { arucoDict = cv::aruco::DICT_6X6_250; }
else if (arucoDictName == "DICT_6X6_1000") { arucoDict = cv::aruco::DICT_6X6_1000; }
else if (arucoDictName == "DICT_7X7_50") { arucoDict = cv::aruco::DICT_7X7_50; }
else if (arucoDictName == "DICT_7X7_100") { arucoDict = cv::aruco::DICT_7X7_100; }
else if (arucoDictName == "DICT_7X7_250") { arucoDict = cv::aruco::DICT_7X7_250; }
else if (arucoDictName == "DICT_7X7_1000") { arucoDict = cv::aruco::DICT_7X7_1000; }
else if (arucoDictName == "DICT_ARUCO_ORIGINAL") { arucoDict = cv::aruco::DICT_ARUCO_ORIGINAL; }
else if (arucoDictName == "DICT_APRILTAG_16h5") { arucoDict = cv::aruco::DICT_APRILTAG_16h5; }
else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; }
else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; }
else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; }
else if (arucoDictName == "DICT_ARUCO_MIP_36h12") { arucoDict = cv::aruco::DICT_ARUCO_MIP_36h12; }
else {
cout << "Incorrect Aruco dictionary name " << arucoDictName << std::endl;
return 1;
}
dictFilename = parser.get<std::string>("adf");
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");
cameraMatrix = Mat::eye(3, 3, CV_64F);
if (parser.has("fx") && parser.has("fy") && parser.has("cx") && parser.has("cy"))
{
cameraMatrix.at<double>(0,0) = parser.get<double>("fx");
cameraMatrix.at<double>(0,2) = parser.get<double>("cx");
cameraMatrix.at<double>(1,1) = parser.get<double>("fy");
cameraMatrix.at<double>(1,2) = parser.get<double>("cy");
flags |= CALIB_USE_INTRINSIC_GUESS;
std::cout << "Use the following camera matrix as an initial guess:\n" << cameraMatrix << std::endl;
}
int viewScaleFactor = parser.get<int>("imshow-scale");
bool useK3 = parser.get<bool>("enable-k3");
std::cout << "Use K3 distortion coefficient? " << (useK3 ? "yes" : "no") << std::endl;
if (!useK3)
{
flags |= CALIB_FIX_K3;
}
int imread_flag = IMREAD_COLOR;
if (!parser.has("imread-apply-exif-rot"))
{
imread_flag |= IMREAD_IGNORE_ORIENTATION;
}
float grid_width = squareSize *(pattern != CHARUCOBOARD ? (boardSize.width - 1): (boardSize.width - 2) );
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;
cv::aruco::Dictionary dictionary;
if (pattern == CHARUCOBOARD) {
if (dictFilename == "None") {
std::cout << "Using predefined dictionary with id: " << arucoDict << std::endl;
dictionary = aruco::getPredefinedDictionary(arucoDict);
}
else {
std::cout << "Using custom dictionary from file: " << dictFilename << std::endl;
cv::FileStorage dict_file(dictFilename, cv::FileStorage::Mode::READ);
cv::FileNode fn(dict_file.root());
dictionary.readDictionary(fn);
}
}
cv::Ptr<cv::aruco::CharucoBoard> ch_board;
std::vector<int> markerIds;
cv::Ptr<cv::aruco::CharucoDetector> ch_detector;
if (pattern == CHARUCOBOARD) {
ch_board = cv::makePtr<cv::aruco::CharucoBoard>(boardSize, squareSize, markerSize, dictionary);
ch_detector = cv::makePtr<cv::aruco::CharucoDetector>(cv::aruco::CharucoDetector(*ch_board));
}
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", cv::WINDOW_AUTOSIZE );
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], imread_flag);
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;
case CHARUCOBOARD:
{
ch_detector->detectBoard(view, pointbuf, markerIds);
found = pointbuf.size() == (size_t)(boardSize.width-1)*(boardSize.height-1);
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)
{
if(pattern != CHARUCOBOARD)
drawChessboardCorners( view, boardSize, Mat(pointbuf), found );
else
drawChessboardCorners( view, Size(boardSize.width-1, boardSize.height-1), 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);
}
if (viewScaleFactor > 1)
{
Mat viewScale;
resize(view, viewScale, Size(), 1.0/viewScaleFactor, 1.0/viewScaleFactor, INTER_AREA);
imshow("Image View", viewScale);
}
else
{
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], imread_flag);
if(view.empty())
continue;
remap(view, rview, map1, map2, INTER_LINEAR);
if (viewScaleFactor > 1)
{
Mat rviewScale;
resize(rview, rviewScale, Size(), 1.0/viewScaleFactor, 1.0/viewScaleFactor, INTER_AREA);
imshow("Image View", rviewScale);
}
else
{
imshow("Image View", rview);
}
char c = (char)waitKey();
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
}
return 0;
}
+224
View File
@@ -0,0 +1,224 @@
//! [tutorial]
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/photo.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include "../dnn/common.hpp"
using namespace std;
using namespace cv;
using namespace cv::dnn;
using namespace cv::ccm;
using namespace mcc;
const string about =
"This sample detects Macbeth color checker using DNN or thresholding and applies color correction."
"To run default:\n"
"\t ./example_cpp_color_correction_model --input=path/to/your/input/image --query=path/to/your/query/image\n"
"With DNN model:\n"
"\t ./example_cpp_color_correction_model mcc --input=path/to/your/input/image --query=path/to/your/query/image\n\n"
"Using pre-computed CCM:\n"
"\t ./example_cpp_color_correction_model mcc --ccm_file=path/to/ccm_output.yaml --query=path/to/your/query/image\n\n"
"Model path can also be specified using --model argument. And config path can be specified using --config. Download it using python download_models.py mcc from dnn samples directory\n\n";
const string param_keys =
"{ help h | | Print help message. }"
"{ @alias | | An alias name of model to extract preprocessing parameters from models.yml file. }"
"{ zoo | ../dnn/models.yml | An optional path to file with preprocessing parameters }"
"{ input i | mcc_ccm_test.jpg | Path to input image for computing CCM.}"
"{ query q | baboon.jpg | Path to query image to apply color correction. If not provided, input image will be used. }"
"{ type | 0 | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl }"
"{ num_charts | 1 | Maximum number of charts in the image }"
"{ ccm_file | | Path to YAML file containing pre-computed CCM parameters}";
const string backend_keys = format(
"{ backend | default | Choose one of computation backends: "
"default: automatically (by default), "
"openvino: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), "
"opencv: OpenCV implementation, "
"vkcom: VKCOM, "
"cuda: CUDA, "
"webnn: WebNN }");
const string target_keys = format(
"{ target | cpu | Choose one of target computation devices: "
"cpu: CPU target (by default), "
"opencl: OpenCL, "
"opencl_fp16: OpenCL fp16 (half-float precision), "
"vpu: VPU, "
"vulkan: Vulkan, "
"cuda: CUDA, "
"cuda_fp16: CUDA fp16 (half-float preprocess) }");
string keys = param_keys + backend_keys + target_keys;
static bool processFrame(const Mat& frame, Ptr<CCheckerDetector> detector, Mat& src, int nc){
if (!detector->process(frame, nc))
{
return false;
}
vector<Ptr<CChecker>> checkers = detector->getListColorChecker();
src = checkers[0]->getChartsRGB(false);
return true;
}
int main(int argc, char* argv[]) {
CommandLineParser parser(argc, argv, keys);
parser.about(about);
if (parser.has("help")) {
cout << about << endl;
parser.printMessage();
return 0;
}
string modelName = parser.get<String>("@alias");
string zooFile = parser.get<String>("zoo");
const char* path = getenv("OPENCV_SAMPLES_DATA_PATH");
if ((path != NULL) || parser.has("@alias")) {
zooFile = findFile(zooFile);
}
else{
cout<<"[WARN] set the environment variables or pass the arguments --model, --config and models.yml file using --zoo for using dnn based detector. Continuing with default detector.\n\n";
}
keys += genPreprocArguments(modelName, zooFile);
parser = CommandLineParser(argc, argv, keys);
int t = parser.get<int>("type");
if (t < 0 || t > 2)
{
cout << "Error: --type must be 0, 1 or 2" << endl;
parser.printMessage(); // prints full usage
return -1;
}
ColorChart chartType = ColorChart(t);
const string sha1 = parser.get<String>("sha1");
const string modelPath = findModel(parser.get<string>("model"), sha1);
const string config_sha1 = parser.get<String>("config_sha1");
const string configPath = findModel(parser.get<string>("config"), config_sha1);
const string backend = parser.get<String>("backend");
const string target = parser.get<String>("target");
int nc = parser.get<int>("num_charts");
// Get input and target image paths
const string inputFile = parser.get<String>("input");
const string queryFile = parser.get<String>("query");
const string ccmFile = parser.get<String>("ccm_file");
if (!ccmFile.empty()) {
// When ccm_file is provided, only query is required
if (queryFile.empty()) {
cout << "Error: Query image path must be provided when using pre-computed CCM." << endl;
parser.printMessage();
return -1;
}
} else {
// Original validation for when computing new CCM
if (inputFile.empty()) {
cout << "Error: Input image path must be provided." << endl;
parser.printMessage();
return -1;
}
}
ColorCorrectionModel model;
Mat queryImage;
if (!ccmFile.empty()) {
// Load CCM from YAML file
FileStorage fs(ccmFile, FileStorage::READ);
if (!fs.isOpened()) {
cout << "Error: Unable to open CCM file: " << ccmFile << endl;
return -1;
}
model.read(fs["ColorCorrectionModel"]);
fs.release();
cout << "Loaded CCM from file: " << ccmFile << endl;
// Read query image when using pre-computed CCM
queryImage = imread(findFile(queryFile));
if (queryImage.empty()) {
cout << "Error: Unable to read query image." << endl;
return -1;
}
} else {
// Read input image for computing new CCM
Mat originalImage = imread(findFile(inputFile));
if (originalImage.empty()) {
cout << "Error: Unable to read input image." << endl;
return -1;
}
// Process first image to compute CCM
Mat image = originalImage.clone();
Mat src;
Ptr<CCheckerDetector> detector;
if (!modelPath.empty() && !configPath.empty()) {
Net net = readNetFromTensorflow(modelPath, configPath);
net.setPreferableBackend(getBackendID(backend));
net.setPreferableTarget(getTargetID(target));
detector = CCheckerDetector::create(net);
cout << "Using DNN-based checker detector." << endl;
} else {
detector = CCheckerDetector::create();
cout << "Using thresholding-based checker detector." << endl;
}
detector->setColorChartType(chartType);
if (!processFrame(image, detector, src, nc)) {
cout << "No chart detected in the input image!" << endl;
return -1;
}
// Convert to double and normalize
src.convertTo(src, CV_64F, 1.0/255.0);
// Color correction model
model = ColorCorrectionModel(src, COLORCHECKER_MACBETH);
model.setCcmType(CCM_LINEAR);
model.setDistance(DISTANCE_CIE2000);
model.setLinearization(LINEARIZATION_GAMMA);
model.setLinearizationGamma(2.2);
Mat ccm = model.compute();
cout << "Computed CCM Matrix:\n" << ccm << endl;
cout << "Loss: " << model.getLoss() << endl;
// Save model parameters to YAML file
FileStorage fs("ccm_output.yaml", FileStorage::WRITE);
model.write(fs);
fs.release();
cout << "Model parameters saved to ccm_output.yaml" << endl;
// Set query image for correction
if (queryFile.empty()) {
cout << "[WARN] No query image provided, applying color correction on input image" << endl;
queryImage = originalImage.clone();
} else {
queryImage = imread(findFile(queryFile));
if (queryImage.empty()) {
cout << "Error: Unable to read query image." << endl;
return -1;
}
}
}
Mat calibratedImage;
model.correctImage(queryImage, calibratedImage);
imshow("Original Image", queryImage);
imshow("Corrected Image", calibratedImage);
waitKey(0);
return 0;
}
//! [tutorial]
+61
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;
}
+69
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;
}
+154
View File
@@ -0,0 +1,154 @@
#include <opencv2/geometry/2d.hpp>
#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;
}
+94
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;
}
+537
View File
@@ -0,0 +1,537 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features.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;
}
+182
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);
}
+208
View File
@@ -0,0 +1,208 @@
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <string>
using namespace cv;
using namespace std;
void drawRandomLines(Mat& image, RNG& rng, int width, int height, int lineType);
void drawRandomRectangles(Mat& image, RNG& rng, int width, int height, int lineType);
void drawRandomEllipses(Mat& image, RNG& rng, int width, int height, int lineType);
void drawRandomPolylines(Mat& image, RNG& rng, int width, int height, int lineType);
void drawRandomFilledPolygons(Mat& image, RNG& rng, int width, int height, int lineType);
void drawRandomCircles(Mat& image, RNG& rng, int width, int height, int lineType);
void drawRandomText(Mat& image, RNG& rng, int width, int height, int lineType);
void drawAll(Mat& image, RNG& rng, int width, int height, int lineType);
// Display help message to the user
static void help() {
cout << "\nThis program demonstrates OpenCV drawing and text output functions by drawing random shapes and texts\n"
"You can change the drawing mode by pressing keys while the program is running:\n"
" 'l' : lines\n"
" 'r' : rectangles\n"
" 'e' : ellipses\n"
" 'p' : polylines\n"
" 'f' : filled polygons\n"
" 'c' : circles\n"
" 't' : text\n"
" 'a' : all shapes\n"
"Press 'ESC' to exit the program.\n";
}
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) {
if (argc == 2) {
string arg = argv[1];
if (arg == "-h" || arg == "--help") {
help();
return 0;
}
}
help();
// Initialize random number generator, image dimensions, and type
RNG rng(0xFFFFFFFF);
int width = 1000, height = 700;
int lineType = LINE_AA;
Mat image = Mat::zeros(height, width, CV_8UC3);
// Draw all shapes by default
drawAll(image, rng, width, height, lineType);
imshow("Drawing Demo", image);
int key = waitKey(0);
while (key != 27) { // 27 is the ASCII code for 'ESC'
switch (key) {
case 'l':
image = Mat::zeros(height, width, CV_8UC3);
drawRandomLines(image, rng, width, height, lineType);
break;
case 'r':
image = Mat::zeros(height, width, CV_8UC3);
drawRandomRectangles(image, rng, width, height, lineType);
break;
case 'e':
image = Mat::zeros(height, width, CV_8UC3);
drawRandomEllipses(image, rng, width, height, lineType);
break;
case 'p':
image = Mat::zeros(height, width, CV_8UC3);
drawRandomPolylines(image, rng, width, height, lineType);
break;
case 'f':
image = Mat::zeros(height, width, CV_8UC3);
drawRandomFilledPolygons(image, rng, width, height, lineType);
break;
case 'c':
image = Mat::zeros(height, width, CV_8UC3);
drawRandomCircles(image, rng, width, height, lineType);
break;
case 't':
image = Mat::zeros(height, width, CV_8UC3);
drawRandomText(image, rng, width, height, lineType);
break;
case 'a':
image = Mat::zeros(height, width, CV_8UC3);
drawAll(image, rng, width, height, lineType);
break;
}
imshow("Drawing Demo", image);
key = waitKey(0);
}
return 0;
}
// Function implementations to draw each type of shape
// Each function follows a similar pattern
void drawRandomLines(Mat& image, RNG& rng, int width, int height, int lineType) {
Point pt1, pt2;
// Draw 100 random lines
for (int i = 0; i < 100; ++i) {
pt1.x = rng.uniform(0, width);
pt1.y = rng.uniform(0, height);
pt2.x = rng.uniform(0, width);
pt2.y = rng.uniform(0, height);
// Draw a line between the random points with a random color and thickness
line(image, pt1, pt2, randomColor(rng), rng.uniform(1, 10), lineType);
}
}
void drawRandomRectangles(Mat& image, RNG& rng, int width, int height, int lineType) {
Point pt1, pt2;
// Generate random corner points
for (int i = 0; i < 100; ++i) {
pt1.x = rng.uniform(0, width);
pt1.y = rng.uniform(0, height);
pt2.x = rng.uniform(0, width);
pt2.y = rng.uniform(0, height);
// Draw a rectangle with random colors and thickness (or filled if thickness is -1). MAX changes any negative number by rng.uniform to -1
rectangle(image, pt1, pt2, randomColor(rng), MAX(rng.uniform(-1, 10), -1), lineType);
}
}
void drawRandomEllipses(Mat& image, RNG& rng, int width, int height, int lineType) {
Point center;
Size axes;
for (int i = 0; i < 50; ++i) {
center.x = rng.uniform(0, width);
center.y = rng.uniform(0, height);
axes.width = rng.uniform(0, 200);
axes.height = rng.uniform(0, 200);
double angle = rng.uniform(0.0, 360.0);
// Draw an ellipse with a random color and thickness
ellipse(image, center, axes, angle, 0, 360, randomColor(rng), rng.uniform(-1, 9), lineType);
}
}
void drawRandomPolylines(Mat& image, RNG& rng, int width, int height, int lineType) {
for (int i = 0; i < 10; ++i) {
Point points[1][5];
points[0][0] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][1] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][2] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][3] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][4] = Point(rng.uniform(0, width), rng.uniform(0, height));
const Point* ppt[1] = {points[0]};
int npt[] = {5};
polylines(image, ppt, npt, 1, true, randomColor(rng), rng.uniform(1, 10), lineType);
}
}
void drawRandomFilledPolygons(Mat& image, RNG& rng, int width, int height, int lineType) {
for (int i = 0; i < 10; ++i) {
Point points[1][5];
// Generate 5 random points for each polyline
points[0][0] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][1] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][2] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][3] = Point(rng.uniform(0, width), rng.uniform(0, height));
points[0][4] = Point(rng.uniform(0, width), rng.uniform(0, height));
const Point* ppt[1] = {points[0]};
int npt[] = {5};
// Draw the polyline with a random color and thickness
fillPoly(image, ppt, npt, 1, randomColor(rng), lineType);
}
}
void drawRandomCircles(Mat& image, RNG& rng, int width, int height, int lineType) {
Point center;
for (int i = 0; i < 100; ++i) {
// Generate a random center and radius
center.x = rng.uniform(0, width);
center.y = rng.uniform(0, height);
circle(image, center, rng.uniform(0, 300), randomColor(rng), rng.uniform(-1, 9), lineType);
}
}
void drawRandomText(Mat& image, RNG& rng, int width, int height, int lineType) {
Point org;
for (int i = 0; i < 50; ++i) {
// Generate a random position for the text
org.x = rng.uniform(0, width);
org.y = rng.uniform(0, height);
// Randomize font face, scale, and thickness
int fontFace = rng.uniform(0, 3);
double fontScale = rng.uniform(0.5, 2.0);
int thickness = rng.uniform(1, 3);
putText(image, "This is OpenCV drawing demo sample", org, fontFace, fontScale, randomColor(rng), thickness, lineType);
}
}
void drawAll(Mat& image, RNG& rng, int width, int height, int lineType) {
drawRandomLines(image, rng, width, height, lineType);
drawRandomRectangles(image, rng, width, height, lineType);
drawRandomEllipses(image, rng, width, height, lineType);
drawRandomPolylines(image, rng, width, height, lineType);
drawRandomFilledPolygons(image, rng, width, height, lineType);
drawRandomCircles(image, rng, width, height, lineType);
drawRandomText(image, rng, width, height, lineType);
}
+343
View File
@@ -0,0 +1,343 @@
// 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/geometry.hpp"
#include "opencv2/features.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, 1000/*maxIters*/, 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);
}
+26
View File
@@ -0,0 +1,26 @@
# cmake needs this line
cmake_minimum_required(VERSION 3.13)
# 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})
+12
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
+50
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
}
@@ -0,0 +1,169 @@
// 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.
// ALIKED + LightGlueMatcher usage example
// Demonstrates feature detection, extraction, and matching using ALIKED and LightGlue.
#include <opencv2/features.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// ---- Parse arguments ----
String alikedModel, lightglueModel, imgPath1, imgPath2;
if (argc >= 5)
{
imgPath1 = argv[1];
imgPath2 = argv[2];
alikedModel = argv[3];
lightglueModel = argv[4];
}
else
{
cout << "Usage: " << argv[0] << " <image1> <image2> <aliked_model> <lightglue_model>" << endl;
cout << endl;
cout << "Example:" << endl;
cout << " " << argv[0] << " img1.jpg img2.jpg aliked-n16rot-top1k-640.onnx aliked_lightglue.onnx" << endl;
return 0;
}
// ---- Load images ----
Mat img1 = imread(imgPath1);
Mat img2 = imread(imgPath2);
if (img1.empty() || img2.empty())
{
cerr << "Error: cannot load images." << endl;
return -1;
}
// ================================================================
// 1. Create ALIKED feature extractor
// ================================================================
// Method A: From ONNX model file
Ptr<ALIKED> aliked = ALIKED::create(alikedModel);
// Method B: Customize parameters
// ALIKED::Params params;
// params.inputSize = Size(640, 640); // Network input resolution
// params.normalizeDescriptors = true; // L2-normalize descriptors
// Ptr<ALIKED> aliked = ALIKED::create(alikedModel, params);
// Method C: From in-memory model data
// vector<uchar> modelData = readFile(alikedModel);
// Ptr<ALIKED> aliked = ALIKED::create(modelData);
cout << "Descriptor size: " << aliked->descriptorSize() << endl; // 128
cout << "Descriptor type: " << aliked->descriptorType() << endl; // CV_32F
cout << "Default norm: " << aliked->defaultNorm() << endl; // NORM_L2
// ================================================================
// 2. Detect keypoints and compute descriptors
// ================================================================
vector<KeyPoint> kpts1, kpts2;
Mat descs1, descs2;
// Method A: detect + compute in one call (recommended)
aliked->detectAndCompute(img1, Mat(), kpts1, descs1);
aliked->detectAndCompute(img2, Mat(), kpts2, descs2);
// Method B: detect only (no descriptors)
// vector<KeyPoint> kpts;
// aliked->detect(img, kpts);
// Method C: compute only (from existing keypoints)
// Mat descs;
// aliked->compute(img, kpts, descs);
cout << "Image 1: " << kpts1.size() << " keypoints, descriptors " << descs1.rows << "x" << descs1.cols << endl;
cout << "Image 2: " << kpts2.size() << " keypoints, descriptors " << descs2.rows << "x" << descs2.cols << endl;
// ================================================================
// 3. Create LightGlueMatcher
// ================================================================
// Method A: From ONNX model file
Ptr<LightGlueMatcher> lg = LightGlueMatcher::create(lightglueModel);
// Method B: Customize parameters
// LightGlueMatcher::Params lgParams;
// lgParams.scoreThreshold = 0.1f; // Filter low-confidence matches
// lgParams.disableWinograd = false; // Keep Winograd convolution
// Ptr<LightGlueMatcher> lg = LightGlueMatcher::create(lightglueModel, lgParams);
// Method C: From in-memory model data
// vector<uchar> lgData = readFile(lightglueModel);
// Ptr<LightGlueMatcher> lg = LightGlueMatcher::create(lgData);
// ================================================================
// 4. Set keypoint context for LightGlue
// ================================================================
// LightGlue needs keypoint coordinates + image sizes for spatial reasoning.
// Build Nx2 float matrices with pixel coordinates.
Mat kpts1Mat((int)kpts1.size(), 2, CV_32F);
Mat kpts2Mat((int)kpts2.size(), 2, CV_32F);
for (size_t i = 0; i < kpts1.size(); i++)
{
kpts1Mat.at<float>((int)i, 0) = kpts1[i].pt.x;
kpts1Mat.at<float>((int)i, 1) = kpts1[i].pt.y;
}
for (size_t i = 0; i < kpts2.size(); i++)
{
kpts2Mat.at<float>((int)i, 0) = kpts2[i].pt.x;
kpts2Mat.at<float>((int)i, 1) = kpts2[i].pt.y;
}
// setPairInfo must be called before match()/knnMatch()
lg->setPairInfo(kpts1Mat, kpts2Mat, img1.size(), img2.size());
// ================================================================
// 5. Match descriptors
// ================================================================
// Method A: 1-to-1 matching (returns best match per query keypoint)
vector<DMatch> matches;
lg->match(descs1, descs2, matches);
cout << "1-to-1 matches: " << matches.size() << endl;
// Method B: kNN matching (k=1 only for LightGlue)
// vector<vector<DMatch>> knnMatches;
// lg->knnMatch(descs1, descs2, knnMatches, 1);
// // knnMatches[i] contains matches for query keypoint i
// ================================================================
// 6. Filter matches by confidence (optional)
// ================================================================
// DMatch distance = 1.0 - confidence_score
// Lower distance = better match
vector<DMatch> goodMatches;
float distanceThreshold = 0.9f; // confidence > 0.1
for (const auto& m : matches)
{
if (m.distance < distanceThreshold)
goodMatches.push_back(m);
}
cout << "Good matches (distance < " << distanceThreshold << "): " << goodMatches.size() << endl;
// ================================================================
// 7. Visualize results
// ================================================================
Mat canvas;
cv::drawMatches(img1, kpts1, img2, kpts2, goodMatches, canvas,
Scalar::all(-1), Scalar::all(-1), vector<char>(),
DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
imshow("ALIKED + LightGlue Matches", canvas);
cout << "Press any key to exit..." << endl;
waitKey(0);
return 0;
}
+68
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;
}
+250
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/features.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;
}
+177
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;
}
+300
View File
@@ -0,0 +1,300 @@
/**
@file gauge.cpp
@author Alessandro de Oliveira Faria (A.K.A. CABELO)
@brief This sample application processes an image frame of an analog gauge
and extracts its reading using functions from the OpenCV* computer vision
library. The workflow is divided into two stages: calibration and
measurement. Questions and suggestions email to:
Alessandro de Oliveira Faria cabelo[at]opensuse[dot]org or OpenCV Team.
@date Nov 26, 2025
*/
#include "opencv2/imgproc.hpp"
#include <opencv2/highgui.hpp>
#include <iostream>
#include <vector>
#include <cmath>
#include <string>
using namespace cv;
using namespace std;
struct GaugeCalibration {
double min_angle;
double max_angle;
double min_value;
double max_value;
string units;
int x;
int y;
int r;
};
static Vec3f avg_circles(const vector<Vec3f> &circles) {
double avg_x = 0.0;
double avg_y = 0.0;
double avg_r = 0.0;
int b = static_cast<int>(circles.size());
for (int i = 0; i < b; ++i) {
avg_x += circles[i][0];
avg_y += circles[i][1];
avg_r += circles[i][2];
}
avg_x /= b;
avg_y /= b;
avg_r /= b;
return Vec3f(static_cast<float>(avg_x),
static_cast<float>(avg_y),
static_cast<float>(avg_r));
}
static double dist_2_pts(double x1, double y1, double x2, double y2) {
double dx = x2 - x1;
double dy = y2 - y1;
return std::sqrt(dx * dx + dy * dy);
}
static GaugeCalibration calibrate_gauge(string filename) {
GaugeCalibration cal;
Mat img = imread(filename);
if (img.empty()) {
cerr << "Error loading image: " << filename << endl;
exit(1);
}
int height = img.rows;
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
// Detects circles (HoughCircles)
vector<Vec3f> circles;
HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
20,
100, 50,
static_cast<int>(height * 0.35),
static_cast<int>(height * 0.48));
if (circles.empty()) {
cerr << "No circles found." << endl;
exit(1);
}
Vec3f avg = avg_circles(circles);
int x = static_cast<int>(avg[0]);
int y = static_cast<int>(avg[1]);
int r = static_cast<int>(avg[2]);
cal.x = x;
cal.y = y;
cal.r = r;
// Draw the circle and the center.
circle(img, Point(x, y), r, Scalar(0, 0, 255), 3, LINE_AA);
circle(img, Point(x, y), 2, Scalar(0, 255, 0), 3, LINE_AA);
// Generation of calibration lines.
double separation = 10.0; // in degrees
int interval = static_cast<int>(360.0 / separation);
vector<Point2d> p1(interval);
vector<Point2d> p2(interval);
vector<Point2d> p_text(interval);
for (int i = 0; i < interval; ++i) {
double angle_rad = separation * i * CV_PI / 180.0;
p1[i].x = x + 0.9 * r * std::cos(angle_rad);
p1[i].y = y + 0.9 * r * std::sin(angle_rad);
}
int text_offset_x = 10;
int text_offset_y = 5;
for (int i = 0; i < interval; ++i) {
double angle_rad = separation * i * CV_PI / 180.0;
p2[i].x = x + r * std::cos(angle_rad);
p2[i].y = y + r * std::sin(angle_rad);
double text_angle_rad = separation * (i + 9) * CV_PI / 180.0; // i+9 = rotate 90°
p_text[i].x = x - text_offset_x + 1.2 * r * std::cos(text_angle_rad);
p_text[i].y = y + text_offset_y + 1.2 * r * std::sin(text_angle_rad);
}
// Draws lines and text.
for (int i = 0; i < interval; ++i) {
line(img,
Point(static_cast<int>(p1[i].x), static_cast<int>(p1[i].y)),
Point(static_cast<int>(p2[i].x), static_cast<int>(p2[i].y)),
Scalar(0, 255, 0), 2);
putText(img,
to_string(static_cast<int>(i * separation)),
Point(static_cast<int>(p_text[i].x), static_cast<int>(p_text[i].y)),
FONT_HERSHEY_SIMPLEX, 0.3, Scalar(0, 0, 0), 1, LINE_AA);
}
// Save calibration image
imwrite("gauge-calibration.jpg", img);
cout << "Min angle (lowest possible angle of dial) - in degrees: ";
cin >> cal.min_angle;
cout << "Max angle (highest possible angle) - in degrees: ";
cin >> cal.max_angle;
cout << "Min value: ";
cin >> cal.min_value;
cout << "Max value: ";
cin >> cal.max_value;
cout << "Enter units: ";
cin >> cal.units;
return cal;
}
static double get_current_value(Mat img,
const GaugeCalibration &cal) {
Mat gray2;
cvtColor(img, gray2, COLOR_BGR2GRAY);
int thresh = 175;
int maxValue = 255;
Mat dst2;
threshold(gray2, dst2, thresh, maxValue, THRESH_BINARY_INV);
// For debugging: threshold image
//imwrite("gauge-tempdst2.jpg", dst2);
// Detect lines
vector<Vec4i> lines;
int minLineLength = 10;
int maxLineGap = 0;
HoughLinesP(dst2, lines, 3, CV_PI / 180, 100, minLineLength, maxLineGap);
if (lines.empty()) {
cerr << "No rows found." << endl;
return 0.0;
}
// Filter lines by distance from center
vector<Vec4i> final_line_list;
double diff1LowerBound = 0.15;
double diff1UpperBound = 0.25;
double diff2LowerBound = 0.5;
double diff2UpperBound = 1.0;
int x = cal.x;
int y = cal.y;
int r = cal.r;
for (size_t i = 0; i < lines.size(); ++i) {
int x1 = lines[i][0];
int y1 = lines[i][1];
int x2 = lines[i][2];
int y2 = lines[i][3];
double diff1 = dist_2_pts(x, y, x1, y1);
double diff2 = dist_2_pts(x, y, x2, y2);
// ensures that diff1 is the smallest (closest to the center)
if (diff1 > diff2) {
std::swap(diff1, diff2);
}
if ((diff1 < diff1UpperBound * r) && (diff1 > diff1LowerBound * r) &&
(diff2 < diff2UpperBound * r) && (diff2 > diff2LowerBound * r)) {
final_line_list.push_back(lines[i]);
}
}
if (final_line_list.empty()) {
cerr << "No lines within the expected radius." << endl;
return 0.0;
}
// Use the first filtered line.
int x1 = final_line_list[0][0];
int y1 = final_line_list[0][1];
int x2 = final_line_list[0][2];
int y2 = final_line_list[0][3];
// Draw the line on the original image for debugging.
line(img, Point(x1, y1), Point(x2, y2), Scalar(0, 255, 0), 2);
//imwrite("gauge-lines-2.jpg", img);
// Decide which point is furthest from the center.
double dist_pt_0 = dist_2_pts(x, y, x1, y1);
double dist_pt_1 = dist_2_pts(x, y, x2, y2);
double x_angle, y_angle;
if (dist_pt_0 > dist_pt_1) {
x_angle = x1 - x;
y_angle = y - y1;
} else {
x_angle = x2 - x;
y_angle = y - y2;
}
double res = 0;
// atan(y/x) in radians
if(x_angle != 0)
{
res = std::atan(y_angle / x_angle);
res = res * 180.0 / CV_PI; // rad2deg
}
double final_angle = 0.0;
if (x_angle > 0 && y_angle > 0) { // Quadrante I
final_angle = 270.0 - res;
}
if (x_angle < 0 && y_angle > 0) { // Quadrante II
final_angle = 90.0 - res;
}
if (x_angle < 0 && y_angle < 0) { // Quadrante III
final_angle = 90.0 - res;
}
if (x_angle > 0 && y_angle < 0) { // Quadrante IV
final_angle = 270.0 - res;
}
double old_min = cal.min_angle;
double old_max = cal.max_angle;
double new_min = cal.min_value;
double new_max = cal.max_value;
double old_value = final_angle;
double old_range = (old_max - old_min);
double new_range = (new_max - new_min);
double new_value = (((old_value - old_min) * new_range) / old_range) + new_min;
return new_value;
}
int main(int argc, char *argv[]) {
CommandLineParser parser(argc, argv, "{@input |gauge-1.jpg|Input image to reads the value using functions from the OpenCV. }");
parser.about("Analog-gauge-reader example:\n");
parser.printMessage();
string filename = parser.get<String>("@input");
Mat img = imread(filename);
if (img.empty()) {
cerr << "Error loading image. " << filename << endl;
return 1;
}
// Calibration
GaugeCalibration cal = calibrate_gauge(filename);
double val = get_current_value(img, cal );
cout << "Current reading: " << val << " " << cal.units << endl;
return 0;
}
+269
View File
@@ -0,0 +1,269 @@
/*******************************************************************************
*
* This program demonstrates various shape fitting techniques using OpenCV.
* It reads an image, applies binary thresholding, and then detects contours.
*
* For each contour, it fits and draws several geometric shapes including
* convex hulls, minimum enclosing circles, rectangles, triangles, and ellipses
* using different fitting 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
*
* The results are displayed with unique colors
* for each shape and fitting method for clear differentiation.
*
*
*********************************************************************************/
#include "opencv2/geometry/2d.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <vector>
using namespace cv;
using namespace std;
const string hot_keys =
"\n\nHot keys: \n"
"\tESC - quit the program\n"
"\tq - quit the program\n"
"\tc - make the circle\n"
"\tr - make the rectangle\n"
"\th - make the convexhull\n"
"\tt - make the triangle\n"
"\te - make the ellipse\n"
"\ta - make all shapes\n"
"\t0 - use OpenCV's method for ellipse fitting\n"
"\t1 - use Approximate Mean Square (AMS) method for ellipse fitting \n"
"\t2 - use Direct least square (Direct) method for ellipse fitting\n";
static void help(char** argv)
{
cout << "\nThis program demonstrates various shape fitting techniques on a set of points using functions: \n"
<< "minAreaRect(), minEnclosingTriangle(), minEnclosingCircle(), convexHull(), and ellipse().\n\n"
<< "Usage: " << argv[0] << " [--image_name=<image_path> Default: ellipses.jpg]\n\n";
cout << hot_keys << endl;
}
void processImage(int, void*);
void drawShapes(Mat &img, const vector<Point> &points, int ellipseMethod, string shape);
void drawConvexHull(Mat &img, const vector<Point> &points);
void drawMinAreaRect(Mat &img, const vector<Point> &points);
void drawFittedEllipses(Mat &img, const vector<Point> &points, int ellipseMethod);
void drawMinEnclosingCircle(Mat &img, const vector<Point> &points);
void drawMinEnclosingTriangle(Mat &img, const vector<Point> &points);
// Shape fitting options
Mat image;
enum EllipseFittingMethod {
OpenCV_Method,
AMS_Method,
Direct_Method
};
struct UserData {
int sliderPos = 70;
string shape = "--all";
int ellipseMethod = OpenCV_Method;
};
const char* keys =
"{help h | | Show help message }"
"{@image |ellipses.jpg| Path to input image file }";
int main(int argc, char** argv) {
cv::CommandLineParser parser(argc, argv, keys);
help(argv);
if (parser.has("help"))
{
return 0;
}
UserData userData; // variable to pass all the necessary values to trackbar callback
string filename = parser.get<string>("@image");
image = imread(samples::findFile(filename), IMREAD_COLOR); // Read the image from the specified path
if (image.empty()) {
cout << "Could not open or find the image" << endl;
return -1;
}
namedWindow("Shapes", WINDOW_AUTOSIZE); // Create a window to display the results
createTrackbar("Threshold", "Shapes", NULL, 255, processImage, &userData); // Create a threshold trackbar
setTrackbarPos("Threshold", "Shapes", userData.sliderPos);
for(;;) {
char key = (char)waitKey(0); // Listen for a key press
if (key == 'q' || key == 27) break; // Exit the loop if 'q' or ESC is pressed
switch (key) {
case 'h': userData.shape = "--convexhull"; break;
case 'a': userData.shape = "--all"; break;
case 't': userData.shape = "--triangle"; break;
case 'c': userData.shape = "--circle"; break;
case 'e': userData.shape = "--ellipse"; break;
case 'r': userData.shape = "--rectangle"; break;
case '0': userData.ellipseMethod = OpenCV_Method; break;
case '1': userData.ellipseMethod = AMS_Method; break;
case '2': userData.ellipseMethod = Direct_Method; break;
default: break; // Do nothing for other keys
}
processImage(userData.sliderPos, &userData); // Process the image with the current settings
}
return 0;
}
// Function to draw the minimum enclosing circle around given points
void drawMinEnclosingCircle(Mat &img, const vector<Point> &points) {
Point2f center;
float radius = 0;
minEnclosingCircle(points, center, radius); // Find the enclosing circle
// Draw the circle
circle(img, center, cvRound(radius), Scalar(0, 0, 255), 2, LINE_AA);
}
// Function to draw the minimum enclosing triangle around given points
void drawMinEnclosingTriangle(Mat &img, const vector<Point> &points) {
vector<Point> triangle;
minEnclosingTriangle(points, triangle); // Find the enclosing triangle
if (triangle.size() != 3) {
return;
}
// Use polylines to draw the triangle. The 'true' argument closes the triangle.
polylines(img, triangle, true, Scalar(255, 0, 0), 2, LINE_AA);
}
// Function to draw the minimum area rectangle around given points
void drawMinAreaRect(Mat &img, const vector<Point> &points) {
RotatedRect box = minAreaRect(points); // Find the minimum area rectangle
Point2f vtx[4];
box.points(vtx);
// Convert Point2f to Point because polylines expects a vector of Point
vector<Point> rectPoints;
for (int i = 0; i < 4; i++) {
rectPoints.push_back(Point(cvRound(vtx[i].x), cvRound(vtx[i].y)));
}
// Use polylines to draw the rectangle. The 'true' argument closes the loop, drawing a rectangle.
polylines(img, rectPoints, true, Scalar(0, 255, 0), 2, LINE_AA);
}
// Function to draw the convex hull of given points
void drawConvexHull(Mat &img, const vector<Point> &points) {
vector<Point> hull;
convexHull(points, hull, false); // Find the convex hull
// Draw the convex hull
polylines(img, hull, true, Scalar(255, 255, 0), 2, LINE_AA);
}
inline static bool isGoodBox(const RotatedRect& box) {
//size.height >= size.width awalys,only if the pts are on a line or at the same point,size.width=0
return (box.size.height <= box.size.width * 30) && (box.size.width > 0);
}
// Function to draw fitted ellipses using different methods
void drawFittedEllipses(Mat &img, const vector<Point> &points, int ellipseMethod) {
switch (ellipseMethod) {
case OpenCV_Method: // Standard ellipse fitting
{
RotatedRect fittedEllipse = fitEllipse(points);
if (isGoodBox(fittedEllipse)) {
ellipse(img, fittedEllipse, Scalar(255, 0, 255), 2, LINE_AA);
}
putText(img, "OpenCV", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA);
}
break;
case AMS_Method: // AMS ellipse fitting
{
RotatedRect fittedEllipseAMS = fitEllipseAMS(points);
if (isGoodBox(fittedEllipseAMS)) {
ellipse(img, fittedEllipseAMS, Scalar(255, 0, 255), 2, LINE_AA);
}
putText(img, "AMS", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA);
}
break;
case Direct_Method: // Direct ellipse fitting
{
RotatedRect fittedEllipseDirect = fitEllipseDirect(points);
if (isGoodBox(fittedEllipseDirect)) {
ellipse(img, fittedEllipseDirect, Scalar(255, 0, 255), 2, LINE_AA);
}
putText(img, "Direct", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA);
}
break;
default: // Default case falls back to OpenCV method
{
RotatedRect fittedEllipse = fitEllipse(points);
if (isGoodBox(fittedEllipse)) {
ellipse(img, fittedEllipse, Scalar(255, 0, 255), 2, LINE_AA);
}
putText(img, "OpenCV (default)", Point(img.cols - 80, 20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 0, 255), 2, LINE_AA);
cout << "Warning: Invalid ellipseMethod value. Falling back to default OpenCV method." << endl;
}
break;
}
}
// Function to draw shapes
void drawShapes(Mat &img, const vector<Point> &points, int ellipseMethod, string shape) {
if (shape == "--circle") {
drawMinEnclosingCircle(img, points);
} else if (shape == "--triangle") {
drawMinEnclosingTriangle(img, points);
} else if (shape == "--rectangle") {
drawMinAreaRect(img, points);
} else if (shape == "--convexhull") {
drawConvexHull(img, points);
} else if (shape == "--ellipse"){
drawFittedEllipses(img, points, ellipseMethod);
}
else if (shape == "--all") {
drawMinEnclosingCircle(img, points);
drawMinEnclosingTriangle(img, points);
drawMinAreaRect(img, points);
drawConvexHull(img, points);
drawFittedEllipses(img, points, ellipseMethod);
}
}
// Main function to process the image based on the current trackbar position
void processImage(int position, void* userData){
UserData* data = static_cast<UserData*>(userData);
data->sliderPos = position;
Mat processedImg = image.clone(); // Clone the original image for processing
Mat gray;
cvtColor(processedImg, gray, COLOR_BGR2GRAY); // Convert to grayscale
threshold(gray, gray, data->sliderPos, 255, THRESH_BINARY); // Apply binary threshold
Mat filteredImg;
medianBlur(gray, filteredImg, 3);
vector<vector<Point>> contours;
findContours(filteredImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); // Find contours
if (contours.empty()) {
return;
}
imshow("Mask", filteredImg); // Show the mask
for (size_t i = 0; i < contours.size(); ++i) {
if (contours[i].size() < 5) { // Check if the contour has enough points
continue;
}
drawShapes(processedImg, contours[i], data->ellipseMethod, data->shape);
}
imshow("Shapes", processedImg); // Display the processed image with fitted shapes
}
+350
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;
}
+399
View File
@@ -0,0 +1,399 @@
/*
* 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}, {
(float)cos(angle), (float)-sin(angle), (rng.uniform(10.f, 20.f)),
(float)sin(angle), (float)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;
}
+54
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;
}
+235
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);
}
+152
View File
@@ -0,0 +1,152 @@
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/features.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;
}
+227
View File
@@ -0,0 +1,227 @@
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/objdetect.hpp>
#ifdef HAVE_OPENCV_DNN
#include <opencv2/dnn.hpp>
#include "../dnn/common.hpp"
#endif
#include <iostream>
using namespace std;
using namespace cv;
#ifdef HAVE_OPENCV_DNN
using namespace cv::dnn;
#endif
using namespace mcc;
const string about =
"This sample demonstrates mcc checker detection with DNN based model and thresholding (default) techniques.\n\n"
"To run default:\n"
"\t ./example_cpp_macbeth_chart_detection --input=path/to/your/input/image/or/video (don't give --input flag if want to use device camera)\n"
#ifdef HAVE_OPENCV_DNN
"With DNN model:\n"
"\t ./example_cpp_macbeth_chart_detection mcc --input=path/to/your/input/image/or/video\n\n"
"Model path can also be specified using --model argument. And config path can be specified using --config. Download it using python download_models.py mcc from dnn samples directory\n\n"
#else
"Note: DNN-based detection is not available in this build.\n\n"
#endif
;
const string param_keys =
"{ help h | | Print help message. }"
#ifdef HAVE_OPENCV_DNN
"{ @alias | | An alias name of model to extract preprocessing parameters from models.yml file. }"
"{ zoo | ../dnn/models.yml | An optional path to file with preprocessing parameters }"
#endif
"{ input i | | Path to input image or video file. Skip this argument to capture frames from a camera.}"
"{ type | 0 | chartType: 0-Standard, 1-DigitalSG, 2-Vinyl, default:0 }"
"{ num_charts | 1 | Maximum number of charts in the image }"
#ifdef HAVE_OPENCV_DNN
"{ model | | Path to the model file for using dnn model. }";
#else
;
#endif
#ifdef HAVE_OPENCV_DNN
const string backend_keys = format(
"{ backend | default | Choose one of computation backends: "
"default: automatically (by default), "
"openvino: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), "
"opencv: OpenCV implementation, "
"vkcom: VKCOM, "
"cuda: CUDA, "
"webnn: WebNN }");
const string target_keys = format(
"{ target | cpu | Choose one of target computation devices: "
"cpu: CPU target (by default), "
"opencl: OpenCL, "
"opencl_fp16: OpenCL fp16 (half-float precision), "
"vpu: VPU, "
"vulkan: Vulkan, "
"cuda: CUDA, "
"cuda_fp16: CUDA fp16 (half-float preprocess) }");
#endif
// Initialize keys before use
string keys = param_keys;
static void initKeys() {
#ifdef HAVE_OPENCV_DNN
keys += backend_keys + target_keys;
#endif
}
static bool processFrame(const Mat& frame, Ptr<CCheckerDetector> detector, Mat& src, Mat& tgt, int nc){
Mat imageCopy = frame.clone();
if (!detector->process(frame, nc))
{
return false;
}
vector<Ptr<CChecker>> checkers = detector->getListColorChecker();
detector->draw(checkers, frame);
src = checkers[0]->getChartsRGB(false);
tgt = detector->getRefColors();
imshow("Image result", frame);
imshow("Original", imageCopy);
return true;
}
int main(int argc, char *argv[])
{
initKeys();
CommandLineParser parser(argc, argv, keys);
parser.about(about);
if (parser.has("help"))
{
cout << about << endl;
parser.printMessage();
return -1;
}
#ifdef HAVE_OPENCV_DNN
string modelName = parser.get<String>("@alias");
string zooFile = parser.get<String>("zoo");
const char* path = getenv("OPENCV_SAMPLES_DATA_PATH");
if ((path != NULL) || parser.has("@alias") || (parser.get<String>("model") != "")) {
zooFile = findFile(zooFile);
}
else{
cout<<"[WARN] set the environment variables or pass the arguments --model, --config and models.yml file using --zoo for using dnn based detector. Continuing with default detector.\n\n";
}
keys += genPreprocArguments(modelName, zooFile);
parser = CommandLineParser(argc, argv, keys);
#endif
int t = parser.get<int>("type");
CV_Assert(0 <= t && t <= 2);
ColorChart chartType = ColorChart(t);
#ifdef HAVE_OPENCV_DNN
const string sha1 = parser.get<String>("sha1");
const string model_path = findModel(parser.get<string>("model"), sha1);
const string config_sha1 = parser.get<String>("config_sha1");
const string pbtxt_path = findModel(parser.get<string>("config"), config_sha1);
const string backend = parser.get<String>("backend");
const string target = parser.get<String>("target");
#endif
int nc = parser.get<int>("num_charts");
Ptr<CCheckerDetector> detector;
#ifdef HAVE_OPENCV_DNN
if (model_path != "" && pbtxt_path != ""){
EngineType engine = ENGINE_AUTO;
if (backend != "default" || target != "cpu"){
engine = ENGINE_CLASSIC;
}
Net net = readNetFromTensorflow(model_path, pbtxt_path, engine);
net.setPreferableBackend(getBackendID(backend));
net.setPreferableTarget(getTargetID(target));
detector = CCheckerDetector::create(net);
cout<<"Detecting checkers using neural network."<<endl;
}
else{
detector = CCheckerDetector::create();
}
#else
detector = CCheckerDetector::create();
#endif
detector->setColorChartType(chartType);
bool isVideo = true;
Mat image;
VideoCapture cap;
if (parser.has("input")){
const string inputFile = parser.get<String>("input");
image = imread(findFile(inputFile));
if (!image.empty())
{
isVideo = false;
}
else
{
// Not an image, so try opening it as a video.
cap.open(findFile(inputFile));
if (!cap.isOpened())
{
cout << "[ERROR] Could not open file as an image or video: " << inputFile << endl;
return -1;
}
}
}
else
cap.open(0);
Mat src, tgt;
bool found = false;
if (isVideo){
cout<<"To print the actual colors and reference colors for current frame press SPACEBAR. To resume press SPACEBAR again"<<endl;
while (cap.grab())
{
Mat frame;
cap.retrieve(frame);
found = processFrame(frame, detector, src, tgt, nc);
int key = waitKey(10);
if (key == ' '){
if(found){
cout<<"Reference colors: "<<tgt<<endl<<"--------------------"<<endl;
cout<<"Actual colors: "<<src<<endl<<endl;
cout<<"Press spacebar to resume."<<endl;
waitKey(0);
cout << "Resumed! Processing continues..." << endl;
}
else{
cout<<"No color chart detected!!"<<endl;
}
}
else if (key == 27) exit(0);
}
if(found){
cout<<"Reference colors: "<<tgt<<endl<<"--------------------"<<endl;
cout<<"Actual colors: "<<src<<endl<<endl;
}
}
else{
found = processFrame(image, detector, src, tgt, nc);
if(found){
cout<<"Reference colors: "<<tgt<<endl<<"--------------------"<<endl;
cout<<"Actual colors: "<<src<<endl<<endl;
waitKey(0);
}
else{
cout<<"No chart detected!!"<<endl;
}
}
return 0;
}
+112
View File
@@ -0,0 +1,112 @@
#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, cross and diamond 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"
"\td - use diamond-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 == 'd' )
element_shape = MORPH_DIAMOND;
else if( c == ' ' )
element_shape = (element_shape + 1) % 4;
}
return 0;
}
@@ -0,0 +1,251 @@
// 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 <vector>
#include <string>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <iostream>
#include <fstream>
// ! [detectPointsAndCalibrate_signature]
static void detectPointsAndCalibrate (cv::Size pattern_size, float pattern_distance, const std::string &pattern_type,
const std::vector<uchar> &models, const std::vector<std::string> &filenames,
const cv::String* dict_path=nullptr)
// ! [detectPointsAndCalibrate_signature]
{
// ! [calib_init]
std::vector<cv::Point3f> board (pattern_size.area());
const int num_cameras = (int)models.size();
std::vector<std::vector<cv::Mat>> image_points_all;
std::vector<cv::Size> image_sizes;
std::vector<cv::Mat> Ks, distortions, Ts, Rs;
if (pattern_type == "checkerboard" || pattern_type == "charuco") {
for (int i = 0; i < pattern_size.height; i++) {
for (int j = 0; j < pattern_size.width; j++) {
board[i*pattern_size.width+j] = cv::Point3f((float)j, (float)i, 0.f) * pattern_distance;
}
}
} else if (pattern_type == "circles") {
for (int i = 0; i < pattern_size.height; i++) {
for (int j = 0; j < pattern_size.width; j++) {
board[i*pattern_size.width+j] = cv::Point3f((float)j, (float)i, 0.f) * pattern_distance;
}
}
} else if (pattern_type == "acircles") {
for (int i = 0; i < pattern_size.height; i++) {
for (int j = 0; j < pattern_size.width; j++) {
if (i % 2 == 1) {
board[i*pattern_size.width+j] = cv::Point3f((j + .5f)*pattern_distance, (i/2 + .5f) * pattern_distance, 0.f);
} else{
board[i*pattern_size.width+j] = cv::Point3f(j*pattern_distance, (i/2)*pattern_distance, 0);
}
}
}
}
else {
CV_Error(cv::Error::StsNotImplemented, "pattern_type is not implemented!");
}
// ! [calib_init]
// ! [charuco_detector]
cv::Ptr<cv::aruco::CharucoDetector> detector;
if (pattern_type == "charuco") {
CV_Assert(dict_path != nullptr);
cv::FileStorage fs(*dict_path, cv::FileStorage::READ);
CV_Assert(fs.isOpened());
int dict_int;
double square_size, marker_size;
fs["dictionary"] >> dict_int;
fs["square_size"] >> square_size;
fs["marker_size"] >> marker_size;
auto dictionary = cv::aruco::getPredefinedDictionary(dict_int);
// For charuco board, the size is defined to be the number of box (not inner corner)
auto charuco_board = cv::aruco::CharucoBoard(
cv::Size(pattern_size.width+1, pattern_size.height+1),
static_cast<float>(square_size), static_cast<float>(marker_size), dictionary);
// It is suggested to use refinement in detecting charuco board
auto detector_params = cv::aruco::DetectorParameters();
auto charuco_params = cv::aruco::CharucoParameters();
charuco_params.tryRefineMarkers = true;
detector_params.cornerRefinementMethod = cv::aruco::CORNER_REFINE_CONTOUR;
detector = cv::makePtr<cv::aruco::CharucoDetector>(charuco_board, charuco_params, detector_params);
}
// ! [charuco_detector]
// ! [detect_pattern]
int num_frames = -1;
for (const auto &filename : filenames) {
std::fstream file(filename);
CV_Assert(file.is_open());
std::string img_file;
std::vector<cv::Mat> image_points_cameras;
bool save_img_size = true;
while (std::getline(file, img_file)) {
if (img_file.empty()){
image_points_cameras.emplace_back(cv::Mat());
continue;
}
cv::Mat img = cv::imread(img_file), corners;
if (save_img_size) {
image_sizes.emplace_back(cv::Size(img.cols, img.rows));
save_img_size = false;
}
bool success = false;
if (pattern_type == "checkerboard") {
cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);
success = cv::findChessboardCorners(img, pattern_size, corners);
}
else if (pattern_type == "circles")
{
success = cv::findCirclesGrid(img, pattern_size, corners, cv::CALIB_CB_SYMMETRIC_GRID);
}
else if (pattern_type == "acircles")
{
success = cv::findCirclesGrid(img, pattern_size, corners, cv::CALIB_CB_ASYMMETRIC_GRID);
}
else if (pattern_type == "charuco")
{
std::vector<int> ids; cv::Mat corners_sub;
detector->detectBoard(img, corners_sub, ids);
corners.create(static_cast<int>(board.size()), 2, CV_32F);
if (ids.size() < 4)
success = false;
else {
success = true;
int head = 0;
for (int i = 0; i < static_cast<int>(board.size()); i++) {
if (head < static_cast<int>(ids.size()) && ids[head] == i) {
corners.at<float>(i, 0) = corners_sub.at<float>(head, 0);
corners.at<float>(i, 1) = corners_sub.at<float>(head, 1);
head++;
} else {
// points outside of frame border are dropped by calibrateMultiview
corners.at<float>(i, 0) = -1.;
corners.at<float>(i, 1) = -1.;
}
}
}
}
cv::Mat corners2;
corners.convertTo(corners2, CV_32FC2);
if (success && corners.rows == pattern_size.area())
image_points_cameras.emplace_back(corners2);
else
image_points_cameras.emplace_back(cv::Mat());
}
if (num_frames == -1)
num_frames = (int)image_points_cameras.size();
else
CV_Assert(num_frames == (int)image_points_cameras.size());
image_points_all.emplace_back(image_points_cameras);
}
// ! [detect_pattern]
// ! [detection_matrix]
cv::Mat visibility(num_cameras, num_frames, CV_8UC1);
for (int i = 0; i < num_cameras; i++) {
for (int j = 0; j < num_frames; j++) {
visibility.at<unsigned char>(i,j) = image_points_all[i][j].empty() ? 0 : 1;
}
}
// ! [detection_matrix]
CV_Assert(num_frames != -1);
std::vector<std::vector<cv::Point3f>> objPoints(num_frames, board);
// ! [multiview_calib]
const double rmse = calibrateMultiview(objPoints, image_points_all, image_sizes, visibility,
models, Ks, distortions, Rs, Ts);
// ! [multiview_calib]
std::cout << "average RMSE over detection mask " << rmse << "\n";
for (int c = 0; c < (int)Rs.size(); c++) {
std::cout << "camera " << c << '\n';
std::cout << "rotation\n" << Rs[c] << "\n";
std::cout << "translation\n" << Ts[c] << "\n";
std::cout << "intrinsic matrix\n" << Ks[c] << "\n";
std::cout << "distortion\n" << distortions[c] << "\n";
}
}
int main (int argc, char **argv) {
cv::String keys =
"{help h usage ? || print help }"
"{pattern_size || (inner) grid width, (inner) grid height }"
"{pattern_distance || pattern scale}"
"{pattern_type | checkerboard | pattern type, e.g., checkerboard or acircles or charuco (recommended)}"
"{is_fisheye || cameras type fisheye (1), pinhole(0), separated by comma (no space)}"
"{filenames || files containing path to image names separated by comma (no space)}"
"{board_dict_path || file containing dictionary information (required field: dictionary, square_size, marker_size). Needed if pattern_type is charuco.}";
cv::CommandLineParser parser(argc, argv, keys);
if (parser.has("help")) {
parser.printMessage();
return 0;
}
CV_Assert(parser.has("pattern_size") && parser.has("pattern_type") &&
parser.has("is_fisheye") && parser.has("filenames"));
CV_Assert(parser.get<cv::String>("pattern_type") == "checkerboard" ||
parser.get<cv::String>("pattern_type") == "circles" ||
parser.get<cv::String>("pattern_type") == "acircles" ||
parser.get<cv::String>("pattern_type") == "charuco"
);
if (parser.get<cv::String>("pattern_type") == "charuco")
CV_Assert(parser.has("board_dict_path"));
cv::Size pattern_size;
const cv::String pattern_size_str = parser.get<cv::String>("pattern_size");
std::string temp_str;
int pattern_size_count = 0;
for (char i : pattern_size_str) {
if (i == ',') {
if (pattern_size_count == 0)
pattern_size.width = std::stoi(temp_str);
pattern_size_count++;
temp_str = "";
} else {
temp_str += i;
}
}
CV_Assert(pattern_size_count == 1);
pattern_size.height = std::stoi(temp_str);
std::vector<uchar> models;
const cv::String is_fisheye_str = parser.get<cv::String>("is_fisheye");
for (char i : is_fisheye_str) {
if (i == '0') {
models.push_back(cv::CALIB_MODEL_PINHOLE);
} else if (i == '1') {
models.push_back(cv::CALIB_MODEL_FISHEYE);
}
}
const cv::String filenames_str = parser.get<cv::String>("filenames");
std::vector<std::string> filenames;
temp_str = "";
for (char i : filenames_str) {
if (i == ',') {
filenames.emplace_back(temp_str);
temp_str = "";
} else {
temp_str += i;
}
}
filenames.emplace_back(temp_str);
CV_CheckEQ(filenames.size(), models.size(), "filenames size must be equal to number of cameras!");
if (parser.has("board_dict_path")) {
cv::String board_dict_path = parser.get<cv::String>("board_dict_path");
detectPointsAndCalibrate (pattern_size, parser.get<float>("pattern_distance"), parser.get<cv::String>("pattern_type"), models, filenames, &board_dict_path);
} else {
detectPointsAndCalibrate (pattern_size, parser.get<float>("pattern_distance"), parser.get<cv::String>("pattern_type"), models, filenames);
}
return 0;
}
+99
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);
}
+32
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;
}
+191
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, IMREAD_GRAYSCALE));
}
}
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;
}
+355
View File
@@ -0,0 +1,355 @@
#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_useArucoBased = false;
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) }"
"{aruco_based | false | use Aruco-based QR code detector instead of contour-based }"
"{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_useArucoBased = cmd_parser.has("aruco_based") && cmd_parser.get<bool>("aruco_based");
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(
const GraphicalCodeDetector& 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(const GraphicalCodeDetector& 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;
GraphicalCodeDetector qrcode = QRCodeDetector();
if (g_useArucoBased)
qrcode = QRCodeDetectorAruco();
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;
GraphicalCodeDetector qrcode = QRCodeDetector();
if (g_useArucoBased)
qrcode = QRCodeDetectorAruco();
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;
}
+610
View File
@@ -0,0 +1,610 @@
/*
*
* 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/geometry.hpp"
#include "opencv2/calib.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/objdetect.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];
snprintf(cmd, sizeof(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++)
{
snprintf(path, sizeof(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;
}
+49
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 = v_add(a, vx_setall_u8(45));
printf("v_get0(vx_setall_u8(10) + vx_setall_u8(45)) => %d\n", (int)v_get0(c));
#else
printf("\nSIMD intrinsics are not available. Check compilation target and passed build options.\n");
#endif
printf("===================== done ======================\n");
return 0;
}
+219
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;
}
@@ -0,0 +1,115 @@
// 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/photo.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static const char* usage =
"Chromatic Aberration Correction Sample\n"
"Usage:\n"
" ca_correction <input_image> <calibration_file> [bayer_pattern] [output_image]\n"
"\n"
"Arguments:\n"
" input_image Path to the input image. Can be:\n"
" • a 3-channel BGR image, or\n"
" • a 1-channel raw Bayer image (see bayer_pattern)\n"
" calibration_file OpenCV YAML/XML file with chromatic aberration calibration:\n"
" image_width, image_height, red_channel/coeffs_x, coeffs_y,\n"
" blue_channel/coeffs_x, coeffs_y.\n"
" output_image (optional) Path to save the corrected image. Default: corrected.png\n"
" bayer_pattern (optional) integer code for demosaicing a 1-channel raw image:\n"
" cv::COLOR_BayerBG2BGR = 46\n"
" cv::COLOR_BayerGB2BGR = 47\n"
" cv::COLOR_BayerGR2BGR = 48\n"
" cv::COLOR_BayerRG2BGR = 49\n"
" If omitted or <0, input is assumed 3-channel BGR.\n"
"\n"
"Example:\n"
" ca_correction input.png calib.yaml 46 corrected.png\n"
"\n";
int main(int argc, char** argv)
{
const string keys =
"{help h | | show this help message }"
"{@input | | input image (BGR or Bayer)}"
"{@calibration | | calibration file (YAML/XML) }"
"{output |corrected.png| output image file }"
"{bayer |-1 | Bayer pattern code for demosaic }"
;
CommandLineParser parser(argc, argv, keys);
parser.about("Chromatic Aberration Correction Sample");
if (parser.has("help") || argc < 3)
{
cout << usage << "\n";
return 0;
}
string inputPath = parser.get<string>("@input");
string calibPath = parser.get<string>("@calibration");
string outputPath = parser.get<string>("output");
int bayerPattern = parser.get<int>("bayer");
if (!parser.check())
{
parser.printErrors();
return 1;
}
Mat input = imread(inputPath, IMREAD_UNCHANGED);
if (input.empty())
{
cerr << "ERROR: Could not load input image: " << inputPath << endl;
return 1;
}
FileStorage fs(calibPath, FileStorage::READ);
if (!fs.isOpened())
{
cerr << "ERROR: Could not load coeffients file: " << calibPath << endl;
return 1;
}
try
{
Mat coeffMat;
Size calibSize = {-1, -1};
int degree = -1;
cv::loadChromaticAberrationParams(fs.root(), coeffMat, calibSize, degree);
Mat corrected;
correctChromaticAberration(input, coeffMat, corrected, calibSize, degree, bayerPattern);
namedWindow("Original", WINDOW_AUTOSIZE);
namedWindow("Corrected", WINDOW_AUTOSIZE);
imshow("Original", input);
imshow("Corrected", corrected);
cout << "Press any key to continue..." << endl;
waitKey();
if (!imwrite(outputPath, corrected))
{
cerr << "WARNING: Could not write output image: " << outputPath << endl;
}
else
{
cout << "Saved corrected image to: " << outputPath << endl;
}
}
catch (const Exception& e)
{
cerr << "OpenCV error: " << e.what() << endl;
return 1;
}
return 0;
}
+251
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);
}
+118
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;
}
+205
View File
@@ -0,0 +1,205 @@
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features.hpp>
#include <vector>
#include <map>
#include <iostream>
using namespace std;
using namespace cv;
static void help(char** argv)
{
cout << "\n This program demonstrates how to use BLOB to detect and filter region \n"
<< "Usage: \n"
<< argv[0]
<< " <image1(detect_blob.png as default)>\n"
<< "Press a key when image window is active to change descriptor";
}
static String Legende(SimpleBlobDetector::Params &pAct)
{
String s = "";
if (pAct.filterByArea)
{
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minArea).str();
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxArea).str();
s = " Area range [" + inf + " to " + sup + "]";
}
if (pAct.filterByCircularity)
{
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minCircularity).str();
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxCircularity).str();
if (s.length() == 0)
s = " Circularity range [" + inf + " to " + sup + "]";
else
s += " AND Circularity range [" + inf + " to " + sup + "]";
}
if (pAct.filterByColor)
{
String inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.blobColor).str();
if (s.length() == 0)
s = " Blob color " + inf;
else
s += " AND Blob color " + inf;
}
if (pAct.filterByConvexity)
{
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minConvexity).str();
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxConvexity).str();
if (s.length() == 0)
s = " Convexity range[" + inf + " to " + sup + "]";
else
s += " AND Convexity range[" + inf + " to " + sup + "]";
}
if (pAct.filterByInertia)
{
String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minInertiaRatio).str();
String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxInertiaRatio).str();
if (s.length() == 0)
s = " Inertia ratio range [" + inf + " to " + sup + "]";
else
s += " AND Inertia ratio range [" + inf + " to " + sup + "]";
}
return s;
}
int main(int argc, char *argv[])
{
String fileName;
cv::CommandLineParser parser(argc, argv, "{@input |detect_blob.png| }{h help | | }");
if (parser.has("h"))
{
help(argv);
return 0;
}
fileName = parser.get<string>("@input");
Mat img = imread(samples::findFile(fileName), IMREAD_COLOR);
if (img.empty())
{
cout << "Image " << fileName << " is empty or cannot be found\n";
return 1;
}
SimpleBlobDetector::Params pDefaultBLOB;
// This is default parameters for SimpleBlobDetector
pDefaultBLOB.thresholdStep = 10;
pDefaultBLOB.minThreshold = 10;
pDefaultBLOB.maxThreshold = 220;
pDefaultBLOB.minRepeatability = 2;
pDefaultBLOB.minDistBetweenBlobs = 10;
pDefaultBLOB.filterByColor = false;
pDefaultBLOB.blobColor = 0;
pDefaultBLOB.filterByArea = false;
pDefaultBLOB.minArea = 25;
pDefaultBLOB.maxArea = 5000;
pDefaultBLOB.filterByCircularity = false;
pDefaultBLOB.minCircularity = 0.9f;
pDefaultBLOB.maxCircularity = (float)1e37;
pDefaultBLOB.filterByInertia = false;
pDefaultBLOB.minInertiaRatio = 0.1f;
pDefaultBLOB.maxInertiaRatio = (float)1e37;
pDefaultBLOB.filterByConvexity = false;
pDefaultBLOB.minConvexity = 0.95f;
pDefaultBLOB.maxConvexity = (float)1e37;
// Descriptor array for BLOB
vector<String> typeDesc;
// Param array for BLOB
vector<SimpleBlobDetector::Params> pBLOB;
vector<SimpleBlobDetector::Params>::iterator itBLOB;
// Color palette
vector< Vec3b > palette;
for (int i = 0; i<65536; i++)
{
uchar c1 = (uchar)rand();
uchar c2 = (uchar)rand();
uchar c3 = (uchar)rand();
palette.push_back(Vec3b(c1, c2, c3));
}
help(argv);
// These descriptors are going to be detecting and computing BLOBS with 6 different params
// Param for first BLOB detector we want all
typeDesc.push_back("BLOB"); // see http://docs.opencv.org/5.x/d0/d7a/classcv_1_1SimpleBlobDetector.html
pBLOB.push_back(pDefaultBLOB);
pBLOB.back().filterByArea = true;
pBLOB.back().minArea = 1;
pBLOB.back().maxArea = float(img.rows*img.cols);
// Param for second BLOB detector we want area between 500 and 2900 pixels
typeDesc.push_back("BLOB");
pBLOB.push_back(pDefaultBLOB);
pBLOB.back().filterByArea = true;
pBLOB.back().minArea = 500;
pBLOB.back().maxArea = 2900;
// Param for third BLOB detector we want only circular object
typeDesc.push_back("BLOB");
pBLOB.push_back(pDefaultBLOB);
pBLOB.back().filterByCircularity = true;
// Param for Fourth BLOB detector we want ratio inertia
typeDesc.push_back("BLOB");
pBLOB.push_back(pDefaultBLOB);
pBLOB.back().filterByInertia = true;
pBLOB.back().minInertiaRatio = 0;
pBLOB.back().maxInertiaRatio = (float)0.2;
// Param for fifth BLOB detector we want ratio inertia
typeDesc.push_back("BLOB");
pBLOB.push_back(pDefaultBLOB);
pBLOB.back().filterByConvexity = true;
pBLOB.back().minConvexity = 0.;
pBLOB.back().maxConvexity = (float)0.9;
// Param for six BLOB detector we want blob with gravity center color equal to 0
typeDesc.push_back("BLOB");
pBLOB.push_back(pDefaultBLOB);
pBLOB.back().filterByColor = true;
pBLOB.back().blobColor = 0;
itBLOB = pBLOB.begin();
vector<double> desMethCmp;
Ptr<Feature2D> b;
String label;
// Descriptor loop
vector<String>::iterator itDesc;
for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
{
vector<KeyPoint> keyImg1;
if (*itDesc == "BLOB")
{
b = SimpleBlobDetector::create(*itBLOB);
label = Legende(*itBLOB);
++itBLOB;
}
try
{
// We can detect keypoint with detect method
vector<KeyPoint> keyImg;
vector<Rect> zone;
vector<vector <Point> > region;
Mat desc, result(img.rows, img.cols, CV_8UC3);
if (b.dynamicCast<SimpleBlobDetector>().get())
{
Ptr<SimpleBlobDetector> sbd = b.dynamicCast<SimpleBlobDetector>();
sbd->detect(img, keyImg, Mat());
drawKeypoints(img, keyImg, result);
int i = 0;
for (vector<KeyPoint>::iterator k = keyImg.begin(); k != keyImg.end(); ++k, ++i)
circle(result, k->pt, (int)k->size, palette[i % 65536]);
}
namedWindow(*itDesc + label, WINDOW_AUTOSIZE);
imshow(*itDesc + label, result);
imshow("Original", img);
waitKey();
}
catch (const Exception& e)
{
cout << "Feature : " << *itDesc << "\n";
cout << e.msg << endl;
}
}
return 0;
}
+109
View File
@@ -0,0 +1,109 @@
#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
static void convolveDFT(InputArray A, InputArray B, OutputArray C) {
// Calculate the size of the output array
int outputRows = A.rows() + B.rows() - 1;
int outputCols = A.cols() + B.cols() - 1;
// Reallocate the output array if needed
C.create(outputRows, outputCols, A.type());
Size dftSize;
// Calculate the size of DFT transform
dftSize.width = getOptimalDFTSize(A.cols() + B.cols() - 1);
dftSize.height = getOptimalDFTSize(A.rows() + B.rows() - 1);
// Allocate temporary buffers and initialize them with 0's
Mat tempA(dftSize, A.type(), Scalar::all(0));
Mat tempB(dftSize, B.type(), Scalar::all(0));
// Copy A and B to the top-left corners of tempA and tempB, respectively
Mat roiA(tempA, Rect(0, 0, A.cols(), A.rows()));
A.copyTo(roiA);
Mat roiB(tempB, Rect(0, 0, B.cols(), B.rows()));
B.copyTo(roiB);
// Now transform the padded A & B in-place;
// use "nonzeroRows" hint for faster processing
dft(tempA, tempA, 0, A.rows());
dft(tempB, tempB, 0, B.rows());
// Multiply the spectrums;
// the function handles packed spectrum representations well
mulSpectrums(tempA, tempB, tempA, 0);
// Transform the product back from the frequency domain.
// Even though all the result rows will be non-zero,
// you need only the first C.rows of them, and thus you
// pass nonzeroRows == C.rows
dft(tempA, tempA, DFT_INVERSE + DFT_SCALE, C.rows());
// Now copy the result back to C.
tempA(Rect(0, 0, C.cols(), C.rows())).copyTo(C);
// All the temporary buffers will be deallocated automatically
}
static void help(const char ** argv)
{
printf("\nThis program demonstrates the use of convolution using discrete Fourier transform (DFT)\n"
"An image is convolved with kernel filter using DFT.\n"
"Usage:\n %s [input -- default lena.jpg]\n", argv[0]);
}
const char* keys =
{
"{help h||}{@input|lena.jpg|input image file}"
};
int main(int argc, const char** argv) {
// Load the image in grayscale
help(argv);
CommandLineParser parser(argc, argv, keys);
if (parser.has("help"))
{
help(argv);
return 0;
}
string filename = parser.get<string>(0);
Mat img = imread(samples::findFile(filename), IMREAD_GRAYSCALE);
// Check if the image is loaded successfully
if (img.empty()) {
std::cerr << "Error: Image not loaded!" << std::endl;
return -1;
}
// Convert the image to CV_32F
Mat img_32f;
img.convertTo(img_32f, CV_32F);
float kernelData[9] = { 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9, 1.0f/9 }; // example of blur filter, can be changed to other filter as well.
Mat kernel(3, 3, CV_32F, kernelData);
// Perform convolution of the image with the sharpening kernel
Mat result;
convolveDFT(img_32f, kernel, result);
// Normalize the result for better visualization
normalize(result, result, 0, 255, NORM_MINMAX);
// Convert result back to 8-bit for display
Mat result_8u;
result.convertTo(result_8u, CV_8U);
// Display the images
imshow("Original Image", img);
imshow("Output Image", result_8u);
waitKey(0); // Wait for a key press to close the windows
return 0;
}
+64
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;
}
+186
View File
@@ -0,0 +1,186 @@
#include <opencv2/core/utility.hpp>
#include "opencv2/geometry.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;
}
+85
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;
}
+107
View File
@@ -0,0 +1,107 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "opencv2/geometry.hpp"
#include "opencv2/features.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);
}
+110
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", "Deep Green", "User defined (random)" };
static void TrackColorMap(int x, void *r)
{
ParamColorMap *p = (ParamColorMap*)r;
Mat dst;
p->iColormap= x;
if (x == COLORMAP_DEEPGREEN + 1)
{
Mat lutRND(256, 1, CV_8UC3);
randu(lutRND, Scalar(0, 0, 0), Scalar(255, 255, 255));
applyColorMap(p->img, dst, lutRND);
}
else
applyColorMap(p->img,dst,p->iColormap);
putText(dst, "Colormap : "+ColorMaps[p->iColormap], Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.8, Scalar(255, 255, 255),2);
imshow(winName, dst);
}
static Mat DrawMyImage(int thickness,int nbShape)
{
Mat img=Mat::zeros(500,256*thickness+100,CV_8UC1);
int offsetx = 50, offsety = 25;
int lineLength = 50;
for (int i=0;i<256;i++)
line(img,Point(thickness*i+ offsetx, offsety),Point(thickness*i+ offsetx, offsety+ lineLength),Scalar(i), thickness);
RNG r;
Point center;
int radius;
int width,height;
int angle;
Rect rc;
for (int i=1;i<=nbShape;i++)
{
int typeShape = r.uniform(MyCIRCLE, MyELLIPSE+1);
switch (typeShape) {
case MyCIRCLE:
center = Point(r.uniform(offsetx,img.cols- offsetx), r.uniform(offsety + lineLength, img.rows - offsety));
radius = r.uniform(1, min(offsetx, offsety));
circle(img,center,radius,Scalar(i),-1);
break;
case MyRECTANGLE:
center = Point(r.uniform(offsetx, img.cols - offsetx), r.uniform(offsety + lineLength, img.rows - offsety));
width = r.uniform(1, min(offsetx, offsety));
height = r.uniform(1, min(offsetx, offsety));
rc = Rect(center-Point(width ,height )/2, center + Point(width , height )/2);
rectangle(img,rc, Scalar(i), -1);
break;
case MyELLIPSE:
center = Point(r.uniform(offsetx, img.cols - offsetx), r.uniform(offsety + lineLength, img.rows - offsety));
width = r.uniform(1, min(offsetx, offsety));
height = r.uniform(1, min(offsetx, offsety));
angle = r.uniform(0, 180);
ellipse(img, center,Size(width/2,height/2),angle,0,360, Scalar(i), -1);
break;
}
}
return img;
}
int main(int argc, char** argv)
{
cout << "This program demonstrates the use of applyColorMap function.\n\n";
ParamColorMap p;
Mat img;
if (argc > 1)
img = imread(samples::findFile(argv[1]), IMREAD_GRAYSCALE);
else
img = DrawMyImage(2,256);
p.img=img;
p.iColormap=0;
imshow("Gray image",img);
namedWindow(winName);
createTrackbar("colormap", winName, NULL, COLORMAP_DEEPGREEN + 1, TrackColorMap, (void*)&p);
setTrackbarMin("colormap", winName, COLORMAP_AUTUMN);
setTrackbarMax("colormap", winName, COLORMAP_DEEPGREEN + 1);
setTrackbarPos("colormap", winName, COLORMAP_AUTUMN);
TrackColorMap(0, (void*)&p);
cout << "Press a key to exit" << endl;
waitKey(0);
return 0;
}
+160
View File
@@ -0,0 +1,160 @@
/*
* Author: Steve Nicholson
*
* A program that illustrates intersectConvexConvex in various scenarios
*/
#include "opencv2/geometry.hpp"
#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();
}
+112
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;
}
+83
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 representative 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;
}
+98
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;
}
+74
View File
@@ -0,0 +1,74 @@
#include "opencv2/geometry/2d.hpp"
#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;
}
+74
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/5.x/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d" << endl
<< " TM_SQDIFF = " << (int)TM_SQDIFF << endl
<< " TM_SQDIFF_NORMED = " << (int)TM_SQDIFF_NORMED << endl
<< " TM_CCORR = " << (int)TM_CCORR << endl
<< " TM_CCORR_NORMED = " << (int)TM_CCORR_NORMED << endl
<< " TM_CCOEFF = " << (int)TM_CCOEFF << endl
<< " TM_CCOEFF_NORMED = " << (int)TM_CCOEFF_NORMED << endl
<< endl;
parser.printMessage();
string filename = samples::findFile(parser.get<string>("i"));
string tmplname = samples::findFile(parser.get<string>("t"));
string maskname = samples::findFile(parser.get<string>("m"));
Mat img = imread(filename);
Mat tmpl = imread(tmplname);
Mat mask = imread(maskname);
Mat res;
if(img.empty())
{
cout << "can not open " << filename << endl;
return -1;
}
if(tmpl.empty())
{
cout << "can not open " << tmplname << endl;
return -1;
}
if(mask.empty())
{
cout << "can not open " << maskname << endl;
return -1;
}
int method = parser.get<int>("cm"); // default 3 (cv::TM_CCORR_NORMED)
matchTemplate(img, tmpl, res, method, mask);
double minVal, maxVal;
Point minLoc, maxLoc;
Rect rect;
minMaxLoc(res, &minVal, &maxVal, &minLoc, &maxLoc);
if(method == TM_SQDIFF || method == TM_SQDIFF_NORMED)
rect = Rect(minLoc, tmpl.size());
else
rect = Rect(maxLoc, tmpl.size());
rectangle(img, rect, Scalar(0, 255, 0), 2);
imshow("detected template", img);
waitKey();
return 0;
}
+46
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;
}
+99
View File
@@ -0,0 +1,99 @@
#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 warpPolar for both linear and log-polar 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);
//! [InverseMap]
// direct transform using warpPolar (replacing deprecated functions)
warpPolar(src, lin_polar_img, Size(),center, maxRadius, flags); // Linear-polar transform
warpPolar(src, log_polar_img, Size(),center, maxRadius, flags + WARP_POLAR_LOG); // Log-polar transform
// 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;
}
+120
View File
@@ -0,0 +1,120 @@
#include "opencv2/imgproc.hpp"
#include "opencv2/geometry.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;
}
+159
View File
@@ -0,0 +1,159 @@
// The "Square Detector" program.
// It loads several images sequentially and tries to find squares in
// each image
#include "opencv2/core.hpp"
#include "opencv2/geometry.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;
}
+119
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;
}
@@ -0,0 +1,54 @@
/**
@file videocapture_basic.cpp
@brief A very basic sample for using VideoCapture and VideoWriter
@author PkLab.net
@date Aug 24, 2016
*/
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
int main(int, char**)
{
Mat frame;
//--- INITIALIZE VIDEOCAPTURE
VideoCapture cap;
// open the default camera using default API
// cap.open(0);
// OR advance usage: select any API backend
int deviceID = 0; // 0 = open default camera
int apiID = cv::CAP_ANY; // 0 = autodetect default API
// open selected camera using selected API
cap.open(deviceID, apiID);
// check if we succeeded
if (!cap.isOpened()) {
cerr << "ERROR! Unable to open camera\n";
return -1;
}
//--- GRAB AND WRITE LOOP
cout << "Start grabbing" << endl
<< "Press any key to terminate" << endl;
for (;;)
{
// wait for a new frame from camera and store it into 'frame'
cap.read(frame);
// check if we succeeded
if (frame.empty()) {
cerr << "ERROR! blank frame grabbed\n";
break;
}
// show live and wait for a key with timeout long enough to show images
imshow("Live", frame);
if (waitKey(5) >= 0)
break;
}
// the camera will be deinitialized automatically in VideoCapture destructor
return 0;
}
@@ -0,0 +1,187 @@
/**
@file warpPerspective_demo.cpp
@brief a demo program shows how perspective transformation applied on an image
@based on a sample code http://study.marearts.com/2015/03/image-warping-using-opencv.html
@modified by Suleyman TURKMEN
*/
#include "opencv2/geometry.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void help(char** argv)
{
// print a welcome message, and the OpenCV version
cout << "\nThis is a demo program shows how perspective transformation applied on an image, \n"
"Using OpenCV version " << CV_VERSION << endl;
cout << "\nUsage:\n" << argv[0] << " [image_name -- Default right.jpg]\n" << endl;
cout << "\nHot keys: \n"
"\tESC, q - quit the program\n"
"\tr - change order of points to rotate transformation\n"
"\tc - delete selected points\n"
"\ti - change order of points to inverse transformation \n"
"\nUse your mouse to select a point and move it to see transformation changes" << endl;
}
static void onMouse(int event, int x, int y, int, void*);
Mat warping(Mat image, Size warped_image_size, vector< Point2f> srcPoints, vector< Point2f> dstPoints);
String windowTitle = "Perspective Transformation Demo";
String labels[4] = { "TL","TR","BR","BL" };
vector< Point2f> roi_corners;
vector< Point2f> midpoints(4);
vector< Point2f> dst_corners(4);
int roiIndex = 0;
bool dragging;
int selected_corner_index = 0;
bool validation_needed = true;
int main(int argc, char** argv)
{
help(argv);
CommandLineParser parser(argc, argv, "{@input| right.jpg |}");
string filename = samples::findFile(parser.get<string>("@input"));
Mat original_image = imread( filename );
Mat image;
float original_image_cols = (float)original_image.cols;
float original_image_rows = (float)original_image.rows;
roi_corners.push_back(Point2f( (float)(original_image_cols / 1.70), (float)(original_image_rows / 4.20) ));
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.15), (float)(original_image.rows / 3.32) ));
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.33), (float)(original_image.rows / 1.10) ));
roi_corners.push_back(Point2f( (float)(original_image.cols / 1.93), (float)(original_image.rows / 1.36) ));
namedWindow(windowTitle, WINDOW_NORMAL);
namedWindow("Warped Image", WINDOW_AUTOSIZE);
moveWindow("Warped Image", 20, 20);
moveWindow(windowTitle, 330, 20);
setMouseCallback(windowTitle, onMouse, 0);
bool endProgram = false;
while (!endProgram)
{
if ( validation_needed & (roi_corners.size() < 4) )
{
validation_needed = false;
image = original_image.clone();
for (size_t i = 0; i < roi_corners.size(); ++i)
{
circle( image, roi_corners[i], 5, Scalar(0, 255, 0), 3 );
if( i > 0 )
{
line(image, roi_corners[i-1], roi_corners[(i)], Scalar(0, 0, 255), 2);
circle(image, roi_corners[i], 5, Scalar(0, 255, 0), 3);
putText(image, labels[i].c_str(), roi_corners[i], FONT_HERSHEY_SIMPLEX, 0.8, Scalar(255, 0, 0), 2);
}
}
imshow( windowTitle, image );
}
if ( validation_needed & ( roi_corners.size() == 4 ))
{
image = original_image.clone();
for ( int i = 0; i < 4; ++i )
{
line(image, roi_corners[i], roi_corners[(i + 1) % 4], Scalar(0, 0, 255), 2);
circle(image, roi_corners[i], 5, Scalar(0, 255, 0), 3);
putText(image, labels[i].c_str(), roi_corners[i], FONT_HERSHEY_SIMPLEX, 0.8, Scalar(255, 0, 0), 2);
}
imshow( windowTitle, image );
midpoints[0] = (roi_corners[0] + roi_corners[1]) / 2;
midpoints[1] = (roi_corners[1] + roi_corners[2]) / 2;
midpoints[2] = (roi_corners[2] + roi_corners[3]) / 2;
midpoints[3] = (roi_corners[3] + roi_corners[0]) / 2;
dst_corners[0].x = 0;
dst_corners[0].y = 0;
dst_corners[1].x = (float)norm(midpoints[1] - midpoints[3]);
dst_corners[1].y = 0;
dst_corners[2].x = dst_corners[1].x;
dst_corners[2].y = (float)norm(midpoints[0] - midpoints[2]);
dst_corners[3].x = 0;
dst_corners[3].y = dst_corners[2].y;
Size warped_image_size = Size(cvRound(dst_corners[2].x), cvRound(dst_corners[2].y));
Mat M = getPerspectiveTransform(roi_corners, dst_corners);
Mat warped_image;
warpPerspective(original_image, warped_image, M, warped_image_size); // do perspective transformation
imshow("Warped Image", warped_image);
}
char c = (char)waitKey( 10 );
if ((c == 'q') | (c == 'Q') | (c == 27))
{
endProgram = true;
}
if ((c == 'c') | (c == 'C'))
{
roi_corners.clear();
}
if ((c == 'r') | (c == 'R'))
{
roi_corners.push_back(roi_corners[0]);
roi_corners.erase(roi_corners.begin());
}
if ((c == 'i') | (c == 'I'))
{
swap(roi_corners[0], roi_corners[1]);
swap(roi_corners[2], roi_corners[3]);
}
}
return 0;
}
static void onMouse(int event, int x, int y, int, void*)
{
// Action when left button is pressed
if (roi_corners.size() == 4)
{
for (int i = 0; i < 4; ++i)
{
if ((event == EVENT_LBUTTONDOWN) && ((abs(roi_corners[i].x - x) < 10)) && (abs(roi_corners[i].y - y) < 10))
{
selected_corner_index = i;
dragging = true;
}
}
}
else if ( event == EVENT_LBUTTONDOWN )
{
roi_corners.push_back( Point2f( (float) x, (float) y ) );
validation_needed = true;
}
// Action when left button is released
if (event == EVENT_LBUTTONUP)
{
dragging = false;
}
// Action when left button is pressed and mouse has moved over the window
if ((event == EVENT_MOUSEMOVE) && dragging)
{
roi_corners[selected_corner_index].x = (float) x;
roi_corners[selected_corner_index].y = (float) y;
validation_needed = true;
}
}
+144
View File
@@ -0,0 +1,144 @@
#include <opencv2/core/utility.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <cstdio>
#include <iostream>
using namespace cv;
using namespace std;
static void help(char** argv)
{
cout << "\nThis program demonstrates the famous watershed segmentation algorithm in OpenCV: watershed()\n"
"Usage:\n" << argv[0] <<" [image_name -- default is fruits.jpg]\n" << endl;
cout << "Hot keys: \n"
"\tESC - quit the program\n"
"\tr - restore the original image\n"
"\tw or SPACE - run watershed segmentation algorithm\n"
"\t\t(before running it, *roughly* mark the areas to segment on the image)\n"
"\t (before that, roughly outline several markers on the image)\n";
}
Mat markerMask, img;
Point prevPt(-1, -1);
static void onMouse( int event, int x, int y, int flags, void* )
{
if( x < 0 || x >= img.cols || y < 0 || y >= img.rows )
return;
if( event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON) )
prevPt = Point(-1,-1);
else if( event == EVENT_LBUTTONDOWN )
prevPt = Point(x,y);
else if( event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON) )
{
Point pt(x, y);
if( prevPt.x < 0 )
prevPt = pt;
line( markerMask, prevPt, pt, Scalar::all(255), 5, 8, 0 );
line( img, prevPt, pt, Scalar::all(255), 5, 8, 0 );
prevPt = pt;
imshow("image", img);
}
}
int main( int argc, char** argv )
{
cv::CommandLineParser parser(argc, argv, "{help h | | }{ @input | fruits.jpg | }");
if (parser.has("help"))
{
help(argv);
return 0;
}
string filename = samples::findFile(parser.get<string>("@input"));
Mat img0 = imread(filename, IMREAD_COLOR), imgGray;
if( img0.empty() )
{
cout << "Couldn't open image ";
help(argv);
return 0;
}
help(argv);
namedWindow( "image", 1 );
img0.copyTo(img);
cvtColor(img, markerMask, COLOR_BGR2GRAY);
cvtColor(markerMask, imgGray, COLOR_GRAY2BGR);
markerMask = Scalar::all(0);
imshow( "image", img );
setMouseCallback( "image", onMouse, 0 );
for(;;)
{
char c = (char)waitKey(0);
if( c == 27 )
break;
if( c == 'r' )
{
markerMask = Scalar::all(0);
img0.copyTo(img);
imshow( "image", img );
}
if( c == 'w' || c == ' ' )
{
int i, j, compCount = 0;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(markerMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
if( contours.empty() )
continue;
Mat markers(markerMask.size(), CV_32S);
markers = Scalar::all(0);
int idx = 0;
for( ; idx >= 0; idx = hierarchy[idx][0], compCount++ )
drawContours(markers, contours, idx, Scalar::all(compCount+1), -1, 8, hierarchy, INT_MAX);
if( compCount == 0 )
continue;
vector<Vec3b> colorTab;
for( i = 0; i < compCount; i++ )
{
int b = theRNG().uniform(0, 255);
int g = theRNG().uniform(0, 255);
int r = theRNG().uniform(0, 255);
colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
double t = (double)getTickCount();
watershed( img0, markers );
t = (double)getTickCount() - t;
printf( "execution time = %gms\n", t*1000./getTickFrequency() );
Mat wshed(markers.size(), CV_8UC3);
// paint the watershed image
for( i = 0; i < markers.rows; i++ )
for( j = 0; j < markers.cols; j++ )
{
int index = markers.at<int>(i,j);
if( index == -1 )
wshed.at<Vec3b>(i,j) = Vec3b(255,255,255);
else if( index <= 0 || index > compCount )
wshed.at<Vec3b>(i,j) = Vec3b(0,0,0);
else
wshed.at<Vec3b>(i,j) = colorTab[index - 1];
}
wshed = wshed*0.5 + imgGray*0.5;
imshow( "watershed transform", wshed );
}
}
return 0;
}
+462
View File
@@ -0,0 +1,462 @@
/* 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/geometry.hpp"
#include "opencv2/stereo.hpp"
#include "opencv2/calib.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/objdetect.hpp"
#include "opencv2/objdetect/charuco_detector.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 or ChArUco images, the number of corners (nx, ny)\n"
" on the chessboards and the number of squares (nx, ny) on ChArUco,\n"
" 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>"
<<" -t=<pattern type: chessboard or charucoboard default=chessboard> -s=<square_size default=1.0> -ms=<marker size default=0.5>"
<<" -ad=<predefined aruco dictionary name default=DICT_4X4_50> -adf=<aruco dictionary file default=None>"
<<" <image list XML/YML file default=stereo_calib.xml>\n" << endl;
cout << "Available Aruco dictionaries: DICT_4X4_50, DICT_4X4_100, DICT_4X4_250, "
<< "DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, "
<< "DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, "
<< "DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, "
<< "DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11, DICT_ARUCO_MIP_36h12\n";
return 0;
}
static void
StereoCalib(const vector<string>& imagelist, Size inputBoardSize, string type, float squareSize, float markerSize, cv::aruco::PredefinedDictionaryType arucoDict, string arucoDictFile, 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;
Size boardSizeInnerCorners, boardSizeUnits;
if (type == "chessboard") {
//chess board pattern boardSize is given in inner corners
boardSizeInnerCorners = inputBoardSize;
boardSizeUnits.height = inputBoardSize.height+1;
boardSizeUnits.width = inputBoardSize.width+1;
}
else if (type == "charucoboard") {
//ChArUco board pattern boardSize is given in squares units
boardSizeUnits = inputBoardSize;
boardSizeInnerCorners.width = inputBoardSize.width - 1;
boardSizeInnerCorners.height = inputBoardSize.height - 1;
}
else {
std::cout << "unknown pattern type " << type << "\n";
return;
}
cv::aruco::Dictionary dictionary;
if (arucoDictFile == "None") {
dictionary = cv::aruco::getPredefinedDictionary(arucoDict);
}
else {
cv::FileStorage dict_file(arucoDictFile, cv::FileStorage::Mode::READ);
cv::FileNode fn(dict_file.root());
dictionary.readDictionary(fn);
}
cv::aruco::CharucoBoard ch_board(boardSizeUnits, squareSize, markerSize, dictionary);
cv::aruco::CharucoDetector ch_detector(ch_board);
std::vector<int> markerIds;
for( i = j = 0; i < nimages; i++ )
{
for( k = 0; k < 2; k++ )
{
const string& filename = imagelist[i*2+k];
Mat img = imread(filename, IMREAD_GRAYSCALE);
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);
if (type == "chessboard") {
found = findChessboardCorners(timg, boardSizeInnerCorners, corners,
CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
}
else if (type == "charucoboard") {
ch_detector.detectBoard(timg, corners, markerIds);
found = corners.size() == (size_t) (boardSizeInnerCorners.height*boardSizeInnerCorners.width);
}
else {
cout << "Error: unknown pattern " << type << "\n";
return;
}
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, boardSizeInnerCorners, 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;
if (type == "chessboard") {
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 < boardSizeInnerCorners.height; j++ )
for( k = 0; k < boardSizeInnerCorners.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], IMREAD_GRAYSCALE), 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 inputBoardSize;
string imagelistfn;
bool showRectified;
cv::CommandLineParser parser(argc, argv, "{w|9|}{h|6|}{t|chessboard|}{s|1.0|}{ms|0.5|}{ad|DICT_4X4_50|}{adf|None|}{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"));
inputBoardSize.width = parser.get<int>("w");
inputBoardSize.height = parser.get<int>("h");
string type = parser.get<string>("t");
float squareSize = parser.get<float>("s");
float markerSize = parser.get<float>("ms");
string arucoDictName = parser.get<string>("ad");
string arucoDictFile = parser.get<string>("adf");
cv::aruco::PredefinedDictionaryType arucoDict;
if (arucoDictName == "DICT_4X4_50") { arucoDict = cv::aruco::DICT_4X4_50; }
else if (arucoDictName == "DICT_4X4_100") { arucoDict = cv::aruco::DICT_4X4_100; }
else if (arucoDictName == "DICT_4X4_250") { arucoDict = cv::aruco::DICT_4X4_250; }
else if (arucoDictName == "DICT_4X4_1000") { arucoDict = cv::aruco::DICT_4X4_1000; }
else if (arucoDictName == "DICT_5X5_50") { arucoDict = cv::aruco::DICT_5X5_50; }
else if (arucoDictName == "DICT_5X5_100") { arucoDict = cv::aruco::DICT_5X5_100; }
else if (arucoDictName == "DICT_5X5_250") { arucoDict = cv::aruco::DICT_5X5_250; }
else if (arucoDictName == "DICT_5X5_1000") { arucoDict = cv::aruco::DICT_5X5_1000; }
else if (arucoDictName == "DICT_6X6_50") { arucoDict = cv::aruco::DICT_6X6_50; }
else if (arucoDictName == "DICT_6X6_100") { arucoDict = cv::aruco::DICT_6X6_100; }
else if (arucoDictName == "DICT_6X6_250") { arucoDict = cv::aruco::DICT_6X6_250; }
else if (arucoDictName == "DICT_6X6_1000") { arucoDict = cv::aruco::DICT_6X6_1000; }
else if (arucoDictName == "DICT_7X7_50") { arucoDict = cv::aruco::DICT_7X7_50; }
else if (arucoDictName == "DICT_7X7_100") { arucoDict = cv::aruco::DICT_7X7_100; }
else if (arucoDictName == "DICT_7X7_250") { arucoDict = cv::aruco::DICT_7X7_250; }
else if (arucoDictName == "DICT_7X7_1000") { arucoDict = cv::aruco::DICT_7X7_1000; }
else if (arucoDictName == "DICT_ARUCO_ORIGINAL") { arucoDict = cv::aruco::DICT_ARUCO_ORIGINAL; }
else if (arucoDictName == "DICT_APRILTAG_16h5") { arucoDict = cv::aruco::DICT_APRILTAG_16h5; }
else if (arucoDictName == "DICT_APRILTAG_25h9") { arucoDict = cv::aruco::DICT_APRILTAG_25h9; }
else if (arucoDictName == "DICT_APRILTAG_36h10") { arucoDict = cv::aruco::DICT_APRILTAG_36h10; }
else if (arucoDictName == "DICT_APRILTAG_36h11") { arucoDict = cv::aruco::DICT_APRILTAG_36h11; }
else if (arucoDictName == "DICT_ARUCO_MIP_36h12") { arucoDict = cv::aruco::DICT_ARUCO_MIP_36h12; }
else {
cout << "incorrect name of aruco dictionary \n";
return 1;
}
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, inputBoardSize, type, squareSize, markerSize, arucoDict, arucoDictFile, false, true, showRectified);
return 0;
}
+328
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/geometry.hpp"
#include "opencv2/stereo.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, STEREO_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;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,74 @@
/**
* @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 pos, void* userdata) {
(void) userdata;
alpha = (double)pos / 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 must 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 trackbar value
alpha_slider = 0;
//![window]
namedWindow("Linear Blend", WINDOW_AUTOSIZE); //Create Window
//![window]
//![create_trackbar]
char TrackbarName[50];
snprintf(TrackbarName, sizeof(TrackbarName), "Alpha x %d", alpha_slider_max);
// Example userdata: Pass a pointer to an integer as userdata
createTrackbar(TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar);
//![create_trackbar]
/// Show initial result
on_trackbar(alpha_slider, nullptr);
/// Wait for user input
waitKey(0);
return 0;
}
@@ -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;
}
@@ -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;
}
@@ -0,0 +1,139 @@
/**
* @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* );
const char* keys =
"{ help h| | Print help message. }"
"{ @input1 | Template_Matching_Original_Image.jpg | image_name }"
"{ @input2 | Template_Matching_Template_Image.jpg | template_name }"
"{ @input3 | | mask_name }";
/**
* @function main
*/
int main( int argc, char** argv )
{
CommandLineParser parser( argc, argv, keys );
samples::addSamplesDataSearchSubDirectory( "doc/tutorials/imgproc/histograms/template_matching/images" );
//! [load_image]
/// Load image and template
img = imread( samples::findFile( parser.get<String>("@input1") ) );
templ = imread( samples::findFile( parser.get<String>("@input2") ), IMREAD_COLOR );
if(argc > 3) {
use_mask = true;
mask = imread(samples::findFile( parser.get<String>("@input3") ), 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;
}
@@ -0,0 +1,107 @@
/**
* @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 |Back_Projection_Theory0.jpg| input image}" );
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/histograms/back_projection/images");
Mat src = imread(samples::findFile(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]
}
@@ -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 );
}
@@ -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;
}
@@ -0,0 +1,96 @@
/**
* @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 |Histogram_Comparison_Source_0.jpg | Path to input image 1. }"
"{ @input2 |Histogram_Comparison_Source_1.jpg | Path to input image 2. }"
"{ @input3 |Histogram_Comparison_Source_2.jpg | 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 );
samples::addSamplesDataSearchSubDirectory( "doc/tutorials/imgproc/histograms/histogram_comparison/images" );
Mat src_base = imread(samples::findFile( parser.get<String>( "@input1" ) ) );
Mat src_test1 = imread(samples::findFile( parser.get<String>( "@input2" ) ) );
Mat src_test2 = imread(samples::findFile( 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, 1, 0, NORM_L1, -1, Mat() );
calcHist( &hsv_half_down, 1, channels, Mat(), hist_half_down, 2, histSize, ranges, true, false );
normalize( hist_half_down, hist_half_down, 1, 0, NORM_L1, -1, Mat() );
calcHist( &hsv_test1, 1, channels, Mat(), hist_test1, 2, histSize, ranges, true, false );
normalize( hist_test1, hist_test1, 1, 0, NORM_L1, -1, Mat() );
calcHist( &hsv_test2, 1, channels, Mat(), hist_test2, 2, histSize, ranges, true, false );
normalize( hist_test2, hist_test2, 1, 0, NORM_L1, -1, Mat() );
//! [Calculate the histograms for the HSV images]
//! [Apply the histogram comparison methods]
for( int compare_method = 0; compare_method < 6; 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;
}
@@ -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;
}
@@ -0,0 +1,46 @@
#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;
}
@@ -0,0 +1,120 @@
/**
* @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 = 3;
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 \n 3: Diamond", "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 \n 3: Diamond", "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; }
else if( erosion_elem == 3) { erosion_type = MORPH_DIAMOND; }
//![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; }
else if( dilation_elem == 3) { dilation_type = MORPH_DIAMOND; }
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]
@@ -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 = 3;
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 - 3: Diamond", 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]
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -0,0 +1,120 @@
/**
* @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/highgui.hpp"
#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
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/anisotropic_image_segmentation/images");
Mat imgIn = imread(samples::findFile("gst_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, CV_8U);
normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAX, CV_8U);
imshow("Original", imgIn);
imshow("Result", 0.5 * (imgIn + imgBin));
imshow("Coherency", imgCoherency);
imshow("Orientation", imgOrientation);
imwrite("result.jpg", 0.5*(imgIn + imgBin));
imwrite("Coherency.jpg", imgCoherency);
imwrite("Orientation.jpg", imgOrientation);
waitKey(0);
//! [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]
@@ -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]
@@ -0,0 +1,326 @@
/**
* @file Drawing_2.cpp
* @brief Simple sample code
*/
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
/// Global Variables
const int NUMBER = 100;
const int DELAY = 5;
const int window_width = 900;
const int window_height = 600;
int x_1 = -window_width/2;
int x_2 = window_width*3/2;
int y_1 = -window_width/2;
int y_2 = window_width*3/2;
/// Function headers
static Scalar randomColor( RNG& rng );
int Drawing_Random_Lines( Mat image, char* window_name, RNG rng );
int Drawing_Random_Rectangles( Mat image, char* window_name, RNG rng );
int Drawing_Random_Ellipses( Mat image, char* window_name, RNG rng );
int Drawing_Random_Polylines( Mat image, char* window_name, RNG rng );
int Drawing_Random_Filled_Polygons( Mat image, char* window_name, RNG rng );
int Drawing_Random_Circles( Mat image, char* window_name, RNG rng );
int Displaying_Random_Text( Mat image, char* window_name, RNG rng );
int Displaying_Big_End( Mat image, char* window_name, RNG rng );
/**
* @function main
*/
int main( void )
{
int c;
/// Start creating a window
char window_name[] = "Drawing_2 Tutorial";
/// Also create a random object (RNG)
RNG rng( 0xFFFFFFFF );
/// Initialize a matrix filled with zeros
Mat image = Mat::zeros( window_height, window_width, CV_8UC3 );
/// Show it in a window during DELAY ms
imshow( window_name, image );
waitKey( DELAY );
/// Now, let's draw some lines
c = Drawing_Random_Lines(image, window_name, rng);
if( c != 0 ) return 0;
/// Go on drawing, this time nice rectangles
c = Drawing_Random_Rectangles(image, window_name, rng);
if( c != 0 ) return 0;
/// Draw some ellipses
c = Drawing_Random_Ellipses( image, window_name, rng );
if( c != 0 ) return 0;
/// Now some polylines
c = Drawing_Random_Polylines( image, window_name, rng );
if( c != 0 ) return 0;
/// Draw filled polygons
c = Drawing_Random_Filled_Polygons( image, window_name, rng );
if( c != 0 ) return 0;
/// Draw circles
c = Drawing_Random_Circles( image, window_name, rng );
if( c != 0 ) return 0;
/// Display text in random positions
c = Displaying_Random_Text( image, window_name, rng );
if( c != 0 ) return 0;
/// Displaying the big end!
c = Displaying_Big_End( image, window_name, rng );
if( c != 0 ) return 0;
waitKey(0);
return 0;
}
/// Function definitions
/**
* @function randomColor
* @brief Produces a random color given a random object
*/
static Scalar randomColor( RNG& rng )
{
int icolor = (unsigned) rng;
return Scalar( icolor&255, (icolor>>8)&255, (icolor>>16)&255 );
}
/**
* @function Drawing_Random_Lines
*/
int Drawing_Random_Lines( Mat image, char* window_name, RNG rng )
{
Point pt1, pt2;
for( int i = 0; i < NUMBER; i++ )
{
pt1.x = rng.uniform( x_1, x_2 );
pt1.y = rng.uniform( y_1, y_2 );
pt2.x = rng.uniform( x_1, x_2 );
pt2.y = rng.uniform( y_1, y_2 );
line( image, pt1, pt2, randomColor(rng), rng.uniform(1, 10), 8 );
imshow( window_name, image );
if( waitKey( DELAY ) >= 0 )
{ return -1; }
}
return 0;
}
/**
* @function Drawing_Rectangles
*/
int Drawing_Random_Rectangles( Mat image, char* window_name, RNG rng )
{
Point pt1, pt2;
int lineType = 8;
int thickness = rng.uniform( -3, 10 );
for( int i = 0; i < NUMBER; i++ )
{
pt1.x = rng.uniform( x_1, x_2 );
pt1.y = rng.uniform( y_1, y_2 );
pt2.x = rng.uniform( x_1, x_2 );
pt2.y = rng.uniform( y_1, y_2 );
rectangle( image, pt1, pt2, randomColor(rng), MAX( thickness, -1 ), lineType );
imshow( window_name, image );
if( waitKey( DELAY ) >= 0 )
{ return -1; }
}
return 0;
}
/**
* @function Drawing_Random_Ellipses
*/
int Drawing_Random_Ellipses( Mat image, char* window_name, RNG rng )
{
int lineType = 8;
for ( int i = 0; i < NUMBER; i++ )
{
Point center;
center.x = rng.uniform(x_1, x_2);
center.y = rng.uniform(y_1, y_2);
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( window_name, image );
if( waitKey(DELAY) >= 0 )
{ return -1; }
}
return 0;
}
/**
* @function Drawing_Random_Polylines
*/
int Drawing_Random_Polylines( Mat image, char* window_name, RNG rng )
{
int lineType = 8;
for( int i = 0; i< NUMBER; i++ )
{
Point pt[2][3];
pt[0][0].x = rng.uniform(x_1, x_2);
pt[0][0].y = rng.uniform(y_1, y_2);
pt[0][1].x = rng.uniform(x_1, x_2);
pt[0][1].y = rng.uniform(y_1, y_2);
pt[0][2].x = rng.uniform(x_1, x_2);
pt[0][2].y = rng.uniform(y_1, y_2);
pt[1][0].x = rng.uniform(x_1, x_2);
pt[1][0].y = rng.uniform(y_1, y_2);
pt[1][1].x = rng.uniform(x_1, x_2);
pt[1][1].y = rng.uniform(y_1, y_2);
pt[1][2].x = rng.uniform(x_1, x_2);
pt[1][2].y = rng.uniform(y_1, y_2);
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( window_name, image );
if( waitKey(DELAY) >= 0 )
{ return -1; }
}
return 0;
}
/**
* @function Drawing_Random_Filled_Polygons
*/
int Drawing_Random_Filled_Polygons( Mat image, char* window_name, RNG rng )
{
int lineType = 8;
for ( int i = 0; i < NUMBER; i++ )
{
Point pt[2][3];
pt[0][0].x = rng.uniform(x_1, x_2);
pt[0][0].y = rng.uniform(y_1, y_2);
pt[0][1].x = rng.uniform(x_1, x_2);
pt[0][1].y = rng.uniform(y_1, y_2);
pt[0][2].x = rng.uniform(x_1, x_2);
pt[0][2].y = rng.uniform(y_1, y_2);
pt[1][0].x = rng.uniform(x_1, x_2);
pt[1][0].y = rng.uniform(y_1, y_2);
pt[1][1].x = rng.uniform(x_1, x_2);
pt[1][1].y = rng.uniform(y_1, y_2);
pt[1][2].x = rng.uniform(x_1, x_2);
pt[1][2].y = rng.uniform(y_1, y_2);
const Point* ppt[2] = {pt[0], pt[1]};
int npt[] = {3, 3};
fillPoly( image, ppt, npt, 2, randomColor(rng), lineType );
imshow( window_name, image );
if( waitKey(DELAY) >= 0 )
{ return -1; }
}
return 0;
}
/**
* @function Drawing_Random_Circles
*/
int Drawing_Random_Circles( Mat image, char* window_name, RNG rng )
{
int lineType = 8;
for (int i = 0; i < NUMBER; i++)
{
Point center;
center.x = rng.uniform(x_1, x_2);
center.y = rng.uniform(y_1, y_2);
circle( image, center, rng.uniform(0, 300), randomColor(rng),
rng.uniform(-1, 9), lineType );
imshow( window_name, image );
if( waitKey(DELAY) >= 0 )
{ return -1; }
}
return 0;
}
/**
* @function Displaying_Random_Text
*/
int Displaying_Random_Text( Mat image, char* window_name, RNG rng )
{
int lineType = 8;
for ( int i = 1; i < NUMBER; i++ )
{
Point org;
org.x = rng.uniform(x_1, x_2);
org.y = rng.uniform(y_1, y_2);
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( window_name, image );
if( waitKey(DELAY) >= 0 )
{ return -1; }
}
return 0;
}
/**
* @function Displaying_Big_End
*/
int Displaying_Big_End( Mat image, char* window_name, RNG )
{
Size textsize = getTextSize("OpenCV forever!", FONT_HERSHEY_COMPLEX, 3, 5, 0);
Point org((window_width - textsize.width)/2, (window_height - textsize.height)/2);
int lineType = 8;
Mat image2;
for( int 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( window_name, image2 );
if( waitKey(DELAY) >= 0 )
{ return -1; }
}
return 0;
}
@@ -0,0 +1,98 @@
#include <iostream>
#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 std::cout;
using std::endl;
using namespace cv;
namespace
{
/** Global Variables */
int alpha = 100;
int beta = 100;
int gamma_cor = 100;
Mat img_original, img_corrected, img_gamma_corrected;
void basicLinearTransform(const Mat &img, const double alpha_, const int beta_)
{
Mat res;
img.convertTo(res, -1, alpha_, beta_);
hconcat(img, res, img_corrected);
imshow("Brightness and contrast adjustments", img_corrected);
}
void gammaCorrection(const Mat &img, const double gamma_)
{
CV_Assert(gamma_ >= 0);
//! [changing-contrast-brightness-gamma-correction]
Mat lookUpTable(1, 256, CV_8U);
uchar* p = lookUpTable.ptr();
for( int i = 0; i < 256; ++i)
p[i] = saturate_cast<uchar>(pow(i / 255.0, gamma_) * 255.0);
Mat res = img.clone();
LUT(img, lookUpTable, res);
//! [changing-contrast-brightness-gamma-correction]
hconcat(img, res, img_gamma_corrected);
imshow("Gamma correction", img_gamma_corrected);
}
void on_linear_transform_alpha_trackbar(int, void *)
{
double alpha_value = alpha / 100.0;
int beta_value = beta - 100;
basicLinearTransform(img_original, alpha_value, beta_value);
}
void on_linear_transform_beta_trackbar(int, void *)
{
double alpha_value = alpha / 100.0;
int beta_value = beta - 100;
basicLinearTransform(img_original, alpha_value, beta_value);
}
void on_gamma_correction_trackbar(int, void *)
{
double gamma_value = gamma_cor / 100.0;
gammaCorrection(img_original, gamma_value);
}
}
int main( int argc, char** argv )
{
CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
img_original = imread( samples::findFile( parser.get<String>( "@input" ) ) );
if( img_original.empty() )
{
cout << "Could not open or find the image!\n" << endl;
cout << "Usage: " << argv[0] << " <Input image>" << endl;
return -1;
}
img_corrected = Mat(img_original.rows, img_original.cols*2, img_original.type());
img_gamma_corrected = Mat(img_original.rows, img_original.cols*2, img_original.type());
hconcat(img_original, img_original, img_corrected);
hconcat(img_original, img_original, img_gamma_corrected);
namedWindow("Brightness and contrast adjustments");
namedWindow("Gamma correction");
createTrackbar("Alpha gain (contrast)", "Brightness and contrast adjustments", &alpha, 500, on_linear_transform_alpha_trackbar);
createTrackbar("Beta bias (brightness)", "Brightness and contrast adjustments", &beta, 200, on_linear_transform_beta_trackbar);
createTrackbar("Gamma correction", "Gamma correction", &gamma_cor, 200, on_gamma_correction_trackbar);
on_linear_transform_alpha_trackbar(0, 0);
on_gamma_correction_trackbar(0, 0);
waitKey();
imwrite("linear_transform_correction.png", img_corrected);
imwrite("gamma_correction.png", img_gamma_corrected);
return 0;
}
@@ -0,0 +1,139 @@
/**
* @file Morphology_3(Extract_Lines).cpp
* @brief Use morphology transformations for extracting horizontal and vertical lines sample code
* @author OpenCV team
*/
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
void show_wait_destroy(const char* winname, cv::Mat img);
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
//! [load_image]
CommandLineParser parser(argc, argv, "{@input | notes.png | 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;
}
// Show source image
imshow("src", src);
//! [load_image]
//! [gray]
// Transform source image to gray if it is not already
Mat gray;
if (src.channels() == 3)
{
cvtColor(src, gray, COLOR_BGR2GRAY);
}
else
{
gray = src;
}
// Show gray image
show_wait_destroy("gray", gray);
//! [gray]
//! [bin]
// Apply adaptiveThreshold at the bitwise_not of gray, notice the ~ symbol
Mat bw;
adaptiveThreshold(~gray, bw, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
// Show binary image
show_wait_destroy("binary", bw);
//! [bin]
//! [init]
// Create the images that will use to extract the horizontal and vertical lines
Mat horizontal = bw.clone();
Mat vertical = bw.clone();
//! [init]
//! [horiz]
// Specify size on horizontal axis
int horizontal_size = horizontal.cols / 30;
// Create structure element for extracting horizontal lines through morphology operations
Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontal_size, 1));
// Apply morphology operations
erode(horizontal, horizontal, horizontalStructure, Point(-1, -1));
dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1));
// Show extracted horizontal lines
show_wait_destroy("horizontal", horizontal);
//! [horiz]
//! [vert]
// Specify size on vertical axis
int vertical_size = vertical.rows / 30;
// Create structure element for extracting vertical lines through morphology operations
Mat verticalStructure = getStructuringElement(MORPH_RECT, Size(1, vertical_size));
// Apply morphology operations
erode(vertical, vertical, verticalStructure, Point(-1, -1));
dilate(vertical, vertical, verticalStructure, Point(-1, -1));
// Show extracted vertical lines
show_wait_destroy("vertical", vertical);
//! [vert]
//! [smooth]
// Inverse vertical image
bitwise_not(vertical, vertical);
show_wait_destroy("vertical_bit", vertical);
// Extract edges and smooth image according to the logic
// 1. extract edges
// 2. dilate(edges)
// 3. src.copyTo(smooth)
// 4. blur smooth img
// 5. smooth.copyTo(src, edges)
// Step 1
Mat edges;
adaptiveThreshold(vertical, edges, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 3, -2);
show_wait_destroy("edges", edges);
// Step 2
Mat kernel = Mat::ones(2, 2, CV_8UC1);
dilate(edges, edges, kernel);
show_wait_destroy("dilate", edges);
// Step 3
Mat smooth;
vertical.copyTo(smooth);
// Step 4
blur(smooth, smooth, Size(2, 2));
// Step 5
smooth.copyTo(vertical, edges);
// Show final result
show_wait_destroy("smooth - final", vertical);
//! [smooth]
return 0;
}
void show_wait_destroy(const char* winname, cv::Mat img) {
imshow(winname, img);
moveWindow(winname, 500, 0);
waitKey(0);
destroyWindow(winname);
}
@@ -0,0 +1,184 @@
/**
* @brief You will learn how to recover an image with motion blur distortion using a Wiener filter
* @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;
void help();
void calcPSF(Mat& outputImg, Size filterSize, int len, double theta);
void fftshift(const Mat& inputImg, Mat& outputImg);
void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H);
void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr);
void edgetaper(const Mat& inputImg, Mat& outputImg, double gamma = 5.0, double beta = 0.2);
const String keys =
"{help h usage ? | | print this message }"
"{image |input.png | input image name }"
"{LEN |125 | length of a motion }"
"{THETA |0 | angle of a motion in degrees }"
"{SNR |700 | signal to noise ratio }"
;
int main(int argc, char *argv[])
{
help();
CommandLineParser parser(argc, argv, keys);
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
int LEN = parser.get<int>("LEN");
double THETA = parser.get<double>("THETA");
int snr = parser.get<int>("SNR");
string strInFileName = parser.get<String>("image");
if (!parser.check())
{
parser.printErrors();
return 0;
}
Mat imgIn;
imgIn = imread(strInFileName, IMREAD_GRAYSCALE);
if (imgIn.empty()) //check whether the image is loaded or not
{
cout << "ERROR : Image cannot be loaded..!!" << endl;
return -1;
}
Mat imgOut;
//! [main]
// it needs to process even image only
Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2);
//Hw calculation (start)
Mat Hw, h;
calcPSF(h, roi.size(), LEN, THETA);
calcWnrFilter(h, Hw, 1.0 / double(snr));
//Hw calculation (stop)
imgIn.convertTo(imgIn, CV_32F);
edgetaper(imgIn, imgIn);
// filtering (start)
filter2DFreq(imgIn(roi), imgOut, Hw);
// filtering (stop)
//! [main]
imgOut.convertTo(imgOut, CV_8U);
normalize(imgOut, imgOut, 0, 255, NORM_MINMAX);
imwrite("result.jpg", imgOut);
return 0;
}
void help()
{
cout << "2018-08-14" << endl;
cout << "Motion_deblur_v2" << endl;
cout << "You will learn how to recover an image with motion blur distortion using a Wiener filter" << endl;
}
//! [calcPSF]
void calcPSF(Mat& outputImg, Size filterSize, int len, double theta)
{
Mat h(filterSize, CV_32F, Scalar(0));
Point point(filterSize.width / 2, filterSize.height / 2);
ellipse(h, point, Size(0, cvRound(float(len) / 2.0)), 90.0 - theta, 0, 360, Scalar(255), FILLED);
Scalar summa = sum(h);
outputImg = h / summa[0];
}
//! [calcPSF]
//! [fftshift]
void fftshift(const Mat& inputImg, Mat& outputImg)
{
outputImg = inputImg.clone();
int cx = outputImg.cols / 2;
int cy = outputImg.rows / 2;
Mat q0(outputImg, Rect(0, 0, cx, cy));
Mat q1(outputImg, Rect(cx, 0, cx, cy));
Mat q2(outputImg, Rect(0, cy, cx, cy));
Mat q3(outputImg, Rect(cx, cy, cx, cy));
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
//! [fftshift]
//! [filter2DFreq]
void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H)
{
Mat planes[2] = { Mat_<float>(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
dft(complexI, complexI, DFT_SCALE);
Mat planesH[2] = { Mat_<float>(H.clone()), Mat::zeros(H.size(), CV_32F) };
Mat complexH;
merge(planesH, 2, complexH);
Mat complexIH;
mulSpectrums(complexI, complexH, complexIH, 0);
idft(complexIH, complexIH);
split(complexIH, planes);
outputImg = planes[0];
}
//! [filter2DFreq]
//! [calcWnrFilter]
void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr)
{
Mat h_PSF_shifted;
fftshift(input_h_PSF, h_PSF_shifted);
Mat planes[2] = { Mat_<float>(h_PSF_shifted.clone()), Mat::zeros(h_PSF_shifted.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
dft(complexI, complexI);
split(complexI, planes);
Mat denom;
pow(abs(planes[0]), 2, denom);
denom += nsr;
divide(planes[0], denom, output_G);
}
//! [calcWnrFilter]
//! [edgetaper]
void edgetaper(const Mat& inputImg, Mat& outputImg, double gamma, double beta)
{
int Nx = inputImg.cols;
int Ny = inputImg.rows;
Mat w1(1, Nx, CV_32F, Scalar(0));
Mat w2(Ny, 1, CV_32F, Scalar(0));
float* p1 = w1.ptr<float>(0);
float* p2 = w2.ptr<float>(0);
float dx = float(2.0 * CV_PI / Nx);
float x = float(-CV_PI);
for (int i = 0; i < Nx; i++)
{
p1[i] = float(0.5 * (tanh((x + gamma / 2) / beta) - tanh((x - gamma / 2) / beta)));
x += dx;
}
float dy = float(2.0 * CV_PI / Ny);
float y = float(-CV_PI);
for (int i = 0; i < Ny; i++)
{
p2[i] = float(0.5 * (tanh((y + gamma / 2) / beta) - tanh((y - gamma / 2) / beta)));
y += dy;
}
Mat w = w2 * w1;
multiply(inputImg, w, outputImg);
}
//! [edgetaper]
@@ -0,0 +1,154 @@
/**
* @brief You will learn how to recover an out-of-focus image by Wiener filter
* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin
*/
#include <iostream>
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
using namespace cv;
using namespace std;
void help();
void calcPSF(Mat& outputImg, Size filterSize, int R);
void fftshift(const Mat& inputImg, Mat& outputImg);
void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H);
void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr);
const String keys =
"{help h usage ? | | print this message }"
"{image |original.jpg | input image name }"
"{R |5 | radius }"
"{SNR |100 | signal to noise ratio}"
;
int main(int argc, char *argv[])
{
help();
CommandLineParser parser(argc, argv, keys);
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
int R = parser.get<int>("R");
int snr = parser.get<int>("SNR");
string strInFileName = parser.get<String>("image");
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/out_of_focus_deblur_filter/images");
if (!parser.check())
{
parser.printErrors();
return 0;
}
Mat imgIn;
imgIn = imread(samples::findFile( strInFileName ), IMREAD_GRAYSCALE);
if (imgIn.empty()) //check whether the image is loaded or not
{
cout << "ERROR : Image cannot be loaded..!!" << endl;
return -1;
}
Mat imgOut;
//! [main]
// it needs to process even image only
Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2);
//Hw calculation (start)
Mat Hw, h;
calcPSF(h, roi.size(), R);
calcWnrFilter(h, Hw, 1.0 / double(snr));
//Hw calculation (stop)
// filtering (start)
filter2DFreq(imgIn(roi), imgOut, Hw);
// filtering (stop)
//! [main]
imgOut.convertTo(imgOut, CV_8U);
normalize(imgOut, imgOut, 0, 255, NORM_MINMAX);
imshow("Original", imgIn);
imshow("Debluring", imgOut);
imwrite("result.jpg", imgOut);
waitKey(0);
return 0;
}
void help()
{
cout << "2018-07-12" << endl;
cout << "DeBlur_v8" << endl;
cout << "You will learn how to recover an out-of-focus image by Wiener filter" << endl;
}
//! [calcPSF]
void calcPSF(Mat& outputImg, Size filterSize, int R)
{
Mat h(filterSize, CV_32F, Scalar(0));
Point point(filterSize.width / 2, filterSize.height / 2);
circle(h, point, R, 255, -1, 8);
Scalar summa = sum(h);
outputImg = h / summa[0];
}
//! [calcPSF]
//! [fftshift]
void fftshift(const Mat& inputImg, Mat& outputImg)
{
outputImg = inputImg.clone();
int cx = outputImg.cols / 2;
int cy = outputImg.rows / 2;
Mat q0(outputImg, Rect(0, 0, cx, cy));
Mat q1(outputImg, Rect(cx, 0, cx, cy));
Mat q2(outputImg, Rect(0, cy, cx, cy));
Mat q3(outputImg, Rect(cx, cy, cx, cy));
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
//! [fftshift]
//! [filter2DFreq]
void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H)
{
Mat planes[2] = { Mat_<float>(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
dft(complexI, complexI, DFT_SCALE);
Mat planesH[2] = { Mat_<float>(H.clone()), Mat::zeros(H.size(), CV_32F) };
Mat complexH;
merge(planesH, 2, complexH);
Mat complexIH;
mulSpectrums(complexI, complexH, complexIH, 0);
idft(complexIH, complexIH);
split(complexIH, planes);
outputImg = planes[0];
}
//! [filter2DFreq]
//! [calcWnrFilter]
void calcWnrFilter(const Mat& input_h_PSF, Mat& output_G, double nsr)
{
Mat h_PSF_shifted;
fftshift(input_h_PSF, h_PSF_shifted);
Mat planes[2] = { Mat_<float>(h_PSF_shifted.clone()), Mat::zeros(h_PSF_shifted.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
dft(complexI, complexI);
split(complexI, planes);
Mat denom;
pow(abs(planes[0]), 2, denom);
denom += nsr;
divide(planes[0], denom, output_G);
}
//! [calcWnrFilter]
@@ -0,0 +1,161 @@
/**
* @brief You will learn how to remove periodic noise in the Fourier domain
* @author Karpushin Vladislav, karpushin@ngs.ru, https://github.com/VladKarpushin
*/
#include <iostream>
#include "opencv2/highgui.hpp"
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
void fftshift(const Mat& inputImg, Mat& outputImg);
void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H);
void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius);
void calcPSD(const Mat& inputImg, Mat& outputImg, int flag = 0);
const String keys =
"{help h usage ? | | print this message }"
"{@image |period_input.jpg | input image name }"
;
int main(int argc, char* argv[])
{
CommandLineParser parser(argc, argv, keys);
string strInFileName = parser.get<String>("@image");
samples::addSamplesDataSearchSubDirectory("doc/tutorials/imgproc/periodic_noise_removing_filter/images");
Mat imgIn = imread(samples::findFile(strInFileName), IMREAD_GRAYSCALE);
if (imgIn.empty()) //check whether the image is loaded or not
{
cout << "ERROR : Image cannot be loaded..!!" << endl;
return -1;
}
imshow("Image corrupted", imgIn);
imgIn.convertTo(imgIn, CV_32F);
//! [main]
// it needs to process even image only
Rect roi = Rect(0, 0, imgIn.cols & -2, imgIn.rows & -2);
imgIn = imgIn(roi);
// PSD calculation (start)
Mat imgPSD;
calcPSD(imgIn, imgPSD);
fftshift(imgPSD, imgPSD);
normalize(imgPSD, imgPSD, 0, 255, NORM_MINMAX);
// PSD calculation (stop)
//H calculation (start)
Mat H = Mat(roi.size(), CV_32F, Scalar(1));
const int r = 21;
synthesizeFilterH(H, Point(705, 458), r);
synthesizeFilterH(H, Point(850, 391), r);
synthesizeFilterH(H, Point(993, 325), r);
//H calculation (stop)
// filtering (start)
Mat imgOut;
fftshift(H, H);
filter2DFreq(imgIn, imgOut, H);
// filtering (stop)
//! [main]
imgOut.convertTo(imgOut, CV_8U);
normalize(imgOut, imgOut, 0, 255, NORM_MINMAX);
imwrite("result.jpg", imgOut);
imwrite("PSD.jpg", imgPSD);
fftshift(H, H);
normalize(H, H, 0, 255, NORM_MINMAX);
imshow("Debluring", imgOut);
imwrite("filter.jpg", H);
waitKey(0);
return 0;
}
//! [fftshift]
void fftshift(const Mat& inputImg, Mat& outputImg)
{
outputImg = inputImg.clone();
int cx = outputImg.cols / 2;
int cy = outputImg.rows / 2;
Mat q0(outputImg, Rect(0, 0, cx, cy));
Mat q1(outputImg, Rect(cx, 0, cx, cy));
Mat q2(outputImg, Rect(0, cy, cx, cy));
Mat q3(outputImg, Rect(cx, cy, cx, cy));
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
}
//! [fftshift]
//! [filter2DFreq]
void filter2DFreq(const Mat& inputImg, Mat& outputImg, const Mat& H)
{
Mat planes[2] = { Mat_<float>(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
dft(complexI, complexI, DFT_SCALE);
Mat planesH[2] = { Mat_<float>(H.clone()), Mat::zeros(H.size(), CV_32F) };
Mat complexH;
merge(planesH, 2, complexH);
Mat complexIH;
mulSpectrums(complexI, complexH, complexIH, 0);
idft(complexIH, complexIH);
split(complexIH, planes);
outputImg = planes[0];
}
//! [filter2DFreq]
//! [synthesizeFilterH]
void synthesizeFilterH(Mat& inputOutput_H, Point center, int radius)
{
Point c2 = center, c3 = center, c4 = center;
c2.y = inputOutput_H.rows - center.y;
c3.x = inputOutput_H.cols - center.x;
c4 = Point(c3.x,c2.y);
circle(inputOutput_H, center, radius, 0, -1, 8);
circle(inputOutput_H, c2, radius, 0, -1, 8);
circle(inputOutput_H, c3, radius, 0, -1, 8);
circle(inputOutput_H, c4, radius, 0, -1, 8);
}
//! [synthesizeFilterH]
// Function calculates PSD(Power spectrum density) by fft with two flags
// flag = 0 means to return PSD
// flag = 1 means to return log(PSD)
//! [calcPSD]
void calcPSD(const Mat& inputImg, Mat& outputImg, int flag)
{
Mat planes[2] = { Mat_<float>(inputImg.clone()), Mat::zeros(inputImg.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
dft(complexI, complexI);
split(complexI, planes); // planes[0] = Re(DFT(I)), planes[1] = Im(DFT(I))
planes[0].at<float>(0) = 0;
planes[1].at<float>(0) = 0;
// compute the PSD = sqrt(Re(DFT(I))^2 + Im(DFT(I))^2)^2
Mat imgPSD;
magnitude(planes[0], planes[1], imgPSD); //imgPSD = sqrt(Power spectrum density)
pow(imgPSD, 2, imgPSD); //it needs ^2 in order to get PSD
outputImg = imgPSD;
// logPSD = log(1 + PSD)
if (flag)
{
Mat imglogPSD;
imglogPSD = imgPSD + Scalar::all(1);
log(imglogPSD, imglogPSD);
outputImg = imglogPSD;
}
}
//! [calcPSD]
@@ -0,0 +1,97 @@
/**
* @file CannyDetector_Demo.cpp
* @brief Sample code showing how to detect edges using the Canny Detector
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
//![variables]
Mat src, src_gray;
Mat dst, detected_edges;
int lowThreshold = 0;
const int max_lowThreshold = 100;
const int ratio = 3;
const int kernel_size = 3;
const char* window_name = "Edge Map";
//![variables]
/**
* @function CannyThreshold
* @brief Trackbar callback - Canny thresholds input with a ratio 1:3
*/
static void CannyThreshold(int, void*)
{
//![reduce_noise]
/// Reduce noise with a kernel 3x3
blur( src_gray, detected_edges, Size(3,3) );
//![reduce_noise]
//![canny]
/// Canny detector
Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
//![canny]
/// Using Canny's output as a mask, we display our result
//![fill]
dst = Scalar::all(0);
//![fill]
//![copyto]
src.copyTo( dst, detected_edges);
//![copyto]
//![display]
imshow( window_name, dst );
//![display]
}
/**
* @function main
*/
int main( int argc, char** argv )
{
//![load]
CommandLineParser parser( argc, argv, "{@input | fruits.jpg | input image}" );
src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR ); // Load an image
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 -1;
}
//![load]
//![create_mat]
/// Create a matrix of the same type and size as src (for dst)
dst.create( src.size(), src.type() );
//![create_mat]
//![convert_to_gray]
cvtColor( src, src_gray, COLOR_BGR2GRAY );
//![convert_to_gray]
//![create_window]
namedWindow( window_name, WINDOW_AUTOSIZE );
//![create_window]
//![create_trackbar]
/// Create a Trackbar for user to enter threshold
createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );
//![create_trackbar]
/// Show the image
CannyThreshold(0, 0);
/// Wait until user exit program by pressing a key
waitKey(0);
return 0;
}
@@ -0,0 +1,83 @@
/**
* @function Geometric_Transforms_Demo.cpp
* @brief Demo code for Geometric Transforms
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/geometry.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/**
* @function main
*/
int main( int argc, char** argv )
{
//! [Load the image]
CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );
Mat src = imread( samples::findFile( 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;
}
//! [Load the image]
//! [Set your 3 points to calculate the Affine Transform]
Point2f srcTri[3];
srcTri[0] = Point2f( 0.f, 0.f );
srcTri[1] = Point2f( src.cols - 1.f, 0.f );
srcTri[2] = Point2f( 0.f, src.rows - 1.f );
Point2f dstTri[3];
dstTri[0] = Point2f( 0.f, src.rows*0.33f );
dstTri[1] = Point2f( src.cols*0.85f, src.rows*0.25f );
dstTri[2] = Point2f( src.cols*0.15f, src.rows*0.7f );
//! [Set your 3 points to calculate the Affine Transform]
//! [Get the Affine Transform]
Mat warp_mat = getAffineTransform( srcTri, dstTri );
//! [Get the Affine Transform]
//! [Apply the Affine Transform just found to the src image]
/// Set the dst image the same type and size as src
Mat warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
warpAffine( src, warp_dst, warp_mat, warp_dst.size() );
//! [Apply the Affine Transform just found to the src image]
/** Rotating the image after Warp */
//! [Compute a rotation matrix with respect to the center of the image]
Point center = Point( warp_dst.cols/2, warp_dst.rows/2 );
double angle = -50.0;
double scale = 0.6;
//! [Compute a rotation matrix with respect to the center of the image]
//! [Get the rotation matrix with the specifications above]
Mat rot_mat = getRotationMatrix2D( center, angle, scale );
//! [Get the rotation matrix with the specifications above]
//! [Rotate the warped image]
Mat warp_rotate_dst;
warpAffine( warp_dst, warp_rotate_dst, rot_mat, warp_dst.size() );
//! [Rotate the warped image]
//! [Show what you got]
imshow( "Source image", src );
imshow( "Warp", warp_dst );
imshow( "Warp + Rotate", warp_rotate_dst );
//! [Show what you got]
//! [Wait until user exits the program]
waitKey();
//! [Wait until user exits the program]
return 0;
}
@@ -0,0 +1,106 @@
/**
* @file HoughCircle_Demo.cpp
* @brief Demo code for Hough Transform
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
namespace
{
// windows and trackbars name
const std::string windowName = "Hough Circle Detection Demo";
const std::string cannyThresholdTrackbarName = "Canny threshold";
const std::string accumulatorThresholdTrackbarName = "Accumulator Threshold";
// initial and max values of the parameters of interests.
const int cannyThresholdInitialValue = 100;
const int accumulatorThresholdInitialValue = 50;
const int maxAccumulatorThreshold = 200;
const int maxCannyThreshold = 255;
void HoughDetection(const Mat& src_gray, const Mat& src_display, int cannyThreshold, int accumulatorThreshold)
{
// will hold the results of the detection
std::vector<Vec3f> circles;
// runs the actual detection
HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, cannyThreshold, accumulatorThreshold, 0, 0 );
// clone the colour, input image for displaying purposes
Mat display = src_display.clone();
for( size_t i = 0; i < circles.size(); i++ )
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// circle center
circle( display, center, 3, Scalar(0,255,0), -1, 8, 0 );
// circle outline
circle( display, center, radius, Scalar(0,0,255), 3, 8, 0 );
}
// shows the results
imshow( windowName, display);
}
}
int main(int argc, char** argv)
{
Mat src, src_gray;
// Read the image
String imageName("stuff.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
src = imread( samples::findFile( imageName ), IMREAD_COLOR );
if( src.empty() )
{
std::cerr << "Invalid input image\n";
std::cout << "Usage : " << argv[0] << " <path_to_input_image>\n";;
return -1;
}
// Convert it to gray
cvtColor( src, src_gray, COLOR_BGR2GRAY );
// Reduce the noise so we avoid false circle detection
GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
//declare and initialize both parameters that are subjects to change
int cannyThreshold = cannyThresholdInitialValue;
int accumulatorThreshold = accumulatorThresholdInitialValue;
// create the main window, and attach the trackbars
namedWindow( windowName, WINDOW_AUTOSIZE );
createTrackbar(cannyThresholdTrackbarName, windowName, &cannyThreshold,maxCannyThreshold);
createTrackbar(accumulatorThresholdTrackbarName, windowName, &accumulatorThreshold, maxAccumulatorThreshold);
// infinite loop to display
// and refresh the content of the output image
// until the user presses q or Q
char key = 0;
while(key != 'q' && key != 'Q')
{
// those parameters cannot be =0
// so we must check here
cannyThreshold = std::max(cannyThreshold, 1);
accumulatorThreshold = std::max(accumulatorThreshold, 1);
//runs the detection, and update the display
HoughDetection(src_gray, src, cannyThreshold, accumulatorThreshold);
// get user key
key = (char)waitKey(10);
}
return 0;
}
@@ -0,0 +1,179 @@
/**
* @file HoughLines_Demo.cpp
* @brief Demo code for Hough Transform
* @author OpenCV team
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/// Global variables
/** General variables */
Mat src, canny_edge, sobel_edge;
Mat src_gray;
Mat standard_hough, probabilistic_hough, weighted_hough;
int min_threshold = 50;
int max_trackbar = 150;
int weightedhough_max_trackbar = 100000;
const char* standard_name = "Standard Hough Lines Demo";
const char* probabilistic_name = "Probabilistic Hough Lines Demo";
const char* weighted_name = "Weighted Hough Lines Demo";
int s_trackbar = max_trackbar;
int p_trackbar = max_trackbar;
int e_trackbar = 60;
int w_trackbar = 60000;
/// Function Headers
void help();
void Standard_Hough( int, void* );
void Probabilistic_Hough( int, void* );
void Weighted_Hough( int, void* );
/**
* @function main
*/
int main( int argc, char** argv )
{
// Read the image
String imageName("building.jpg"); // by default
if (argc > 1)
{
imageName = argv[1];
}
src = imread( samples::findFile( imageName ), IMREAD_COLOR );
if( src.empty() )
{ help();
return -1;
}
/// Pass the image to gray
cvtColor( src, src_gray, COLOR_RGB2GRAY );
/// Apply Canny/Sobel edge detector
Canny( src_gray, canny_edge, 50, 200, 3 );
Sobel( src_gray, sobel_edge, CV_16S, 1, 0 ); // dx(order of the derivative x)=1,dy=0
/// Create Trackbars for Thresholds
char thresh_label[50];
snprintf( thresh_label, sizeof(thresh_label), "Thres: %d + input", min_threshold );
namedWindow( standard_name, WINDOW_AUTOSIZE );
createTrackbar( thresh_label, standard_name, &s_trackbar, max_trackbar, Standard_Hough );
namedWindow( probabilistic_name, WINDOW_AUTOSIZE );
createTrackbar( thresh_label, probabilistic_name, &p_trackbar, max_trackbar, Probabilistic_Hough );
const char* edge_thresh_label = "Edge Thres: input";
namedWindow( weighted_name, WINDOW_AUTOSIZE);
createTrackbar( edge_thresh_label, weighted_name, &e_trackbar, max_trackbar, Weighted_Hough);
createTrackbar( thresh_label, weighted_name, &w_trackbar, weightedhough_max_trackbar, Weighted_Hough);
/// Initialize
Standard_Hough(0, 0);
Probabilistic_Hough(0, 0);
Weighted_Hough(0, 0);
waitKey(0);
return 0;
}
/**
* @function help
* @brief Indications of how to run this program and why is it for
*/
void help()
{
printf("\t Hough Transform to detect lines \n ");
printf("\t---------------------------------\n ");
printf(" Usage: ./HoughLines_Demo <image_name> \n");
}
/**
* @function Standard_Hough
*/
void Standard_Hough( int, void* )
{
vector<Vec2f> s_lines;
cvtColor( canny_edge, standard_hough, COLOR_GRAY2BGR );
/// 1. Use Standard Hough Transform
HoughLines( canny_edge, s_lines, 1, CV_PI/180, min_threshold + s_trackbar, 0, 0 );
/// Show the result
for( size_t i = 0; i < s_lines.size(); i++ )
{
float r = s_lines[i][0], t = s_lines[i][1];
double cos_t = cos(t), sin_t = sin(t);
double x0 = r*cos_t, y0 = r*sin_t;
double alpha = 1000;
Point pt1( cvRound(x0 + alpha*(-sin_t)), cvRound(y0 + alpha*cos_t) );
Point pt2( cvRound(x0 - alpha*(-sin_t)), cvRound(y0 - alpha*cos_t) );
line( standard_hough, pt1, pt2, Scalar(255,0,0), 3, LINE_AA);
}
imshow( standard_name, standard_hough );
}
/**
* @function Probabilistic_Hough
*/
void Probabilistic_Hough( int, void* )
{
vector<Vec4i> p_lines;
cvtColor( canny_edge, probabilistic_hough, COLOR_GRAY2BGR );
/// 2. Use Probabilistic Hough Transform
HoughLinesP( canny_edge, p_lines, 1, CV_PI/180, min_threshold + p_trackbar, 30, 10 );
/// Show the result
for( size_t i = 0; i < p_lines.size(); i++ )
{
Vec4i l = p_lines[i];
line( probabilistic_hough, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(255,0,0), 3, LINE_AA);
}
imshow( probabilistic_name, probabilistic_hough );
}
/**
* @function Weighted_Hough
* This can detect lines based on the edge intensities.
*/
void Weighted_Hough( int, void* )
{
vector<Vec2f> s_lines;
/// prepare
Mat edge_img;
convertScaleAbs(sobel_edge, edge_img );
// use same threshold for edge with Hough.
threshold( edge_img, edge_img, e_trackbar, 255, cv::THRESH_TOZERO);
cvtColor( edge_img, weighted_hough, COLOR_GRAY2BGR );
/// 3. Use Weighted Hough Transform
const bool use_edgeval{true};
HoughLines( edge_img, s_lines, 1, CV_PI/180, min_threshold + w_trackbar, 0, 0, 0, CV_PI, use_edgeval);
/// Show the result
for( size_t i = 0; i < s_lines.size(); i++ )
{
float r = s_lines[i][0], t = s_lines[i][1];
double cos_t = cos(t), sin_t = sin(t);
double x0 = r*cos_t, y0 = r*sin_t;
double alpha = 1000;
Point pt1( cvRound(x0 + alpha*(-sin_t)), cvRound(y0 + alpha*cos_t) );
Point pt2( cvRound(x0 - alpha*(-sin_t)), cvRound(y0 - alpha*cos_t) );
line( weighted_hough, pt1, pt2, Scalar(255,0,0), 3, LINE_AA );
}
imshow( weighted_name, weighted_hough );
}
@@ -0,0 +1,67 @@
/**
* @file Laplace_Demo.cpp
* @brief Sample code showing how to detect edges using the Laplace operator
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
/**
* @function main
*/
int main( int argc, char** argv )
{
//![variables]
// Declare the variables we are going to use
Mat src, src_gray, dst;
int kernel_size = 3;
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
const char* window_name = "Laplace Demo";
//![variables]
//![load]
const char* imageName = argc >=2 ? argv[1] : "lena.jpg";
src = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image
// Check if image is loaded fine
if(src.empty()){
printf(" Error opening image\n");
printf(" Program Arguments: [image_name -- default lena.jpg] \n");
return -1;
}
//![load]
//![reduce_noise]
// Reduce noise by blurring with a Gaussian filter ( kernel size = 3 )
GaussianBlur( src, src, Size(3, 3), 0, 0, BORDER_DEFAULT );
//![reduce_noise]
//![convert_to_gray]
cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to grayscale
//![convert_to_gray]
/// Apply Laplace function
Mat abs_dst;
//![laplacian]
Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
//![laplacian]
//![convert]
// converting back to CV_8U
convertScaleAbs( dst, abs_dst );
//![convert]
//![display]
imshow( window_name, abs_dst );
waitKey(0);
//![display]
return 0;
}
@@ -0,0 +1,114 @@
/**
* @function Remap_Demo.cpp
* @brief Demo code for Remap
* @author Ana Huaman
*/
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
/// Function Headers
void update_map( int &ind, Mat &map_x, Mat &map_y );
/**
* @function main
*/
int main(int argc, const char** argv)
{
CommandLineParser parser(argc, argv, "{@image |chicky_512.png|input image name}");
std::string filename = parser.get<std::string>(0);
//! [Load]
/// Load the image
Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
if (src.empty())
{
std::cout << "Cannot read image: " << filename << std::endl;
return -1;
}
//! [Load]
//! [Create]
/// Create dst, map_x and map_y with the same size as src:
Mat dst(src.size(), src.type());
Mat map_x(src.size(), CV_32FC1);
Mat map_y(src.size(), CV_32FC1);
//! [Create]
//! [Window]
/// Create window
const char* remap_window = "Remap demo";
namedWindow( remap_window, WINDOW_AUTOSIZE );
//! [Window]
//! [Loop]
/// Index to switch between the remap modes
int ind = 0;
for(;;)
{
/// Update map_x & map_y. Then apply remap
update_map(ind, map_x, map_y);
remap( src, dst, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0) );
/// Display results
imshow( remap_window, dst );
/// Each 1 sec. Press ESC to exit the program
char c = (char)waitKey( 1000 );
if( c == 27 )
{
break;
}
}
//! [Loop]
return 0;
}
/**
* @function update_map
* @brief Fill the map_x and map_y matrices with 4 types of mappings
*/
//! [Update]
void update_map( int &ind, Mat &map_x, Mat &map_y )
{
for( int i = 0; i < map_x.rows; i++ )
{
for( int j = 0; j < map_x.cols; j++ )
{
switch( ind )
{
case 0:
if( j > map_x.cols*0.25 && j < map_x.cols*0.75 && i > map_x.rows*0.25 && i < map_x.rows*0.75 )
{
map_x.at<float>(i, j) = 2*( j - map_x.cols*0.25f ) + 0.5f;
map_y.at<float>(i, j) = 2*( i - map_x.rows*0.25f ) + 0.5f;
}
else
{
map_x.at<float>(i, j) = 0;
map_y.at<float>(i, j) = 0;
}
break;
case 1:
map_x.at<float>(i, j) = (float)j;
map_y.at<float>(i, j) = (float)(map_x.rows - i);
break;
case 2:
map_x.at<float>(i, j) = (float)(map_x.cols - j);
map_y.at<float>(i, j) = (float)i;
break;
case 3:
map_x.at<float>(i, j) = (float)(map_x.cols - j);
map_y.at<float>(i, j) = (float)(map_x.rows - i);
break;
default:
break;
} // end of switch
}
}
ind = (ind+1) % 4;
}
//! [Update]
@@ -0,0 +1,124 @@
/**
* @file Sobel_Demo.cpp
* @brief Sample code uses Sobel or Scharr OpenCV functions for edge detection
* @author OpenCV team
*/
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
/**
* @function main
*/
int main( int argc, char** argv )
{
cv::CommandLineParser parser(argc, argv,
"{@input |lena.jpg|input image}"
"{ksize k|1|ksize (hit 'K' to increase its value at run time)}"
"{scale s|1|scale (hit 'S' to increase its value at run time)}"
"{delta d|0|delta (hit 'D' to increase its value at run time)}"
"{help h|false|show help message}");
cout << "The sample uses Sobel or Scharr OpenCV functions for edge detection\n\n";
parser.printMessage();
cout << "\nPress 'ESC' to exit program.\nPress 'R' to reset values ( ksize will be -1 equal to Scharr function )";
//![variables]
// First we declare the variables we are going to use
Mat image,src, src_gray;
Mat grad;
const String window_name = "Sobel Demo - Simple Edge Detector";
int ksize = parser.get<int>("ksize");
int scale = parser.get<int>("scale");
int delta = parser.get<int>("delta");
int ddepth = CV_16S;
//![variables]
//![load]
String imageName = parser.get<String>("@input");
// As usual we load our source image (src)
image = imread( samples::findFile( imageName ), IMREAD_COLOR ); // Load an image
// Check if image is loaded fine
if( image.empty() )
{
printf("Error opening image: %s\n", imageName.c_str());
return EXIT_FAILURE;
}
//![load]
for (;;)
{
//![reduce_noise]
// Remove noise by blurring with a Gaussian filter ( kernel size = 3 )
GaussianBlur(image, src, Size(3, 3), 0, 0, BORDER_DEFAULT);
//![reduce_noise]
//![convert_to_gray]
// Convert the image to grayscale
cvtColor(src, src_gray, COLOR_BGR2GRAY);
//![convert_to_gray]
//![sobel]
/// Generate grad_x and grad_y
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X
Sobel(src_gray, grad_x, ddepth, 1, 0, ksize, scale, delta, BORDER_DEFAULT);
/// Gradient Y
Sobel(src_gray, grad_y, ddepth, 0, 1, ksize, scale, delta, BORDER_DEFAULT);
//![sobel]
//![convert]
// converting back to CV_8U
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
//![convert]
//![blend]
/// Total Gradient (approximate)
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
//![blend]
//![display]
imshow(window_name, grad);
char key = (char)waitKey(0);
//![display]
if(key == 27)
{
return EXIT_SUCCESS;
}
if (key == 'k' || key == 'K')
{
ksize = ksize < 30 ? ksize+2 : -1;
}
if (key == 's' || key == 'S')
{
scale++;
}
if (key == 'd' || key == 'D')
{
delta++;
}
if (key == 'r' || key == 'R')
{
scale = 1;
ksize = -1;
delta = 0;
}
}
return EXIT_SUCCESS;
}

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