mirror of
https://github.com/opencv/opencv.git
synced 2026-07-29 15:23:05 +04:00
Merge branch 4.x
This commit is contained in:
@@ -38,23 +38,14 @@ int main( int argc, char** argv )
|
||||
points.push_back(pt);
|
||||
}
|
||||
|
||||
vector<int> hull;
|
||||
convexHull(Mat(points), hull, true);
|
||||
vector<Point> hull;
|
||||
convexHull(points, hull, true);
|
||||
|
||||
img = Scalar::all(0);
|
||||
for( i = 0; i < count; i++ )
|
||||
circle(img, points[i], 3, Scalar(0, 0, 255), FILLED, LINE_AA);
|
||||
|
||||
int hullcount = (int)hull.size();
|
||||
Point pt0 = points[hull[hullcount-1]];
|
||||
|
||||
for( i = 0; i < hullcount; i++ )
|
||||
{
|
||||
Point pt = points[hull[i]];
|
||||
line(img, pt0, pt, Scalar(0, 255, 0), 1,LINE_AA);
|
||||
pt0 = pt;
|
||||
}
|
||||
|
||||
polylines(img, hull, true, Scalar(0, 255, 0), 1, LINE_AA);
|
||||
imshow("hull", img);
|
||||
|
||||
char key = (char)waitKey();
|
||||
|
||||
+27
-10
@@ -107,12 +107,14 @@ void GCApplication::showImage() const
|
||||
|
||||
Mat res;
|
||||
Mat binMask;
|
||||
if( !isInitialized )
|
||||
image->copyTo( res );
|
||||
else
|
||||
{
|
||||
getBinMask( mask, binMask );
|
||||
image->copyTo( res, 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;
|
||||
@@ -201,24 +203,39 @@ void GCApplication::mouseClick( int event, int x, int y, int flags, void* )
|
||||
case EVENT_LBUTTONUP:
|
||||
if( rectState == IN_PROCESS )
|
||||
{
|
||||
rect = Rect( Point(rect.x, rect.y), Point(x,y) );
|
||||
rectState = SET;
|
||||
setRectInMask();
|
||||
CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
|
||||
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;
|
||||
|
||||
+34
-24
@@ -1,6 +1,6 @@
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
|
||||
#include "opencv2/core/cvdef.h"
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace cv;
|
||||
@@ -14,15 +14,19 @@ static void help()
|
||||
{
|
||||
printf( "\nExample of c calls to OpenCV's Kalman filter.\n"
|
||||
" Tracking of rotating point.\n"
|
||||
" Rotation speed is constant.\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 point angle + gaussian noise.\n"
|
||||
" The real and the estimated points are connected with yellow line segment,\n"
|
||||
" the real and the measured points are connected with red line segment.\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).\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 with a different speed.\n"
|
||||
" Pressing any key (except ESC) will reset the tracking.\n"
|
||||
" Pressing ESC will stop the program.\n"
|
||||
);
|
||||
}
|
||||
@@ -39,7 +43,9 @@ int main(int, char**)
|
||||
|
||||
for(;;)
|
||||
{
|
||||
randn( state, Scalar::all(0), Scalar::all(0.1) );
|
||||
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);
|
||||
@@ -60,36 +66,40 @@ int main(int, char**)
|
||||
double predictAngle = prediction.at<float>(0);
|
||||
Point predictPt = calcPoint(center, R, predictAngle);
|
||||
|
||||
randn( measurement, Scalar::all(0), Scalar::all(KF.measurementNoiseCov.at<float>(0)));
|
||||
|
||||
// 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
|
||||
#define drawCross( center, color, d ) \
|
||||
line( img, Point( center.x - d, center.y - d ), \
|
||||
Point( center.x + d, center.y + d ), color, 1, LINE_AA, 0); \
|
||||
line( img, Point( center.x + d, center.y - d ), \
|
||||
Point( center.x - d, center.y + d ), color, 1, LINE_AA, 0 )
|
||||
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);
|
||||
|
||||
img = Scalar::all(0);
|
||||
drawCross( statePt, Scalar(255,255,255), 3 );
|
||||
drawCross( measPt, Scalar(0,0,255), 3 );
|
||||
drawCross( predictPt, Scalar(0,255,0), 3 );
|
||||
line( img, statePt, measPt, Scalar(0,0,255), 3, LINE_AA, 0 );
|
||||
line( img, statePt, predictPt, Scalar(0,255,255), 3, LINE_AA, 0 );
|
||||
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 );
|
||||
|
||||
if(theRNG().uniform(0,4) != 0)
|
||||
KF.correct(measurement);
|
||||
|
||||
randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));
|
||||
state = KF.transitionMatrix*state + processNoise;
|
||||
|
||||
imshow( "Kalman", img );
|
||||
code = (char)waitKey(100);
|
||||
code = (char)waitKey(1000);
|
||||
|
||||
if( code > 0 )
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "opencv2/imgproc.hpp"
|
||||
#include "opencv2/imgcodecs.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
cv::CommandLineParser parser(argc, argv,
|
||||
"{input i|building.jpg|input image}"
|
||||
"{refine r|false|if true use LSD_REFINE_STD method, if false use LSD_REFINE_NONE method}"
|
||||
"{canny c|false|use Canny edge detector}"
|
||||
"{overlay o|false|show result on input image}"
|
||||
"{help h|false|show help message}");
|
||||
|
||||
if (parser.get<bool>("help"))
|
||||
{
|
||||
parser.printMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
parser.printMessage();
|
||||
|
||||
String filename = samples::findFile(parser.get<String>("input"));
|
||||
bool useRefine = parser.get<bool>("refine");
|
||||
bool useCanny = parser.get<bool>("canny");
|
||||
bool overlay = parser.get<bool>("overlay");
|
||||
|
||||
Mat image = imread(filename, IMREAD_GRAYSCALE);
|
||||
|
||||
if( image.empty() )
|
||||
{
|
||||
cout << "Unable to load " << filename;
|
||||
return 1;
|
||||
}
|
||||
|
||||
imshow("Source Image", image);
|
||||
|
||||
if (useCanny)
|
||||
{
|
||||
Canny(image, image, 50, 200, 3); // Apply Canny edge detector
|
||||
}
|
||||
|
||||
// Create and LSD detector with standard or no refinement.
|
||||
Ptr<LineSegmentDetector> ls = useRefine ? createLineSegmentDetector(LSD_REFINE_STD) : createLineSegmentDetector(LSD_REFINE_NONE);
|
||||
|
||||
double start = double(getTickCount());
|
||||
vector<Vec4f> lines_std;
|
||||
|
||||
// Detect the lines
|
||||
ls->detect(image, lines_std);
|
||||
|
||||
double duration_ms = (double(getTickCount()) - start) * 1000 / getTickFrequency();
|
||||
std::cout << "It took " << duration_ms << " ms." << std::endl;
|
||||
|
||||
// Show found lines
|
||||
if (!overlay || useCanny)
|
||||
{
|
||||
image = Scalar(0, 0, 0);
|
||||
}
|
||||
|
||||
ls->drawSegments(image, lines_std);
|
||||
|
||||
String window_name = useRefine ? "Result - standard refinement" : "Result - no refinement";
|
||||
window_name += useCanny ? " - Canny edge detector used" : "";
|
||||
|
||||
imshow(window_name, image);
|
||||
|
||||
waitKey();
|
||||
return 0;
|
||||
}
|
||||
@@ -89,7 +89,7 @@ void MatchingMethod( int, void* )
|
||||
|
||||
//! [create_result_matrix]
|
||||
/// Create the result matrix
|
||||
int result_cols = img.cols - templ.cols + 1;
|
||||
int result_cols = img.cols - templ.cols + 1;
|
||||
int result_rows = img.rows - templ.rows + 1;
|
||||
|
||||
result.create( result_rows, result_cols, CV_32FC1 );
|
||||
|
||||
@@ -72,18 +72,18 @@ void Hist_and_Backproj(int, void* )
|
||||
//! [initialize]
|
||||
int histSize = MAX( bins, 2 );
|
||||
float hue_range[] = { 0, 180 };
|
||||
const float* ranges = { hue_range };
|
||||
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 );
|
||||
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 );
|
||||
calcBackProject( &hue, 1, 0, hist, backproj, ranges, 1, true );
|
||||
//! [Get Backprojection]
|
||||
|
||||
//! [Draw the backproj]
|
||||
|
||||
@@ -37,7 +37,7 @@ int main(int argc, char** argv)
|
||||
|
||||
//! [Set the ranges ( for B,G,R) )]
|
||||
float range[] = { 0, 256 }; //the upper boundary is exclusive
|
||||
const float* histRange = { range };
|
||||
const float* histRange[] = { range };
|
||||
//! [Set the ranges ( for B,G,R) )]
|
||||
|
||||
//! [Set histogram param]
|
||||
@@ -46,9 +46,9 @@ int main(int argc, char** argv)
|
||||
|
||||
//! [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 );
|
||||
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]
|
||||
|
||||
@@ -62,7 +62,7 @@ int main( int argc, char** argv )
|
||||
{
|
||||
float lambda_1 = myHarris_dst.at<Vec6f>(i, j)[0];
|
||||
float lambda_2 = myHarris_dst.at<Vec6f>(i, j)[1];
|
||||
Mc.at<float>(i, j) = lambda_1*lambda_2 - 0.04f*pow( ( lambda_1 + lambda_2 ), 2 );
|
||||
Mc.at<float>(i, j) = lambda_1*lambda_2 - 0.04f*((lambda_1 + lambda_2) * (lambda_1 + lambda_2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
#include <iostream>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
namespace
|
||||
{
|
||||
//! [convolution-sequential]
|
||||
void conv_seq(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
//![convolution-make-borders]
|
||||
int rows = src.rows, cols = src.cols;
|
||||
dst = Mat(rows, cols, src.type());
|
||||
|
||||
// Taking care of edge values
|
||||
// Make border = kernel.rows / 2;
|
||||
|
||||
int sz = kernel.rows / 2;
|
||||
copyMakeBorder(src, src, sz, sz, sz, sz, BORDER_REPLICATE);
|
||||
//![convolution-make-borders]
|
||||
|
||||
//! [convolution-kernel-loop]
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
uchar *dptr = dst.ptr(i);
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
double value = 0;
|
||||
|
||||
for (int k = -sz; k <= sz; k++)
|
||||
{
|
||||
// slightly faster results when we create a ptr due to more efficient memory access.
|
||||
uchar *sptr = src.ptr(i + sz + k);
|
||||
for (int l = -sz; l <= sz; l++)
|
||||
{
|
||||
value += kernel.ptr<double>(k + sz)[l + sz] * sptr[j + sz + l];
|
||||
}
|
||||
}
|
||||
dptr[j] = saturate_cast<uchar>(value);
|
||||
}
|
||||
}
|
||||
//! [convolution-kernel-loop]
|
||||
}
|
||||
//! [convolution-sequential]
|
||||
|
||||
#ifdef CV_CXX11
|
||||
void conv_parallel(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
int rows = src.rows, cols = src.cols;
|
||||
|
||||
dst = Mat(rows, cols, CV_8UC1, Scalar(0));
|
||||
|
||||
// Taking care of edge values
|
||||
// Make border = kernel.rows / 2;
|
||||
|
||||
int sz = kernel.rows / 2;
|
||||
copyMakeBorder(src, src, sz, sz, sz, sz, BORDER_REPLICATE);
|
||||
|
||||
//! [convolution-parallel-cxx11]
|
||||
parallel_for_(Range(0, rows * cols), [&](const Range &range)
|
||||
{
|
||||
for (int r = range.start; r < range.end; r++)
|
||||
{
|
||||
int i = r / cols, j = r % cols;
|
||||
|
||||
double value = 0;
|
||||
for (int k = -sz; k <= sz; k++)
|
||||
{
|
||||
uchar *sptr = src.ptr(i + sz + k);
|
||||
for (int l = -sz; l <= sz; l++)
|
||||
{
|
||||
value += kernel.ptr<double>(k + sz)[l + sz] * sptr[j + sz + l];
|
||||
}
|
||||
}
|
||||
dst.ptr(i)[j] = saturate_cast<uchar>(value);
|
||||
}
|
||||
});
|
||||
//! [convolution-parallel-cxx11]
|
||||
}
|
||||
|
||||
void conv_parallel_row_split(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
int rows = src.rows, cols = src.cols;
|
||||
|
||||
dst = Mat(rows, cols, CV_8UC1, Scalar(0));
|
||||
|
||||
// Taking care of edge values
|
||||
// Make border = kernel.rows / 2;
|
||||
|
||||
int sz = kernel.rows / 2;
|
||||
copyMakeBorder(src, src, sz, sz, sz, sz, BORDER_REPLICATE);
|
||||
|
||||
//! [convolution-parallel-cxx11-row-split]
|
||||
parallel_for_(Range(0, rows), [&](const Range &range)
|
||||
{
|
||||
for (int i = range.start; i < range.end; i++)
|
||||
{
|
||||
|
||||
uchar *dptr = dst.ptr(i);
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
double value = 0;
|
||||
for (int k = -sz; k <= sz; k++)
|
||||
{
|
||||
uchar *sptr = src.ptr(i + sz + k);
|
||||
for (int l = -sz; l <= sz; l++)
|
||||
{
|
||||
value += kernel.ptr<double>(k + sz)[l + sz] * sptr[j + sz + l];
|
||||
}
|
||||
}
|
||||
dptr[j] = saturate_cast<uchar>(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
//! [convolution-parallel-cxx11-row-split]
|
||||
}
|
||||
#else
|
||||
|
||||
//! [convolution-parallel]
|
||||
class parallelConvolution : public ParallelLoopBody
|
||||
{
|
||||
private:
|
||||
Mat m_src, &m_dst;
|
||||
Mat m_kernel;
|
||||
int sz;
|
||||
|
||||
public:
|
||||
parallelConvolution(Mat src, Mat &dst, Mat kernel)
|
||||
: m_src(src), m_dst(dst), m_kernel(kernel)
|
||||
{
|
||||
sz = kernel.rows / 2;
|
||||
}
|
||||
|
||||
//! [overload-full]
|
||||
virtual void operator()(const Range &range) const CV_OVERRIDE
|
||||
{
|
||||
for (int r = range.start; r < range.end; r++)
|
||||
{
|
||||
int i = r / m_src.cols, j = r % m_src.cols;
|
||||
|
||||
double value = 0;
|
||||
for (int k = -sz; k <= sz; k++)
|
||||
{
|
||||
uchar *sptr = m_src.ptr(i + sz + k);
|
||||
for (int l = -sz; l <= sz; l++)
|
||||
{
|
||||
value += m_kernel.ptr<double>(k + sz)[l + sz] * sptr[j + sz + l];
|
||||
}
|
||||
}
|
||||
m_dst.ptr(i)[j] = saturate_cast<uchar>(value);
|
||||
}
|
||||
}
|
||||
//! [overload-full]
|
||||
};
|
||||
//! [convolution-parallel]
|
||||
|
||||
void conv_parallel(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
int rows = src.rows, cols = src.cols;
|
||||
|
||||
dst = Mat(rows, cols, CV_8UC1, Scalar(0));
|
||||
|
||||
// Taking care of edge values
|
||||
// Make border = kernel.rows / 2;
|
||||
|
||||
int sz = kernel.rows / 2;
|
||||
copyMakeBorder(src, src, sz, sz, sz, sz, BORDER_REPLICATE);
|
||||
|
||||
//! [convolution-parallel-function]
|
||||
parallelConvolution obj(src, dst, kernel);
|
||||
parallel_for_(Range(0, rows * cols), obj);
|
||||
//! [convolution-parallel-function]
|
||||
}
|
||||
|
||||
//! [conv-parallel-row-split]
|
||||
class parallelConvolutionRowSplit : public ParallelLoopBody
|
||||
{
|
||||
private:
|
||||
Mat m_src, &m_dst;
|
||||
Mat m_kernel;
|
||||
int sz;
|
||||
|
||||
public:
|
||||
parallelConvolutionRowSplit(Mat src, Mat &dst, Mat kernel)
|
||||
: m_src(src), m_dst(dst), m_kernel(kernel)
|
||||
{
|
||||
sz = kernel.rows / 2;
|
||||
}
|
||||
|
||||
//! [overload-row-split]
|
||||
virtual void operator()(const Range &range) const CV_OVERRIDE
|
||||
{
|
||||
for (int i = range.start; i < range.end; i++)
|
||||
{
|
||||
|
||||
uchar *dptr = dst.ptr(i);
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
double value = 0;
|
||||
for (int k = -sz; k <= sz; k++)
|
||||
{
|
||||
uchar *sptr = src.ptr(i + sz + k);
|
||||
for (int l = -sz; l <= sz; l++)
|
||||
{
|
||||
value += kernel.ptr<double>(k + sz)[l + sz] * sptr[j + sz + l];
|
||||
}
|
||||
}
|
||||
dptr[j] = saturate_cast<uchar>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
//! [overload-row-split]
|
||||
};
|
||||
//! [conv-parallel-row-split]
|
||||
|
||||
void conv_parallel_row_split(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
int rows = src.rows, cols = src.cols;
|
||||
|
||||
dst = Mat(rows, cols, CV_8UC1, Scalar(0));
|
||||
|
||||
// Taking care of edge values
|
||||
// Make border = kernel.rows / 2;
|
||||
|
||||
int sz = kernel.rows / 2;
|
||||
copyMakeBorder(src, src, sz, sz, sz, sz, BORDER_REPLICATE);
|
||||
|
||||
//! [convolution-parallel-function-row]
|
||||
parallelConvolutionRowSplit obj(src, dst, kernel);
|
||||
parallel_for_(Range(0, rows), obj);
|
||||
//! [convolution-parallel-function-row]
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void help(char *progName)
|
||||
{
|
||||
cout << endl
|
||||
<< " This program shows how to use the OpenCV parallel_for_ function and \n"
|
||||
<< " compares the performance of the sequential and parallel implementations for a \n"
|
||||
<< " convolution operation\n"
|
||||
<< " Usage:\n "
|
||||
<< progName << " [image_path -- default lena.jpg] " << endl
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
help(argv[0]);
|
||||
const char *filepath = argc >= 2 ? argv[1] : "../../../../data/lena.jpg";
|
||||
|
||||
Mat src, dst, kernel;
|
||||
src = imread(filepath, IMREAD_GRAYSCALE);
|
||||
|
||||
if (src.empty())
|
||||
{
|
||||
cerr << "Can't open [" << filepath << "]" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
namedWindow("Input", 1);
|
||||
namedWindow("Output1", 1);
|
||||
namedWindow("Output2", 1);
|
||||
namedWindow("Output3", 1);
|
||||
imshow("Input", src);
|
||||
|
||||
kernel = (Mat_<double>(3, 3) << 1, 0, -1,
|
||||
1, 0, -1,
|
||||
1, 0, -1);
|
||||
|
||||
/*
|
||||
Uncomment the kernels you want to use or write your own kernels to test out
|
||||
performance.
|
||||
*/
|
||||
|
||||
/*
|
||||
kernel = (Mat_<double>(5, 5) << 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1);
|
||||
kernel /= 100;
|
||||
*/
|
||||
|
||||
/*
|
||||
kernel = (Mat_<double>(3, 3) << 1, 1, 1,
|
||||
0, 0, 0,
|
||||
-1, -1, -1);
|
||||
|
||||
*/
|
||||
|
||||
double t = (double)getTickCount();
|
||||
|
||||
conv_seq(src, dst, kernel);
|
||||
|
||||
t = ((double)getTickCount() - t) / getTickFrequency();
|
||||
cout << " Sequential implementation: " << t << "s" << endl;
|
||||
|
||||
imshow("Output1", dst);
|
||||
waitKey(0);
|
||||
|
||||
t = (double)getTickCount();
|
||||
|
||||
conv_parallel(src, dst, kernel);
|
||||
|
||||
t = ((double)getTickCount() - t) / getTickFrequency();
|
||||
cout << " Parallel Implementation: " << t << "s" << endl;
|
||||
|
||||
imshow("Output2", dst);
|
||||
waitKey(0);
|
||||
|
||||
t = (double)getTickCount();
|
||||
|
||||
conv_parallel_row_split(src, dst, kernel);
|
||||
|
||||
t = ((double)getTickCount() - t) / getTickFrequency();
|
||||
cout << " Parallel Implementation(Row Split): " << t << "s" << endl
|
||||
<< endl;
|
||||
|
||||
imshow("Output3", dst);
|
||||
waitKey(0);
|
||||
|
||||
// imwrite("src.png", src);
|
||||
// imwrite("dst.png", dst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
#include <iostream>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgcodecs.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/core/simd_intrinsics.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
const int N = 100005, K = 2000;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void conv_seq(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
int rows = src.rows, cols = src.cols;
|
||||
dst = Mat(rows, cols, CV_8UC1);
|
||||
|
||||
int sz = kernel.rows / 2;
|
||||
copyMakeBorder(src, src, sz, sz, sz, sz, BORDER_REPLICATE);
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
uchar *dptr = dst.ptr<uchar>(i);
|
||||
for (int j = 0; j < cols; j++)
|
||||
{
|
||||
float value = 0;
|
||||
|
||||
for (int k = -sz; k <= sz; k++)
|
||||
{
|
||||
// slightly faster results when we create a ptr due to more efficient memory access.
|
||||
uchar *sptr = src.ptr<uchar>(i + sz + k);
|
||||
for (int l = -sz; l <= sz; l++)
|
||||
{
|
||||
value += kernel.ptr<float>(k + sz)[l + sz] * sptr[j + sz + l];
|
||||
}
|
||||
}
|
||||
dptr[j] = saturate_cast<uchar>(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! [convolution-1D-scalar]
|
||||
void conv1d(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
|
||||
//! [convolution-1D-border]
|
||||
int len = src.cols;
|
||||
dst = Mat(1, len, CV_8UC1);
|
||||
|
||||
int sz = kernel.cols / 2;
|
||||
copyMakeBorder(src, src, 0, 0, sz, sz, BORDER_REPLICATE);
|
||||
//! [convolution-1D-border]
|
||||
|
||||
//! [convolution-1D-scalar-main]
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
double value = 0;
|
||||
for (int k = -sz; k <= sz; k++)
|
||||
value += src.ptr<uchar>(0)[i + k + sz] * kernel.ptr<float>(0)[k + sz];
|
||||
|
||||
dst.ptr<uchar>(0)[i] = saturate_cast<uchar>(value);
|
||||
}
|
||||
//! [convolution-1D-scalar-main]
|
||||
}
|
||||
//! [convolution-1D-scalar]
|
||||
|
||||
//! [convolution-1D-vector]
|
||||
void conv1dsimd(Mat src, Mat kernel, float *ans, int row = 0, int rowk = 0, int len = -1)
|
||||
{
|
||||
if (len == -1)
|
||||
len = src.cols;
|
||||
|
||||
//! [convolution-1D-convert]
|
||||
Mat src_32, kernel_32;
|
||||
|
||||
const int alpha = 1;
|
||||
src.convertTo(src_32, CV_32FC1, alpha);
|
||||
|
||||
int ksize = kernel.cols, sz = kernel.cols / 2;
|
||||
copyMakeBorder(src_32, src_32, 0, 0, sz, sz, BORDER_REPLICATE);
|
||||
//! [convolution-1D-convert]
|
||||
|
||||
|
||||
//! [convolution-1D-main]
|
||||
//! [convolution-1D-main-h1]
|
||||
int step = v_float32().nlanes;
|
||||
float *sptr = src_32.ptr<float>(row), *kptr = kernel.ptr<float>(rowk);
|
||||
for (int k = 0; k < ksize; k++)
|
||||
{
|
||||
//! [convolution-1D-main-h1]
|
||||
//! [convolution-1D-main-h2]
|
||||
v_float32 kernel_wide = vx_setall_f32(kptr[k]);
|
||||
int i;
|
||||
for (i = 0; i + step < len; i += step)
|
||||
{
|
||||
v_float32 window = vx_load(sptr + i + k);
|
||||
v_float32 sum = vx_load(ans + i) + kernel_wide * window;
|
||||
v_store(ans + i, sum);
|
||||
}
|
||||
//! [convolution-1D-main-h2]
|
||||
|
||||
//! [convolution-1D-main-h3]
|
||||
for (; i < len; i++)
|
||||
{
|
||||
*(ans + i) += sptr[i + k]*kptr[k];
|
||||
}
|
||||
//! [convolution-1D-main-h3]
|
||||
}
|
||||
//! [convolution-1D-main]
|
||||
}
|
||||
//! [convolution-1D-vector]
|
||||
|
||||
//! [convolution-2D]
|
||||
void convolute_simd(Mat src, Mat &dst, Mat kernel)
|
||||
{
|
||||
//! [convolution-2D-init]
|
||||
int rows = src.rows, cols = src.cols;
|
||||
int ksize = kernel.rows, sz = ksize / 2;
|
||||
dst = Mat(rows, cols, CV_32FC1);
|
||||
|
||||
copyMakeBorder(src, src, sz, sz, 0, 0, BORDER_REPLICATE);
|
||||
|
||||
int step = v_float32().nlanes;
|
||||
//! [convolution-2D-init]
|
||||
|
||||
//! [convolution-2D-main]
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
for (int k = 0; k < ksize; k++)
|
||||
{
|
||||
float ans[N] = {0};
|
||||
conv1dsimd(src, kernel, ans, i + k, k, cols);
|
||||
int j;
|
||||
for (j = 0; j + step < cols; j += step)
|
||||
{
|
||||
v_float32 sum = vx_load(&dst.ptr<float>(i)[j]) + vx_load(&ans[j]);
|
||||
v_store(&dst.ptr<float>(i)[j], sum);
|
||||
}
|
||||
|
||||
for (; j < cols; j++)
|
||||
dst.ptr<float>(i)[j] += ans[j];
|
||||
}
|
||||
}
|
||||
//! [convolution-2D-main]
|
||||
|
||||
//! [convolution-2D-conv]
|
||||
const int alpha = 1;
|
||||
dst.convertTo(dst, CV_8UC1, alpha);
|
||||
//! [convolution-2D-conv]
|
||||
}
|
||||
//! [convolution-2D]
|
||||
|
||||
static void help(char *progName)
|
||||
{
|
||||
cout << endl
|
||||
<< " This program shows how to use the OpenCV parallel_for_ function and \n"
|
||||
<< " compares the performance of the sequential and parallel implementations for a \n"
|
||||
<< " convolution operation\n"
|
||||
<< " Usage:\n "
|
||||
<< progName << " [image_path -- default lena.jpg] " << endl
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
// 1-D Convolution //
|
||||
Mat vsrc(1, N, CV_8UC1), k(1, K, CV_32FC1), vdst;
|
||||
RNG rng(time(0));
|
||||
rng.RNG::fill(vsrc, RNG::UNIFORM, Scalar(0), Scalar(255));
|
||||
rng.RNG::fill(k, RNG::UNIFORM, Scalar(-50), Scalar(50));
|
||||
|
||||
double t = (double)getTickCount();
|
||||
conv1d(vsrc, vdst, k);
|
||||
t = ((double)getTickCount() - t) / getTickFrequency();
|
||||
cout << " Sequential 1-D convolution implementation: " << t << "s" << endl;
|
||||
|
||||
t = (double)getTickCount();
|
||||
float ans[N] = {0};
|
||||
conv1dsimd(vsrc, k, ans);
|
||||
t = ((double)getTickCount() - t) / getTickFrequency();
|
||||
cout << " Vectorized 1-D convolution implementation: " << t << "s" << endl;
|
||||
|
||||
// 2-D Convolution //
|
||||
help(argv[0]);
|
||||
|
||||
const char *filepath = argc >= 2 ? argv[1] : "../../../../data/lena.jpg";
|
||||
|
||||
Mat src, dst1, dst2, kernel;
|
||||
src = imread(filepath, IMREAD_GRAYSCALE);
|
||||
|
||||
if (src.empty())
|
||||
{
|
||||
cerr << "Can't open [" << filepath << "]" << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
namedWindow("Input", 1);
|
||||
namedWindow("Output", 1);
|
||||
imshow("Input", src);
|
||||
|
||||
kernel = (Mat_<float>(3, 3) << 1, 0, -1,
|
||||
2, 0, -2,
|
||||
1, 0, -1);
|
||||
|
||||
t = (double)getTickCount();
|
||||
|
||||
conv_seq(src, dst1, kernel);
|
||||
|
||||
t = ((double)getTickCount() - t) / getTickFrequency();
|
||||
cout << " Sequential 2-D convolution implementation: " << t << "s" << endl;
|
||||
|
||||
imshow("Output", dst1);
|
||||
waitKey(0);
|
||||
|
||||
t = (double)getTickCount();
|
||||
|
||||
convolute_simd(src, dst2, kernel);
|
||||
|
||||
t = ((double)getTickCount() - t) / getTickFrequency();
|
||||
cout << " Vectorized 2-D convolution implementation: " << t << "s" << endl
|
||||
<< endl;
|
||||
|
||||
imshow("Output", dst2);
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user