diff --git a/CMakeLists.txt b/CMakeLists.txt index 460dafa..a709ecb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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} ) @@ -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} ) #... diff --git a/example_20-01.cpp b/example_20-01.cpp new file mode 100644 index 0000000..859dfc3 --- /dev/null +++ b/example_20-01.cpp @@ -0,0 +1,75 @@ +//Example 20-01. Using K-means +#include +#include + +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(i); + cv::Point ipt = points.at(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; +} diff --git a/example_20-02.cpp b/example_20-02.cpp new file mode 100644 index 0000000..b4d0214 --- /dev/null +++ b/example_20-02.cpp @@ -0,0 +1,92 @@ +//Example 20-02. Using the Mahalanobis distance for classification +#include +#include +#include +#include + +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 clusters(CLUSTER_COUNT); + + for(int i = 0; i < SAMPLE_COUNT; i++) { + int clusterIdx = labels.at(i); + + cv::Point ipt = points.at(i); + + cv::Mat sample(1, 2, CV_32FC1); + sample.at(0, 0) = ipt.x; + sample.at(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 covarMats(CLUSTER_COUNT); + vector 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(0, 0) = rng.uniform(0, img.cols); + newPoint.at(0, 1) = rng.uniform(0, img.rows); + vector 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(0), 5, colorTab[clusterIdx], + cv::FILLED, cv::LINE_AA); + cv::imshow("Example 20-02", img); + } + + cv::destroyAllWindows(); + return 0; +}