Skip to content

Commit

Permalink
Merge pull request oreillymedia#26 from DolotovEvgeniy/learning20
Browse files Browse the repository at this point in the history
Add examples for Chapter 20
  • Loading branch information
garybradski authored Jun 11, 2017
2 parents 0d078c0 + 12900e3 commit 604ff4a
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ add_executable( example_15-BackgroundSubtractor example_15-BackgroundSubtractor.
add_executable( example_16-01 example_16-01.cpp )
add_executable( example_17-01 example_17-01.cpp )
add_executable( example_18-01 example_18-01.cpp )
add_executable( example_20-01 example_20-01.cpp )
add_executable( example_20-02 example_20-02.cpp )
#...

target_link_libraries( example_02-01 ${OpenCV_LIBS} )
Expand Down Expand Up @@ -116,4 +118,6 @@ target_link_libraries( example_15-BackgroundSubtractor ${OpenCV_LIBS} )
target_link_libraries( example_16-01 ${OpenCV_LIBS} )
target_link_libraries( example_17-01 ${OpenCV_LIBS} )
target_link_libraries( example_18-01 ${OpenCV_LIBS} )
target_link_libraries( example_20-01 ${OpenCV_LIBS} )
target_link_libraries( example_20-02 ${OpenCV_LIBS} )
#...
75 changes: 75 additions & 0 deletions example_20-01.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//Example 20-01. Using K-means
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;

static void help(char* argv[]) {
cout << "\nThis program demonstrates kmeans clustering.\n"
" It generates an image with random points, then assigns a random number\n"
" of cluster centers and uses kmeans to move those cluster centers to their\n"
" representative location\n"
"Usage:\n"
<< argv[0] << "\n" << endl;
}

int main(int argc, char** argv) {
const int MAX_CLUSTERS = 5;
cv::Scalar colorTab[] = {
cv::Scalar( 0, 0, 255 ),
cv::Scalar( 0, 255, 0 ),
cv::Scalar( 255, 100, 100 ),
cv::Scalar( 255, 0, 255 ),
cv::Scalar( 0, 255, 255 )
};
cv::Mat img(500, 500, CV_8UC3);
cv::RNG rng(12345);
for(;;) {
int clusterCount = rng.uniform(2, MAX_CLUSTERS+1);
int sampleCount = rng.uniform(1, 1001);
cv::Mat points(sampleCount, 1, CV_32FC2), labels;
clusterCount = MIN(clusterCount, sampleCount);
cv::Mat centers(clusterCount, 1, points.type());
/* generate random sample from multigaussian distribution */
for(int k = 0; k < clusterCount; k++) {
cv::Point center;
center.x = rng.uniform(0, img.cols);
center.y = rng.uniform(0, img.rows);
cv::Mat pointChunk = points.rowRange(
k*sampleCount/clusterCount,
k == clusterCount - 1 ? sampleCount : (k+1)*sampleCount/clusterCount
);
rng.fill(
pointChunk,
cv::RNG::NORMAL,
cv::Scalar(center.x, center.y),
cv::Scalar(img.cols*0.05, img.rows*0.05)
);
}
randShuffle(points, 1, &rng);
kmeans(
points,
clusterCount,
labels,
cv::TermCriteria(
cv::TermCriteria::EPS | cv::TermCriteria::COUNT,
10,
1.0
),
3,
cv::KMEANS_PP_CENTERS,
centers
);
img = cv::Scalar::all(0);
for(int i = 0; i < sampleCount; i++) {
int clusterIdx = labels.at<int>(i);
cv::Point ipt = points.at<cv::Point2f>(i);
cv::circle(img, ipt, 2, colorTab[clusterIdx], cv::FILLED, cv::LINE_AA);
}
cv::imshow("Example 20-01", img);
char key = (char)cv::waitKey();
if(key == 27 || key == 'q' || key == 'Q') // 'ESC'
break;
}
return 0;
}
92 changes: 92 additions & 0 deletions example_20-02.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//Example 20-02. Using the Mahalanobis distance for classification
#include <opencv2/opencv.hpp>
#include <iostream>
#include <ctime>
#include <algorithm>

using namespace std;

const int CLUSTER_COUNT = 4;
const int SAMPLE_COUNT = 500;
const cv::Scalar colorTab[] = {
cv::Scalar( 0, 0, 255 ),
cv::Scalar( 0, 255, 0 ),
cv::Scalar( 255, 0, 0 ),
cv::Scalar( 255, 0, 255 ),
cv::Scalar( 0, 255, 255 )
};

static void help(char* argv[]) {
cout << "\nThis program demonstrates using the Mahalanobis distance for classification.\n"
" It generates an image with random points, uses kmeans clustering.\n"
" And then uses the Mahalanobis distance for classification.\n"
"Usage:\n"
<< argv[0] << "\n" << endl;
}
int main(int argc, char** argv) {
cv::Mat img(500, 500, CV_8UC3, cv::Scalar::all(0));

cv::Mat points(SAMPLE_COUNT, 1, CV_32FC2);
cv::RNG rng(time(NULL));
rng.fill(points, cv::RNG::UNIFORM, cv::Scalar(0, 0), cv::Scalar(img.cols, img.rows));

cv::Mat labels;
kmeans(points, CLUSTER_COUNT, labels,
cv::TermCriteria(cv::TermCriteria::EPS | cv::TermCriteria::COUNT,
10, 1.0),
3,
cv::KMEANS_PP_CENTERS
);

vector<cv::Mat> clusters(CLUSTER_COUNT);

for(int i = 0; i < SAMPLE_COUNT; i++) {
int clusterIdx = labels.at<int>(i);

cv::Point ipt = points.at<cv::Point2f>(i);

cv::Mat sample(1, 2, CV_32FC1);
sample.at<float>(0, 0) = ipt.x;
sample.at<float>(0, 1) = ipt.y;
clusters[clusterIdx].push_back(sample);
cv::circle(img, ipt, 2, colorTab[clusterIdx], cv::FILLED, cv::LINE_AA);
}
cv::namedWindow("Example 20-02");
cv::imshow("Example 20-02", img);

vector<cv::Mat> covarMats(CLUSTER_COUNT);
vector<cv::Mat> means(CLUSTER_COUNT);
for(int i = 0; i < CLUSTER_COUNT; i++) {
cv::calcCovarMatrix(clusters[i], covarMats[i], means[i],
CV_COVAR_NORMAL | CV_COVAR_ROWS, 5);

}

cout << "Press any button to classify the next point!\n"
<< "Press ESC to exit." << endl;

for(;;) {
char key = (char)cv::waitKey();
if( key == 27 ) break;

cv::Mat newPoint(1, 2, CV_32FC1);
newPoint.at<float>(0, 0) = rng.uniform(0, img.cols);
newPoint.at<float>(0, 1) = rng.uniform(0, img.rows);
vector<float> mahalanobisDistance(CLUSTER_COUNT);

for(int i = 0; i < CLUSTER_COUNT; i++) {
mahalanobisDistance[i] = cv::Mahalanobis(newPoint, means[i],
covarMats[i]);
}
int clusterIdx = std::distance( mahalanobisDistance.begin(),
min_element(mahalanobisDistance.begin(),
mahalanobisDistance.end()));

cv::circle(img, newPoint.at<cv::Point2f>(0), 5, colorTab[clusterIdx],
cv::FILLED, cv::LINE_AA);
cv::imshow("Example 20-02", img);
}

cv::destroyAllWindows();
return 0;
}

0 comments on commit 604ff4a

Please sign in to comment.