diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..eabe14b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,43 @@ +#Specify the version being used aswell as the language +cmake_minimum_required(VERSION 2.8.11) + +#Name your project here +project(pointmets) + +#set the module directory +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}") + +#find the STIM library +find_package(STIM REQUIRED) + +#find the approximate nearest neighbor library +find_package(ANN REQUIRED) + +#find the pthreads package +find_package(Threads) + +include_directories( + ${STIM_INCLUDE_DIRS} + ${ANN_INCLUDE_DIR} + ) + +#Assign source files to the appropriate variables +file(GLOB SRC_CPP "*.cpp") +file(GLOB SRC_H "*.h") + +#create an executable file +add_executable(pointmets + ${SRC_H} + ${SRC_CPP} + ) + +#set the link libraries +target_link_libraries(pointmets + ${CMAKE_THREAD_LIBS_INIT} + ${ANN_LIBRARY} + ) + +#copy an OBJ test case +configure_file(data/blue_gt.txt blue_gt.txt COPYONLY) +configure_file(data/blue_t.txt blue_t.txt COPYONLY) +configure_file(data/blue_gt.bmp blue_gt.bmp COPYONLY) \ No newline at end of file diff --git a/FindANN.cmake b/FindANN.cmake new file mode 100644 index 0000000..c4b5649 --- /dev/null +++ b/FindANN.cmake @@ -0,0 +1,42 @@ +# - Try to find ANN +# Once done this will define +# +# ANN_FOUND - system has ANN +# ANN_INCLUDE_DIR - the ANN include directory +# ANN_LIBRARY - Link these to use ANN +# + +IF (ANN_INCLUDE_DIRS) + # Already in cache, be silent + SET(ANN_FIND_QUIETLY TRUE) +ENDIF (ANN_INCLUDE_DIRS) + +FIND_PATH( ANN_INCLUDE_DIR ANN/ANN.h + PATHS "/usr/include" "C:/libs/ANN/include") + +if( WIN32 ) + + set(ANN_LIBRARY $ENV{ANN_PATH}\\ANN.lib) + set(ANN_INCLUDE_DIR $ENV{ANN_PATH}) + + + # Store the library dir. May be used for linking to dll! + # GET_FILENAME_COMPONENT( ANN_LIBRARY_DIR ${ANN_LIBRARY} PATH ) + + find_package_handle_standard_args(ANN DEFAULT_MSG ANN_INCLUDE_DIR) + +else (WIN32) + + FIND_LIBRARY( ANN_LIBRARY + NAMES ann ANN + PATHS /lib /usr/lib /usr/lib64 /usr/local/lib ) + +endif( WIN32) + + +IF (ANN_INCLUDE_DIR AND ANN_LIBRARY) + SET(ANN_FOUND TRUE) +ELSE (ANN_INCLUDE_DIR AND ANN_LIBRARY) + SET( ANN_FOUND FALSE ) +ENDIF (ANN_INCLUDE_DIR AND ANN_LIBRARY) + diff --git a/FindSTIM.cmake b/FindSTIM.cmake new file mode 100644 index 0000000..700157d --- /dev/null +++ b/FindSTIM.cmake @@ -0,0 +1,9 @@ +include(FindPackageHandleStandardArgs) + +set(STIM_INCLUDE_DIR $ENV{STIMLIB_PATH}) + +find_package_handle_standard_args(STIM DEFAULT_MSG STIM_INCLUDE_DIR) + +if(STIM_FOUND) + set(STIM_INCLUDE_DIRS ${STIM_INCLUDE_DIR}) +endif() \ No newline at end of file diff --git a/data/blue_gt.bmp b/data/blue_gt.bmp new file mode 100644 index 0000000..354a11c Binary files /dev/null and b/data/blue_gt.bmp differ diff --git a/data/blue_gt.txt b/data/blue_gt.txt new file mode 100644 index 0000000..7d0c82e --- /dev/null +++ b/data/blue_gt.txt @@ -0,0 +1,210 @@ +3 686 +19 537 +46 587 +57 785 +73 465 +99 367 +103 657 +109 1038 +115 304 +149 665 +175 984 +187 324 +191 1069 +200 628 +205 566 +218 388 +242 494 +242 633 +249 288 +249 745 +259 442 +270 193 +292 984 +297 539 +297 688 +313 463 +322 342 +329 842 +337 304 +342 407 +380 517 +382 1003 +394 306 +398 372 +400 1071 +401 658 +410 236 +419 585 +421 421 +433 101 +433 182 +433 793 +435 492 +471 341 +474 515 +479 244 +480 1012 +484 310 +485 873 +489 95 +498 174 +501 443 +501 772 +504 388 +524 338 +529 239 +531 488 +544 556 +558 411 +561 99 +562 276 +566 728 +574 624 +574 1044 +578 220 +580 146 +586 44 +605 326 +606 385 +611 536 +620 95 +625 692 +636 458 +642 213 +645 578 +650 37 +653 283 +656 735 +659 387 +669 106 +698 528 +700 460 +703 10 +708 1073 +711 382 +713 884 +715 292 +715 667 +721 197 +724 735 +731 233 +736 57 +737 582 +746 638 +748 158 +763 483 +775 706 +777 202 +779 531 +779 950 +787 599 +793 102 +793 322 +794 1074 +797 368 +816 278 +829 478 +831 648 +836 191 +840 730 +847 106 +847 938 +849 559 +850 377 +854 814 +874 676 +875 215 +877 329 +879 174 +896 438 +897 22 +904 868 +906 733 +909 217 +910 265 +918 589 +930 645 +931 143 +937 492 +937 690 +945 824 +947 234 +949 408 +965 310 +970 88 +979 135 +979 450 +979 539 +981 290 +999 213 +999 937 +1003 1007 +1004 380 +1019 832 +1029 183 +1029 312 +1035 744 +1036 68 +1063 556 +1083 165 +1083 423 +1092 729 +1099 11 +1099 344 +1104 241 +1117 106 +1118 827 +1129 666 +1133 485 +1149 19 +1157 152 +1159 570 +1160 410 +1176 325 +1179 244 +1185 702 +1189 778 +1192 472 +1217 559 +1222 202 +1244 95 +1245 310 +1251 255 +1252 142 +1253 422 +1278 474 +1280 567 +1304 177 +1309 710 +1338 329 +1339 255 +1339 413 +1363 555 +1363 678 +1364 489 +1367 180 +1369 107 +1384 774 +1405 339 +1447 624 +1453 426 +1461 133 +1462 357 +1473 853 +1488 500 +1488 766 +1516 642 +1551 484 +1578 837 +1588 331 +1603 741 +1632 628 +1635 367 +1641 472 +1654 566 +1686 924 +1704 819 +1754 694 +1777 785 +1852 381 \ No newline at end of file diff --git a/data/blue_t.txt b/data/blue_t.txt new file mode 100644 index 0000000..e6239ab --- /dev/null +++ b/data/blue_t.txt @@ -0,0 +1,214 @@ +2 680 +28 535 +44 588 +57 786 +66 556 +73 463 +100 368 +101 657 +113 1037 +116 303 +148 670 +186 325 +186 985 +191 1075 +193 627 +205 562 +218 387 +220 875 +244 749 +245 631 +246 491 +252 287 +259 444 +274 196 +283 1075 +300 543 +300 980 +302 685 +316 464 +324 340 +332 842 +338 306 +344 408 +381 518 +387 998 +397 371 +398 306 +402 1070 +406 661 +409 237 +419 583 +425 420 +433 182 +434 100 +436 797 +442 494 +472 339 +473 519 +478 246 +479 322 +484 873 +488 1004 +490 94 +498 174 +503 773 +504 442 +507 388 +525 338 +527 243 +535 487 +543 558 +559 416 +561 98 +563 278 +569 731 +573 625 +577 223 +577 1036 +583 145 +586 43 +606 327 +607 387 +611 536 +620 98 +628 690 +634 458 +644 215 +644 582 +648 36 +652 286 +656 740 +660 386 +669 105 +697 531 +700 461 +707 0 +709 1075 +713 381 +715 666 +715 883 +717 295 +724 204 +726 741 +731 230 +737 587 +739 57 +744 157 +744 641 +764 479 +774 950 +778 706 +780 205 +781 531 +790 603 +792 314 +794 104 +795 1075 +798 374 +817 282 +832 478 +832 647 +837 193 +842 731 +846 104 +847 382 +848 814 +851 562 +854 936 +877 213 +878 172 +878 333 +880 674 +897 26 +897 437 +903 220 +906 870 +911 264 +913 737 +918 591 +933 142 +936 494 +936 649 +946 690 +946 821 +947 232 +954 405 +970 89 +970 303 +977 136 +983 542 +985 451 +995 934 +1002 209 +1006 381 +1007 1011 +1024 189 +1025 834 +1029 311 +1031 744 +1035 70 +1064 557 +1082 164 +1083 423 +1094 733 +1099 12 +1101 342 +1105 244 +1116 828 +1120 103 +1123 661 +1130 488 +1149 23 +1156 572 +1157 154 +1161 411 +1176 244 +1177 326 +1187 702 +1195 780 +1196 472 +1219 563 +1221 203 +1242 315 +1244 94 +1250 258 +1251 143 +1253 423 +1277 862 +1281 479 +1283 570 +1302 712 +1306 176 +1336 331 +1338 258 +1338 415 +1363 490 +1365 559 +1365 683 +1367 181 +1369 106 +1384 777 +1401 338 +1404 883 +1436 629 +1452 429 +1462 132 +1464 363 +1474 859 +1481 504 +1485 772 +1516 646 +1550 487 +1578 841 +1585 331 +1601 744 +1629 632 +1636 370 +1639 473 +1649 569 +1683 928 +1699 823 +1750 700 +1771 787 +1848 384 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1fffda0 --- /dev/null +++ b/main.cpp @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//load a set of points from an ASCII file +std::vector< stim::vec > points_from_list(std::string filename){ + + std::vector< stim::vec > result; //create an array to store the result + + std::string str; + + //load the ground truth + std::ifstream gfile(filename.c_str()); + while(std::getline(gfile, str)){ + stim::vec v(str); + result.push_back(v); + } + + return result; //return the list of points +} + +//load a set of points from an image (nonzero values are point positions) +std::vector< stim::vec > points_from_image(std::string filename){ + + stim::image I; //create an image object + + I.load(filename); //load the image file + + std::vector idx = I.sparse_idx(); //get the 1D indices for each nonzero pixel + + std::vector< stim::vec > result; //generate an array to store the 2D pixel positions + result.resize(idx.size()); //allocate the space to save time + + unsigned long w = I.width(); //get the image width (used to resolve the 2D pixel position from the 1D index) + + unsigned long x, y; + for(unsigned long i = 0; i < idx.size(); i++){ + y = idx[i] / w; + x = idx[i] - y * w; + + result[i] = stim::vec(x, y); + } + + + return result; //return the array of points + +} + +/// This function calculates the number of hits ( +void calc_hitlist(std::vector< unsigned int >& hits, + std::vector< float >& dists, + std::vector< stim::vec > data, + std::vector< stim::vec > query){ + + int n_data = data.size(); + int n_query = query.size(); + + //allocate space in the hit lists + hits.resize(n_query); + dists.resize(n_query); + + //calculate the spatial dimension + unsigned int dim = 1; + for(unsigned int i = 0; i < data.size(); i++) + if(data[i].size() > dim) dim = data[i].size(); + + //number of data points + ANNpointArray dataPts = annAllocPts(n_data, dim); //array of data points + ANNpoint queryPt = annAllocPt(dim); //query point + ANNidxArray nnIdx = new ANNidx[1]; //indices of nearest neighbors + ANNdistArray sq_dist = new ANNdist[1]; //array of squared distances to nearest neighbors + + //load the ground truth points into the ANN point array + for(unsigned int i = 0; i < data.size(); i++){ + for(unsigned int d = 0; d < dim; d++){ + dataPts[i][d] = data[i][d]; + } + } + + //create a KD-tree + ANNkd_tree* kdTree; //KD tree search structure + kdTree = new ANNkd_tree(dataPts, n_data, dim); //create the KD tree search structure + + + //submit each query point to the KD tree to find the nearest neighbor + for(unsigned int q = 0; q < n_query; q++){ + + for(unsigned int d = 0; d < dim; d++){ + queryPt[d] = query[q][d]; + } + + //query the KD-tree + kdTree->annkSearch(queryPt, 1, nnIdx, sq_dist); + + //put the result in the hit array + hits[q] = nnIdx[0]; + dists[q] = sqrt(sq_dist[0]); + } +} + +int main(int argc, char** argv){ + + //output advertisement + std::cout< > G; + std::vector< stim::vec > T; + + + //if an ASCII list of points is specified + if(gfilename.get_extension() == "bmp") + G = points_from_image(gfilename.str()); + else + G = points_from_list(gfilename.str()); + + if(tfilename.get_extension() == "bmp") + T = points_from_image(gfilename.str()); + else + T = points_from_list(tfilename.str()); + + //calculate the hit list and distances for the test array + std::vector< unsigned int > T_hits; + std::vector< float > T_dists; + calc_hitlist(T_hits, T_dists, G, T); + + //calculate the hit list and distances for the ground truth array + std::vector< unsigned int > G_hits; + std::vector< float > G_dists; + calc_hitlist(G_hits, G_dists, T, G); + + //count up metrics for each test point + std::vector< unsigned int > TP; + std::vector< unsigned int > FP; + unsigned int g, t; + for(t = 0; t < T.size(); t++){ + + //a true positive has a matching hit in both hit lists, with a distance less than the radius + g = T_hits[t]; + if(G_hits[g] == t && T_dists[t] <= r) TP.push_back(t); + else FP.push_back(t); + } + + std::vector< unsigned int > FN; + for(g = 0; g < G.size(); g++){ + t = G_hits[g]; + if(T_hits[t] != g || G_dists[g] > r) FN.push_back(g); + } + + std::cout<<"N: "<