From 2f70e503fc618eaf8200eeac43cefe1d4b033cc3 Mon Sep 17 00:00:00 2001 From: sidn77 Date: Sat, 8 Jul 2017 00:11:52 +0530 Subject: [PATCH 1/4] Added new functions with docs --- data/argset3.dat | Bin 0 -> 68564 bytes data/emclassi3.yml | 51620 ++++++++++++++++ data/knnclassi3.yml | 31570 ++++++++++ help/builder_help.sce | 21 + help/builder_help.sce~ | 21 + help/en_US/blobAnalysis.xml | 94 + help/en_US/build_help.sce | 17 + help/en_US/build_help.sce~ | 17 + help/en_US/decorrstretch.xml | 74 + help/en_US/detectAndComputeORB.xml | 106 + help/en_US/detectBRISKFeatures.xml | 94 + help/en_US/detectFASTFeatures.xml | 113 + help/en_US/detectHarrisFeatures.xml | 86 + help/en_US/detectSURFFeatures.xml | 95 + help/en_US/disparity.xml | 98 + help/en_US/disparity.xml~ | 95 + help/en_US/filter.xml | 88 + help/en_US/ftrans2.xml | 72 + help/en_US/getParams.xml | 91 + help/en_US/getParams.xml~ | 91 + help/en_US/graydiffweight.xml | 80 + help/en_US/imabsdiff.xml | 82 + help/en_US/imboxfilt3.xml | 113 + help/en_US/imboxfilt3.xml~ | 107 + help/en_US/imcontrast.xml | 77 + help/en_US/imcrop.xml | 79 + help/en_US/imextendedmax.xml | 75 + help/en_US/imfindcircles.xml | 82 + help/en_US/imwrite.xml | 73 + help/en_US/integralFilter.xml | 81 + help/en_US/isFilter.xml | 77 + help/en_US/master_help.xml | 85 + help/en_US/matchFeatures.xml | 124 + help/en_US/mlPredict.xml | 96 + help/en_US/reconstructScene.xml | 93 + help/en_US/scharr.xml | 82 + help/en_US/scharr.xml~ | 82 + .../scilab_en_US_help/JavaHelpSearch/DOCS | Bin 0 -> 3569 bytes .../scilab_en_US_help/JavaHelpSearch/DOCS.TAB | 5 + .../scilab_en_US_help/JavaHelpSearch/OFFSETS | Bin 0 -> 134 bytes .../JavaHelpSearch/POSITIONS | Bin 0 -> 13270 bytes .../scilab_en_US_help/JavaHelpSearch/SCHEMA | 2 + .../scilab_en_US_help/JavaHelpSearch/TMAP | Bin 0 -> 14336 bytes .../en_US/scilab_en_US_help/ScilabCaution.png | Bin 0 -> 513 bytes help/en_US/scilab_en_US_help/ScilabEdit.png | Bin 0 -> 414 bytes .../en_US/scilab_en_US_help/ScilabExecute.png | Bin 0 -> 535 bytes .../scilab_en_US_help/ScilabImportant.png | Bin 0 -> 637 bytes help/en_US/scilab_en_US_help/ScilabNote.png | Bin 0 -> 687 bytes help/en_US/scilab_en_US_help/ScilabTip.png | Bin 0 -> 687 bytes .../en_US/scilab_en_US_help/ScilabWarning.png | Bin 0 -> 513 bytes .../scilab_en_US_help/_LaTeX_filter.xml_1.png | Bin 0 -> 3449 bytes .../_LaTeX_imboxfilt3.xml_1.png | Bin 0 -> 919 bytes .../_LaTeX_imboxfilt3.xml_2.png | Bin 0 -> 3250 bytes .../en_US/scilab_en_US_help/blobAnalysis.html | 102 + help/en_US/scilab_en_US_help/c_code.css | 54 + .../scilab_en_US_help/decorrstretch.html | 84 + .../detectAndComputeORB.html | 114 + .../detectBRISKFeatures.html | 104 + .../scilab_en_US_help/detectFASTFeatures.html | 118 + .../detectHarrisFeatures.html | 96 + .../scilab_en_US_help/detectSURFFeatures.html | 105 + help/en_US/scilab_en_US_help/disparity.html | 108 + help/en_US/scilab_en_US_help/disparity.html~ | 107 + help/en_US/scilab_en_US_help/filter.html | 96 + help/en_US/scilab_en_US_help/ftrans2.html | 86 + help/en_US/scilab_en_US_help/getParams.html | 96 + .../scilab_en_US_help/graydiffweight.html | 90 + help/en_US/scilab_en_US_help/imabsdiff.html | 92 + help/en_US/scilab_en_US_help/imboxfilt3.html | 98 + help/en_US/scilab_en_US_help/imcontrast.html | 87 + help/en_US/scilab_en_US_help/imcrop.html | 89 + .../scilab_en_US_help/imextendedmax.html | 85 + .../scilab_en_US_help/imfindcircles.html | 92 + help/en_US/scilab_en_US_help/imwrite.html | 83 + help/en_US/scilab_en_US_help/index.html | 241 + .../scilab_en_US_help/integralFilter.html | 91 + help/en_US/scilab_en_US_help/isFilter.html | 86 + help/en_US/scilab_en_US_help/jhelpidx.xml | 3 + help/en_US/scilab_en_US_help/jhelpmap.jhm | 38 + help/en_US/scilab_en_US_help/jhelpset.hs | 28 + help/en_US/scilab_en_US_help/jhelptoc.xml | 40 + .../scilab_en_US_help/matchFeatures.html | 129 + help/en_US/scilab_en_US_help/mlPredict.html | 101 + .../scilab_en_US_help/reconstructScene.html | 103 + help/en_US/scilab_en_US_help/scharr.html | 92 + help/en_US/scilab_en_US_help/scilab_code.css | 96 + ...tion_c28e37d78ba50cc67245894dd02440a0.html | 241 + help/en_US/scilab_en_US_help/sepFilter2D.html | 97 + .../stereoCalibrateAndRect.html | 105 + help/en_US/scilab_en_US_help/style.css | 350 + .../scilab_en_US_help/trainEMClassifier.html | 104 + .../scilab_en_US_help/trainKNNClassifier.html | 103 + .../scilab_en_US_help/trainLRClassifier.html | 114 + .../scilab_en_US_help/triangulatePoints.html | 89 + help/en_US/scilab_en_US_help/whitepoint.html | 89 + help/en_US/scilab_en_US_help/xml_code.css | 94 + help/en_US/sepFilter2D.xml | 87 + help/en_US/stereoCalibrateAndRect.xml | 95 + help/en_US/trainEMClassifier.xml | 99 + help/en_US/trainKNNClassifier.xml | 98 + help/en_US/trainLRClassifier.xml | 109 + help/en_US/trainLRClassifier.xml~ | 106 + help/en_US/triangulatePoints.xml | 75 + help/en_US/whitepoint.xml | 81 + help/en_US/whitepoint.xml~ | 81 + images/bike.jpg | Bin 0 -> 7729 bytes images/blob.jpg | Bin 0 -> 16923 bytes images/checkerBoard.jpg | Bin 0 -> 58854 bytes images/chess.jpg | Bin 0 -> 248619 bytes images/left1.jpg | Bin 0 -> 52016 bytes images/lena.jpg | Bin 0 -> 1333 bytes images/plane.jpg | Bin 0 -> 6322 bytes images/right1.jpg | Bin 0 -> 52760 bytes images/table.jpg | Bin 0 -> 9756 bytes images/table1.jpg | Bin 0 -> 7205 bytes macros/blobAnalysis.bin | Bin 0 -> 22572 bytes macros/blobAnalysis.sci | 140 + macros/decorrstretch.bin | Bin 0 -> 3972 bytes macros/decorrstretch.sci | 55 + macros/detectAndComputeORB.bin | Bin 0 -> 47820 bytes macros/detectAndComputeORB.sci | 257 + macros/detectBRISKFeatures.bin | Bin 0 -> 12612 bytes macros/detectBRISKFeatures.sci | 73 + macros/detectFASTFeatures.bin | Bin 0 -> 13628 bytes macros/detectFASTFeatures.sci | 85 + macros/detectHarrisFeatures.bin | Bin 0 -> 9156 bytes macros/detectHarrisFeatures.sci | 68 + macros/detectORB.bin | Bin 0 -> 40036 bytes macros/detectORB.sci | 226 + macros/detectSURFFeatures.bin | Bin 0 -> 15540 bytes macros/detectSURFFeatures.sci | 74 + macros/disparity.bin | Bin 0 -> 15176 bytes macros/disparity.sci | 107 + macros/filter.bin | Bin 0 -> 6528 bytes macros/filter.sci | 53 + macros/ftrans2.bin | Bin 0 -> 4828 bytes macros/ftrans2.sci | 55 + macros/getParams.bin | Bin 0 -> 18584 bytes macros/getParams.sci | 124 + macros/graydiffweight.bin | Bin 0 -> 5680 bytes macros/graydiffweight.sci | 51 + macros/imabsdiff.bin | Bin 0 -> 6944 bytes macros/imabsdiff.sci | 65 + macros/imboxfilt3.bin | Bin 0 -> 7052 bytes macros/imboxfilt3.sci | 83 + macros/imcontrast.bin | Bin 0 -> 3180 bytes macros/imcontrast.sci | 46 + macros/imcrop.bin | Bin 0 -> 4272 bytes macros/imcrop.sci | 46 + macros/imextendedmax.bin | Bin 0 -> 3548 bytes macros/imextendedmax.sci | 47 + macros/imfindcircles.bin | Bin 0 -> 5528 bytes macros/imfindcircles.sci | 62 + macros/imwrite.bin | Bin 0 -> 3132 bytes macros/imwrite.sci | 43 + macros/integralFilter.bin | Bin 0 -> 5512 bytes macros/integralFilter.sci | 55 + macros/isFilter.bin | Bin 0 -> 4140 bytes macros/isFilter.sci | 47 + macros/matchFeatures.bin | Bin 0 -> 17244 bytes macros/matchFeatures.sci | 98 + macros/mlPredict.bin | Bin 0 -> 9940 bytes macros/mlPredict.sci | 107 + macros/reconstructScene.bin | Bin 0 -> 8232 bytes macros/reconstructScene.sci | 75 + macros/scharr.bin | Bin 0 -> 4904 bytes macros/scharr.sci | 50 + macros/sepFilter2D.bin | Bin 0 -> 8928 bytes macros/sepFilter2D.sci | 64 + macros/stereoCalibrateAndRect.bin | Bin 0 -> 14804 bytes macros/stereoCalibrateAndRect.sci | 82 + macros/trainEMClassifier.bin | Bin 0 -> 8600 bytes macros/trainEMClassifier.sci | 77 + macros/trainKNNClassifier.bin | Bin 0 -> 8048 bytes macros/trainKNNClassifier.sci | 73 + macros/trainLRClassifier.bin | Bin 0 -> 15460 bytes macros/trainLRClassifier.sci | 94 + macros/triangulatePoints.bin | Bin 0 -> 5092 bytes macros/triangulatePoints.sci | 42 + macros/whitepoint.bin | Bin 0 -> 9072 bytes macros/whitepoint.sci | 46 + sci_gateway/cpp/opencv_decorrstretch.cpp | 145 + .../cpp/opencv_detectAndComputeORB.cpp | 660 + .../cpp/opencv_detectBRISKFeatures.cpp | 449 + sci_gateway/cpp/opencv_detectFASTFeatures.cpp | 594 + .../cpp/opencv_detectHarrisFeatures.cpp | 350 + sci_gateway/cpp/opencv_detectORB.cpp | 636 + sci_gateway/cpp/opencv_detectSURFFeatures.cpp | 446 + sci_gateway/cpp/opencv_disparity.cpp | 499 + sci_gateway/cpp/opencv_filter2D.cpp | 193 + sci_gateway/cpp/opencv_ftrans2.cpp | 208 + sci_gateway/cpp/opencv_getParamsEM.cpp | 214 + sci_gateway/cpp/opencv_getParamsKNN.cpp | 207 + sci_gateway/cpp/opencv_getParamsLR.cpp | 254 + sci_gateway/cpp/opencv_graydiffweight.cpp | 97 + sci_gateway/cpp/opencv_imabsdiff.cpp | 59 + sci_gateway/cpp/opencv_imboxfilt3.cpp | 140 + sci_gateway/cpp/opencv_imcontrast.cpp | 99 + sci_gateway/cpp/opencv_imcrop.cpp | 138 + sci_gateway/cpp/opencv_imextendedmax.cpp | 119 + sci_gateway/cpp/opencv_imfindcircles.cpp | 155 + sci_gateway/cpp/opencv_imwrite.cpp | 93 + sci_gateway/cpp/opencv_integralFilter.cpp | 252 + sci_gateway/cpp/opencv_isFilter.cpp | 294 + sci_gateway/cpp/opencv_matchFeatures.cpp | 592 + sci_gateway/cpp/opencv_predictEM.cpp | 324 + sci_gateway/cpp/opencv_predictKNN.cpp | 336 + sci_gateway/cpp/opencv_predictLR.cpp | 295 + sci_gateway/cpp/opencv_reconstructScene.cpp | 126 + sci_gateway/cpp/opencv_scharr.cpp | 165 + sci_gateway/cpp/opencv_sepFilter2D.cpp | 271 + .../cpp/opencv_stereoCalibrateAndRect.cpp | 609 + sci_gateway/cpp/opencv_trainEMClassifier.cpp | 519 + sci_gateway/cpp/opencv_trainKNNClassifier.cpp | 517 + sci_gateway/cpp/opencv_trainLRClassifier.cpp | 696 + sci_gateway/cpp/opencv_whitepoint.cpp | 121 + 216 files changed, 104751 insertions(+) create mode 100644 data/argset3.dat create mode 100644 data/emclassi3.yml create mode 100644 data/knnclassi3.yml create mode 100644 help/builder_help.sce create mode 100644 help/builder_help.sce~ create mode 100644 help/en_US/blobAnalysis.xml create mode 100644 help/en_US/build_help.sce create mode 100644 help/en_US/build_help.sce~ create mode 100644 help/en_US/decorrstretch.xml create mode 100644 help/en_US/detectAndComputeORB.xml create mode 100644 help/en_US/detectBRISKFeatures.xml create mode 100644 help/en_US/detectFASTFeatures.xml create mode 100644 help/en_US/detectHarrisFeatures.xml create mode 100644 help/en_US/detectSURFFeatures.xml create mode 100644 help/en_US/disparity.xml create mode 100644 help/en_US/disparity.xml~ create mode 100644 help/en_US/filter.xml create mode 100644 help/en_US/ftrans2.xml create mode 100644 help/en_US/getParams.xml create mode 100644 help/en_US/getParams.xml~ create mode 100644 help/en_US/graydiffweight.xml create mode 100644 help/en_US/imabsdiff.xml create mode 100644 help/en_US/imboxfilt3.xml create mode 100644 help/en_US/imboxfilt3.xml~ create mode 100644 help/en_US/imcontrast.xml create mode 100644 help/en_US/imcrop.xml create mode 100644 help/en_US/imextendedmax.xml create mode 100644 help/en_US/imfindcircles.xml create mode 100644 help/en_US/imwrite.xml create mode 100644 help/en_US/integralFilter.xml create mode 100644 help/en_US/isFilter.xml create mode 100644 help/en_US/master_help.xml create mode 100644 help/en_US/matchFeatures.xml create mode 100644 help/en_US/mlPredict.xml create mode 100644 help/en_US/reconstructScene.xml create mode 100644 help/en_US/scharr.xml create mode 100644 help/en_US/scharr.xml~ create mode 100644 help/en_US/scilab_en_US_help/JavaHelpSearch/DOCS create mode 100644 help/en_US/scilab_en_US_help/JavaHelpSearch/DOCS.TAB create mode 100644 help/en_US/scilab_en_US_help/JavaHelpSearch/OFFSETS create mode 100644 help/en_US/scilab_en_US_help/JavaHelpSearch/POSITIONS create mode 100644 help/en_US/scilab_en_US_help/JavaHelpSearch/SCHEMA create mode 100644 help/en_US/scilab_en_US_help/JavaHelpSearch/TMAP create mode 100644 help/en_US/scilab_en_US_help/ScilabCaution.png create mode 100644 help/en_US/scilab_en_US_help/ScilabEdit.png create mode 100644 help/en_US/scilab_en_US_help/ScilabExecute.png create mode 100644 help/en_US/scilab_en_US_help/ScilabImportant.png create mode 100644 help/en_US/scilab_en_US_help/ScilabNote.png create mode 100644 help/en_US/scilab_en_US_help/ScilabTip.png create mode 100644 help/en_US/scilab_en_US_help/ScilabWarning.png create mode 100644 help/en_US/scilab_en_US_help/_LaTeX_filter.xml_1.png create mode 100644 help/en_US/scilab_en_US_help/_LaTeX_imboxfilt3.xml_1.png create mode 100644 help/en_US/scilab_en_US_help/_LaTeX_imboxfilt3.xml_2.png create mode 100644 help/en_US/scilab_en_US_help/blobAnalysis.html create mode 100644 help/en_US/scilab_en_US_help/c_code.css create mode 100644 help/en_US/scilab_en_US_help/decorrstretch.html create mode 100644 help/en_US/scilab_en_US_help/detectAndComputeORB.html create mode 100644 help/en_US/scilab_en_US_help/detectBRISKFeatures.html create mode 100644 help/en_US/scilab_en_US_help/detectFASTFeatures.html create mode 100644 help/en_US/scilab_en_US_help/detectHarrisFeatures.html create mode 100644 help/en_US/scilab_en_US_help/detectSURFFeatures.html create mode 100644 help/en_US/scilab_en_US_help/disparity.html create mode 100644 help/en_US/scilab_en_US_help/disparity.html~ create mode 100644 help/en_US/scilab_en_US_help/filter.html create mode 100644 help/en_US/scilab_en_US_help/ftrans2.html create mode 100644 help/en_US/scilab_en_US_help/getParams.html create mode 100644 help/en_US/scilab_en_US_help/graydiffweight.html create mode 100644 help/en_US/scilab_en_US_help/imabsdiff.html create mode 100644 help/en_US/scilab_en_US_help/imboxfilt3.html create mode 100644 help/en_US/scilab_en_US_help/imcontrast.html create mode 100644 help/en_US/scilab_en_US_help/imcrop.html create mode 100644 help/en_US/scilab_en_US_help/imextendedmax.html create mode 100644 help/en_US/scilab_en_US_help/imfindcircles.html create mode 100644 help/en_US/scilab_en_US_help/imwrite.html create mode 100644 help/en_US/scilab_en_US_help/index.html create mode 100644 help/en_US/scilab_en_US_help/integralFilter.html create mode 100644 help/en_US/scilab_en_US_help/isFilter.html create mode 100644 help/en_US/scilab_en_US_help/jhelpidx.xml create mode 100644 help/en_US/scilab_en_US_help/jhelpmap.jhm create mode 100644 help/en_US/scilab_en_US_help/jhelpset.hs create mode 100644 help/en_US/scilab_en_US_help/jhelptoc.xml create mode 100644 help/en_US/scilab_en_US_help/matchFeatures.html create mode 100644 help/en_US/scilab_en_US_help/mlPredict.html create mode 100644 help/en_US/scilab_en_US_help/reconstructScene.html create mode 100644 help/en_US/scilab_en_US_help/scharr.html create mode 100644 help/en_US/scilab_en_US_help/scilab_code.css create mode 100644 help/en_US/scilab_en_US_help/section_c28e37d78ba50cc67245894dd02440a0.html create mode 100644 help/en_US/scilab_en_US_help/sepFilter2D.html create mode 100644 help/en_US/scilab_en_US_help/stereoCalibrateAndRect.html create mode 100644 help/en_US/scilab_en_US_help/style.css create mode 100644 help/en_US/scilab_en_US_help/trainEMClassifier.html create mode 100644 help/en_US/scilab_en_US_help/trainKNNClassifier.html create mode 100644 help/en_US/scilab_en_US_help/trainLRClassifier.html create mode 100644 help/en_US/scilab_en_US_help/triangulatePoints.html create mode 100644 help/en_US/scilab_en_US_help/whitepoint.html create mode 100644 help/en_US/scilab_en_US_help/xml_code.css create mode 100644 help/en_US/sepFilter2D.xml create mode 100644 help/en_US/stereoCalibrateAndRect.xml create mode 100644 help/en_US/trainEMClassifier.xml create mode 100644 help/en_US/trainKNNClassifier.xml create mode 100644 help/en_US/trainLRClassifier.xml create mode 100644 help/en_US/trainLRClassifier.xml~ create mode 100644 help/en_US/triangulatePoints.xml create mode 100644 help/en_US/whitepoint.xml create mode 100644 help/en_US/whitepoint.xml~ create mode 100644 images/bike.jpg create mode 100644 images/blob.jpg create mode 100644 images/checkerBoard.jpg create mode 100644 images/chess.jpg create mode 100644 images/left1.jpg create mode 100644 images/lena.jpg create mode 100644 images/plane.jpg create mode 100644 images/right1.jpg create mode 100644 images/table.jpg create mode 100644 images/table1.jpg create mode 100644 macros/blobAnalysis.bin create mode 100644 macros/blobAnalysis.sci create mode 100644 macros/decorrstretch.bin create mode 100644 macros/decorrstretch.sci create mode 100644 macros/detectAndComputeORB.bin create mode 100644 macros/detectAndComputeORB.sci create mode 100644 macros/detectBRISKFeatures.bin create mode 100644 macros/detectBRISKFeatures.sci create mode 100644 macros/detectFASTFeatures.bin create mode 100644 macros/detectFASTFeatures.sci create mode 100644 macros/detectHarrisFeatures.bin create mode 100644 macros/detectHarrisFeatures.sci create mode 100644 macros/detectORB.bin create mode 100644 macros/detectORB.sci create mode 100644 macros/detectSURFFeatures.bin create mode 100644 macros/detectSURFFeatures.sci create mode 100644 macros/disparity.bin create mode 100644 macros/disparity.sci create mode 100644 macros/filter.bin create mode 100644 macros/filter.sci create mode 100644 macros/ftrans2.bin create mode 100644 macros/ftrans2.sci create mode 100644 macros/getParams.bin create mode 100644 macros/getParams.sci create mode 100644 macros/graydiffweight.bin create mode 100644 macros/graydiffweight.sci create mode 100644 macros/imabsdiff.bin create mode 100644 macros/imabsdiff.sci create mode 100644 macros/imboxfilt3.bin create mode 100644 macros/imboxfilt3.sci create mode 100644 macros/imcontrast.bin create mode 100644 macros/imcontrast.sci create mode 100644 macros/imcrop.bin create mode 100644 macros/imcrop.sci create mode 100644 macros/imextendedmax.bin create mode 100644 macros/imextendedmax.sci create mode 100644 macros/imfindcircles.bin create mode 100644 macros/imfindcircles.sci create mode 100644 macros/imwrite.bin create mode 100644 macros/imwrite.sci create mode 100644 macros/integralFilter.bin create mode 100644 macros/integralFilter.sci create mode 100644 macros/isFilter.bin create mode 100644 macros/isFilter.sci create mode 100644 macros/matchFeatures.bin create mode 100644 macros/matchFeatures.sci create mode 100644 macros/mlPredict.bin create mode 100644 macros/mlPredict.sci create mode 100644 macros/reconstructScene.bin create mode 100644 macros/reconstructScene.sci create mode 100644 macros/scharr.bin create mode 100644 macros/scharr.sci create mode 100644 macros/sepFilter2D.bin create mode 100644 macros/sepFilter2D.sci create mode 100644 macros/stereoCalibrateAndRect.bin create mode 100644 macros/stereoCalibrateAndRect.sci create mode 100644 macros/trainEMClassifier.bin create mode 100644 macros/trainEMClassifier.sci create mode 100644 macros/trainKNNClassifier.bin create mode 100644 macros/trainKNNClassifier.sci create mode 100644 macros/trainLRClassifier.bin create mode 100644 macros/trainLRClassifier.sci create mode 100644 macros/triangulatePoints.bin create mode 100644 macros/triangulatePoints.sci create mode 100644 macros/whitepoint.bin create mode 100644 macros/whitepoint.sci create mode 100644 sci_gateway/cpp/opencv_decorrstretch.cpp create mode 100644 sci_gateway/cpp/opencv_detectAndComputeORB.cpp create mode 100644 sci_gateway/cpp/opencv_detectBRISKFeatures.cpp create mode 100644 sci_gateway/cpp/opencv_detectFASTFeatures.cpp create mode 100644 sci_gateway/cpp/opencv_detectHarrisFeatures.cpp create mode 100644 sci_gateway/cpp/opencv_detectORB.cpp create mode 100644 sci_gateway/cpp/opencv_detectSURFFeatures.cpp create mode 100644 sci_gateway/cpp/opencv_disparity.cpp create mode 100644 sci_gateway/cpp/opencv_filter2D.cpp create mode 100644 sci_gateway/cpp/opencv_ftrans2.cpp create mode 100644 sci_gateway/cpp/opencv_getParamsEM.cpp create mode 100644 sci_gateway/cpp/opencv_getParamsKNN.cpp create mode 100644 sci_gateway/cpp/opencv_getParamsLR.cpp create mode 100644 sci_gateway/cpp/opencv_graydiffweight.cpp create mode 100644 sci_gateway/cpp/opencv_imabsdiff.cpp create mode 100644 sci_gateway/cpp/opencv_imboxfilt3.cpp create mode 100644 sci_gateway/cpp/opencv_imcontrast.cpp create mode 100644 sci_gateway/cpp/opencv_imcrop.cpp create mode 100644 sci_gateway/cpp/opencv_imextendedmax.cpp create mode 100644 sci_gateway/cpp/opencv_imfindcircles.cpp create mode 100644 sci_gateway/cpp/opencv_imwrite.cpp create mode 100644 sci_gateway/cpp/opencv_integralFilter.cpp create mode 100644 sci_gateway/cpp/opencv_isFilter.cpp create mode 100644 sci_gateway/cpp/opencv_matchFeatures.cpp create mode 100644 sci_gateway/cpp/opencv_predictEM.cpp create mode 100644 sci_gateway/cpp/opencv_predictKNN.cpp create mode 100644 sci_gateway/cpp/opencv_predictLR.cpp create mode 100644 sci_gateway/cpp/opencv_reconstructScene.cpp create mode 100644 sci_gateway/cpp/opencv_scharr.cpp create mode 100644 sci_gateway/cpp/opencv_sepFilter2D.cpp create mode 100644 sci_gateway/cpp/opencv_stereoCalibrateAndRect.cpp create mode 100644 sci_gateway/cpp/opencv_trainEMClassifier.cpp create mode 100644 sci_gateway/cpp/opencv_trainKNNClassifier.cpp create mode 100644 sci_gateway/cpp/opencv_trainLRClassifier.cpp create mode 100644 sci_gateway/cpp/opencv_whitepoint.cpp diff --git a/data/argset3.dat b/data/argset3.dat new file mode 100644 index 0000000000000000000000000000000000000000..5ec28c2dbae3e6347a910a0270720992c185876b GIT binary patch literal 68564 zcmc(odDP`|9mk(*-wnecW4Vk%2a_Qw%Uq5nDoZ8H2^VEa3o1f~E0U#><%Fm%5}{J) zSXyqVAO!D!bY$V_XoAI50G@KL^MdcQvt8DM zwc6|fXy)o`9KNo({;th+(~b+fbA!bj)ewe>nRc|Io&9~Xos)6UHt?du$yYdY)u>@L2} z_c_mIAKTCOxfad3&YbBPa}W96rJ#B3%)OuD;BCYQKDYA!KH~^pH}hw-`MCpK=s_O_ zFoaf%a}FKoLJ#^dfFZQljBV&Z7kbc#0SuwV;f|k4U+ju|Cyci zpZQ7unV`z@Kj}Z$-jTZg<|qAUe$s#DC;exB(tqYB{bzpCf96Z_{3ZS8+>`!u z?vB*@o1gTb`APqopY)&kN&lIj^q=`j|CyikpZStJ|4ILu?MThv{G|WPPx{aNr2ouM z`p^8N|IAPN&-|qS%uo8yd`b96?=&NspYmTb|CIll{FMKi{FMKi{FMKi{FMKi{FMKi z{FMKi{G|Vy4k`bcFUkC*|D1c$f95CsXMWOu<|qAUe$s#DC;exB(tnuF(P$HI5uSMVq-fWX#(ZQx^YGF%3?!4ohJ z!MqK2ghSwTxDxJ$=U`a`up#UUN5DDoQ+NPoz{(uZ4(tVAfD7P8cm(F>@T?B+h6CUv zxD;-M>99BpIT?0z9V8a*b?@IFTurdGdu>1@CW~E!TaEoa0*-w zcfixI6kj5+KI{aC!kKV2{1IM&iF_%?#;`ja1>c4NJP3311p$*_3-~A;4;R5rFomr; z8D8!?3%KO}_xm&a43_8(``&`rvja!>Rk`!^?4TlCd$!Fh`u>L3vjZB6cR+RV4(K%A z0cFQK@Lxl`1ONR*JMiEB=t!PTJ4m`i+LNw9+LLxjd(sYRPud~vNjs!HX@|5Y?U44Q zZg30WRo z_oN-tp0q>SlXggZ(hg})+9B;pJ4pImq&?{xq&;bev?sj|j^uu@L)w#eNPE%_X;0cA z?MXYNJ!yxuC+#5Vvzhj!YmoM&Yv4#;3p=DeX@|5Y?U44Q9nzk(L)w#eNPE%_X;0cg z(tb#L(tJm99qf?yq#e?pv_smHc1U~D4rx!?A?-;!q&;bev?uK#DM#t1W~4hLJ=v^7 z(vwYxq$isWNl!K%lAdfjBt6-5NP4pAko08JA??YgN79pakaUN%CtZWIC+(2-q#e?p zv_smHc1U~D4rx!?A?-=s;7B^k4z5MIL)w$(r#)$hv?uM5_M{!sp0q>SlXggZ(hg}) zdM+JFN7*6mNjrEw((91+r1@!2+9B;pJET2nhqNc{koKe<(w_88IFf#_L)w#eNPE%_ z?uqoZut&N>+LNw9+LLxjd(sYRPud~vN%x~8c`odb_M{!sp0q>SlXh@lruTzA(jC&C zbPdv;v_smHc1U~Dz2HdhNjs!HX@|5Y?U44Q9nzk(L)w#eko37od(t&Xd(sYRPkJ33 z$^Br5v?uM5_M{!sp0q>SlXggZ(hg})+CkE1Gwn&&Ani%lz>&Nbc1U~D4rx!?A?-;! zq&;bev?uM5_M{!sp0tCc{gC#g`Hti|*dgsnJET2nhqNc{koKe<(w?+K+LLxjd(sYR zPuf9Jj?xRwn6-oVTbTy>%i-gS@GjUHJ_D!158xK~8_dUxR)wkXVK^MV4p+c$VLB{K z=<2Wq>;*@`IdC=H4Nt>3WU&@(1N*|U&*3GvBD{&i zwgG$q4uY@1B`^&hhPgNhE5Syv3w#z%gCD}J@OPM>jXDWBuse9qsWah9xC5SmMc7Dd zz?QH#91Z8fHE<6+150qB*M@CjKR6D~gP+5F@GqFaqECVC;p1>3d>3wjA-n|3bDt^i zLG?j67`_UZ!cFi9%+0-~R)&pXS2z?-hs)tMcnlWcep9Q#X0Qhw31`7oa3?$oi*nDY zHDN2*2YT>LxE6j7-jixc?mM*(ya)D&FT(lo3%DQt4a;!51mD9H-mrT}y_QUl$O1%xVvrS?wV+ zt3Bk|bW}RQOy^piS?wY7sy$?8wTH~C_K=y?9x}7qLuOWc$joXFc}^UaPB63DLuR_Z z)$^?Oka^V}GPBx4W>$O1%xVvrS?wV+t3BkNbyS{DGpjvhX0?aR^qN+$t+~~i)gE$= z)gCgl+Cyemd&tac54nFFmHXDrY7d!N?IAO(J!Gc)sQP-ETb)_$A?H}_Av3EzWM;L8 zyq1p2J!EFJhs><@keSsUGPBx4W>$O1OsU?t)gE$=)gCgl+C#3Zqw;#1S?wV+t3709 zwTH~C_K=y?9x}7qLuN|#S*iArbFB7|b97X$t(nyxGPBx4W>$O1%xVvrS?wV+t3709 zwTH}<>hoFcA@dxS^E9*CLuOWc$joXFnOW^2GpjvhX0?aRtoD$Z)gCfas+^z;no*ru z>7izxl^$v`D?QX?R(hz(tn^TmS?QrBv(iINW~GOk%xVucxs@I=Q>rtoJ>(p#J!EFJ zhs><@keSsUGPBx4W>$O1%xVvLHXW5tFw?nKXI6X2ylM}bS?wV+t3709wTH~C_K=y? z9x}7qL!J{yr4!7o_K=ybZ}mK@J!D?Bhs><@keSsUGPBx4W>$O1%xVw0XC0O2)68lQ znOW^2GrgwOYin+GX0?Z$W3`9OtoD$Z)gCgl+C%OiN9DdXv)V&uR(r_IY7d#|KB~T+ z=2mA`d&oIfd&tac51Co*A+M#Qau1nV?IAO(J!EFJhs><@keSsUGE=JeZMBD-W3`9O ztoD%W>ZrV)W>$O1%xVvrS?wV+t3709wTH~C_K=xUeO9VH<@ zkeSsUGPBx4W>$O1%xVvrS?wV+rTTnUd&oRT + + + + + + + blobAnalysis + Detects blob in the source image + + + + + Calling Sequence + + [blob] = blobAnalysis(srcImg) + [blob] = blobAnalysis(srcImg, Name, Value) + + + + + + Parameters + + srcImg: + The input image Matrix. + ROI: + This defines a particular in the image in of which you want the features. + filterByThreshold: + This filter compares the intensity of a binary image at the center of a + filterByArea: + Extracted blobs have an area between minArea (inclusive) and maxArea (exclusive). + filterByCircularity: + Extracted blobs have circularity ( 4∗π∗Areaperimeter∗perimeter) between + filterByConvexity: + Extracted blobs have convexity (area / area of blob convex hull) between minConvexity + + + + + Description + +The function uses SimpleBlobDetector function to detect the blobs then it checks for different Name +Value pair arguments and accordingly returns the parameters of the blob such as 2D coordinates of the +blob, size of the blob. + + +The Name-Value pair may be any of following typesbool filterByArea, vector [minArea maxArea]bool filterByCircularity, vector [minCircularity maxCircularity]bool filterByConvexity, vector [minConvexity maxConvexity]double ROI, vector bool filterByThreshold, vector [minThreshold maxThreshold] + + + + + + + Examples + + + + + See also + + drawKeypoints + + + + + Authors + + Deepshikha + + + diff --git a/help/en_US/build_help.sce b/help/en_US/build_help.sce new file mode 100644 index 0000000..81154f3 --- /dev/null +++ b/help/en_US/build_help.sce @@ -0,0 +1,17 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// Author: Shamika Mohanan +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in +// This file must be used under the terms of the BSD. +// This source file is licensed as described in the file LICENSE, which +// you should have received as part of this distribution. The terms +// are also available at +// https://opensource.org/licenses/BSD-3-Clause + +help_lang_dir = get_absolute_file_path('build_help.sce'); + +tbx_build_help(TOOLBOX_TITLE, help_lang_dir); + +clear help_lang_dir; + diff --git a/help/en_US/build_help.sce~ b/help/en_US/build_help.sce~ new file mode 100644 index 0000000..0205c56 --- /dev/null +++ b/help/en_US/build_help.sce~ @@ -0,0 +1,17 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// Author: Shamika Mohanan +// Organization: FOSSEE, IIT Bombay +// Email: harpreet.mertia@gmail.com +// This file must be used under the terms of the BSD. +// This source file is licensed as described in the file LICENSE, which +// you should have received as part of this distribution. The terms +// are also available at +// https://opensource.org/licenses/BSD-3-Clause + +help_lang_dir = get_absolute_file_path('build_help.sce'); + +tbx_build_help(TOOLBOX_TITLE, help_lang_dir); + +clear help_lang_dir; + diff --git a/help/en_US/decorrstretch.xml b/help/en_US/decorrstretch.xml new file mode 100644 index 0000000..ab9169a --- /dev/null +++ b/help/en_US/decorrstretch.xml @@ -0,0 +1,74 @@ + + + + + + + + decorrstretch + Applies decorrelation stretch to an image. + + + + + Calling Sequence + + outputImage = decorrstretch(image); + + + + + + Parameters + + image: + Input image. + + + + + Description + +This function applies decorrelation stretch to an input image which causes the image to enhance +by way of amplifying image difference. + + + + + + + Examples + + + + + See also + + imread + imshow + + + + + Authors + + Dhruti Shah + + + diff --git a/help/en_US/detectAndComputeORB.xml b/help/en_US/detectAndComputeORB.xml new file mode 100644 index 0000000..e785072 --- /dev/null +++ b/help/en_US/detectAndComputeORB.xml @@ -0,0 +1,106 @@ + + + + + + + + detectAndComputeORB + Oriented FAST and rotated BRIEF (ORB) is used to detect and compute the corners in an image. + + + + + Calling Sequence + + [orb] = detectAndComputeORB(srcImg) + [orb] = detectAndComputeORB(srcImg, Name(same as the ones given under description), Value, ...) + + + + + + Parameters + + srcImg: + The input image Matrix + ROI: + This defines a particular in the image in of which you want the features. + maxFeatures: + The maximum number of features to retain. + scaleFactor: + Pyramid decimation ratio, greater than 1. scaleFactor==2 means the classical pyramid, + nLevels: + The number of pyramid levels. The smallest level will have linear size equal to + edgeThreshold: + This is size of the border where the features are not detected. It should roughly match + firstLevel: + It should be 0 in the current implementation. + scoreType: + The default HARRIS_SCORE (flag value = 0) means that Harris algorithm is used to rank features + patchSize: + Size of the patch used by the oriented BRIEF descriptor. Of course, on smaller pyramid layers + fastThreshold: + The threshold value used for feature detection. + + + + + Description + +Oriented FAST and rotated BRIEF (ORB) is a fast robust local feature detector, first presented +by Ethan Rublee in 2011,that can be used in computer vision tasks like object recognition +or 3D reconstruction. +It is based on the FAST keypoint detector and the visual descriptor BRIEF (Binary Robust +Independent Elementary Features). +Its aim is to provide a fast and efficient alternative to SIFT. + + +The Name-Value pair may be any of following types edgeThreshold fastThreshold firstLevel maxFeatures nLevels patchSize scaleFactor scoreType + + + + + + + Examples + + + + + See also + + imread + drawMatch + drawKeypoints + matchFeatures + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/detectBRISKFeatures.xml b/help/en_US/detectBRISKFeatures.xml new file mode 100644 index 0000000..d278da3 --- /dev/null +++ b/help/en_US/detectBRISKFeatures.xml @@ -0,0 +1,94 @@ + + + + + + + + detectBRISKFeatures + This function is used to detect BRISK(Binary Robust Invariant Scalable Keypoints) Features in a grayscale Image. + + + + + Calling Sequence + + result = detectBRISKFeatures(Image); + result = detectBRISKFeatures(Image, Name, Value, ...) + + + + + + Parameters + + result: + BRISKPoints struct which contains Location of KeyPoints, Orientation, Metric, SignOfLaplacian, Scale and Count of the features. + Image : + Input image, specified as a A-by-N 2D grayscale. + MinContrast : + (Optional) The minimum difference in intensity between a corner and its surrounding region. (Default: 0.2). The value must be between 0 and 1. + NumOctaves : + (Optional)The number of Octaves that the detector uses. (Default - 3) The value must be an integer scalar in between 1 and 4. + MinQuality : + (Optional) This specifies the minimum quality accepted for corners. (Default - 0.1) The value must be between 0 and 1. + ROI : + (Optional) Region Of Interest. This is taken as a vector [u v width height]. When specified, the function detects the key points within region of area width*height with u and v being the top left corner coordinates. + + + + + Description + +This function returns the BRISK features detected in a 2D grayscale image. + + + + + + + Examples + + + + + See also + + imread + drawMatch + drawKeypoints + matchFeatures + extractFeatures + + + + + Authors + + Shashank Shekhar + Siddhant Narang + + + diff --git a/help/en_US/detectFASTFeatures.xml b/help/en_US/detectFASTFeatures.xml new file mode 100644 index 0000000..1766720 --- /dev/null +++ b/help/en_US/detectFASTFeatures.xml @@ -0,0 +1,113 @@ + + + + + + + + detectFASTFeatures + This function is used to detect the corner points using FAST Alogrithm + + + + + Calling Sequence + + [ Location Count Metric ] = detectFASTFeatures( Image, Name, Value... ) + + + + + + Parameters + + Image: + Input Image, should be a 2-D grayscale. The Input Image should be real + MinQuality [Optional Input Argument]: + Minimum Accepted Quality of Corners, can be specified as a scalar value between [0,1]. Default: 0.1 + MinContrast [Optional Input Argument]: + Minimum Intensity difference for Corners to be detected, can be specified as a scalar value between[0,1]. Default: 0.2 + ROI [Optional Input Argument]: + Specify a rectangular region of operation. Format [ x y width height ]. Default: [1 1 size(Image,2) size(Image,1)] + Location: + Set of x,y coordinates for the deteccted points + Count: + Number of corner points detected + Metric: + Value describing the strength of each detected Point + + + + + Description + +The detectFASTFeatures function uses the Features from Accelerated Segment Test (FAST) algorithm to find feature points. + + + + + + + Examples + + + + + Examples + + + + + See also + + imread + drawMatch + drawKeypoints + matchFeatures + + + + + Authors + + Umang Agrawal + Sridhar Reddy + Siddhant Narang + + + diff --git a/help/en_US/detectHarrisFeatures.xml b/help/en_US/detectHarrisFeatures.xml new file mode 100644 index 0000000..f55af8a --- /dev/null +++ b/help/en_US/detectHarrisFeatures.xml @@ -0,0 +1,86 @@ + + + + + + + + detectHarrisFeatures + This function is used to find corner points in an image using Harris algorithm. + + + + + Calling Sequence + + points = detectHarrisFeatures(I); + points = detectHarrisFeatures(I, Name, Value, ...); + + + + + + Parameters + + points: + Structure of corner points + I: + Input image to detectHarrisFeatures() + MinQuality: + (Optional) Minimum accepted quality of corners (Default- 0.01) + FilterSize: + (Optional) Dimension of Gaussian Filter (Default: 5) + ROI: + (Optional) Rectangular region for corner detection + SensitivityFactor: + (Optional) SensitivityFactor of Harris algorithm (Default- 0.04) + + + + + Description + +This function detects corners in an image I. These corner points are used to extract features and hence recognize the contents of an image. + + + + + + + Examples + + + + + See also + + imread + drawKeypoints + + + + + Authors + + Rohit Suri + Sridhar Reddy + Siddhant Narang + + + diff --git a/help/en_US/detectSURFFeatures.xml b/help/en_US/detectSURFFeatures.xml new file mode 100644 index 0000000..eb7cb5e --- /dev/null +++ b/help/en_US/detectSURFFeatures.xml @@ -0,0 +1,95 @@ + + + + + + + + detectSURFFeatures + This function is used to detect SURF(Speeded Up Robust Features) Features in a grayscale Image. + + + + + Calling Sequence + + result = detectSURFFeatures(Image); + result = detectSURFFeatures(Image, Name, Value, ...) + + + + + + Parameters + + result: + SURFPoints struct which contains Location of KeyPoints, Orientation, Metric, SignOfLaplacian, Scale and Count of the features. + Image : + Input image, specified as a A-by-N 2D grayscale. + MetricThreshold : + (Optional) With default value equal to 1000, it is to be specified as a scalar. Every interest point detected has a strength associated with it. In case, only the stronget ones are needed, this parameter has to be given a larger value. To get more no of interest points/blobs, it is to be reduced. + NumOctaves : + (Optional)With default value equal to 3, it is to be specified as a scalar. Larger the number of octaves, larger is the size of blobs detected. This is because higher octave use large sized filters. Value must be an integer scalar in between 1 and 4. + NumScaleLevels : + (Optional)With default value equal to 4, it is to be specified as a scalar. It denotes the number of scale level for each octave. The Value must be an integer scalar greater than or equal to 3. + ROI : + (Optional) Region Of Interest. This is taken as a vector [u v width height]. When specified, the function detects the key points within region of area width*height with u and v being the top left corner coordinates. + + + + + Description + +This function return the SURF(Speeded Up Robust Features) Interest Points for a 2D Grayscale image. It is scale- and rotation- invariant point detector and descriptor and its application include Camera Calibration, 3D Reconstruction, Object Recognition to name a few. + + + + + + + Examples + + + + + See also + + imread + drawMatch + drawKeypoints + matchFeatures + extractFeatures + + + + + Authors + + Shashank Shekhar + Siddhant Narang + + + diff --git a/help/en_US/disparity.xml b/help/en_US/disparity.xml new file mode 100644 index 0000000..28b659c --- /dev/null +++ b/help/en_US/disparity.xml @@ -0,0 +1,98 @@ + + + + + + + + disparity + This function returns the disparity map between two images which + + + + + Calling Sequence + + map, map1 = disparity(img1, img2) + map, map1 = disparity(img1, img2, Name(same as the ones given under parameters), Value, ....) + + + + + + Parameters + + method: + Disparity estimation algorithm, specified as the comma-separated pair consisting of 'Method' + numDisparities: + Maximum disparity minus minimum disparity. This parameter must be divisible by 16. + SADWindowSize: + Matched block size. It must be an odd number >=1 + uniquenessRatio: + Margin in percentage by which the best (minimum) computed cost function value should + textureThreshold: + This controls the detailing in the disparity map. + disp12MaxDiff: + Maximum allowed difference (in integer pixel units) in the left-right disparity check. + Returns: + disparity map + + + + + Description + +Validates disparity using the left-right check. The matrix "cost" should be computed by the +stereo correspondence algorithm. + + + + + + + Examples + + + + + See also + + imread + genCheckerboardPoints + detectCheckerboardCorne + stereoCalibrateAndRect + reconstructScene + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/disparity.xml~ b/help/en_US/disparity.xml~ new file mode 100644 index 0000000..7c6bb1f --- /dev/null +++ b/help/en_US/disparity.xml~ @@ -0,0 +1,95 @@ + + + + + + + + disparity + This function returns the disparity map between two images which + + + + + Calling Sequence + + + + + + Parameters + + method: + Disparity estimation algorithm, specified as the comma-separated pair consisting of 'Method' and // character vector 'blockMatching' or 'semi-blockMatching'. + numDisparities: + Maximum disparity minus minimum disparity. This parameter must be divisible by 16. + SADWindowSize: + Matched block size. It must be an odd number >=1 + uniquenessRatio: + Margin in percentage by which the best (minimum) computed cost function value should “win†+ textureThreshold: + This controls the detailing in the disparity map. + disp12MaxDiff: + Maximum allowed difference (in integer pixel units) in the left-right disparity check. + Returns: + disparity map + + + + + Description + +Validates disparity using the left-right check. The matrix "cost" should be computed by the +stereo correspondence algorithm + + + + + + + Examples + + + + + See also + + imread + genCheckerboardPoints + detectCheckerboardCorne + stereoCalibrateAndRect + reconstructScene + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/filter.xml b/help/en_US/filter.xml new file mode 100644 index 0000000..3cdcf94 --- /dev/null +++ b/help/en_US/filter.xml @@ -0,0 +1,88 @@ + + + + + + + + filter + Convolves an image with the kernel. + + + + + Calling Sequence + + img = filter(input_image, depth, kernelMatrix, -1, -1, 1); + + + + + + Parameters + + input_image: + Input image. + depth: + Destination image depth, given below are the possible values- CV_8U CV_16U/CV_16S CV_32F CV_64F + kernelMatrix: + The matrix which defines the kernel of the filter to be applied on the input image. + anchor_x: + X-coordinate of the anchor. + anchor_y: + Y-coordinate of the anchor. + delta: + Value added to the filtered results before storing them. + + + + + Description + +The function applies an arbitrary linear filter to an image. In-place operation is supported. +When the aperture is partially outside the image, the function interpolates outlier pixel values +according to the specified border mode. +The function does actually compute correlation, not the convolution: + +dst(x, y) = $$\sum_{0 < x' < kernel.cols}_{0 < y' < kernel.rows} kernel(x', y') * src(x + x' - anchor.y + y'- anchor.y) + + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Sukul Bagai + + + diff --git a/help/en_US/ftrans2.xml b/help/en_US/ftrans2.xml new file mode 100644 index 0000000..f10835c --- /dev/null +++ b/help/en_US/ftrans2.xml @@ -0,0 +1,72 @@ + + + + + + + + ftrans2 + 2-D FIR filter using frequency transformation. + + + + + Calling Sequence + + h = ftrans2(b, t); + + + + + + Parameters + + b: + A bandpass filter + t: + Transformation matrix + + + + + Description + +Produces the two-dimensional FIR filter h that corresponds to the one-dimensional FIR filter b +using the transform t. +(ftrans2 returns h as a computational molecule, which is the appropriate form to use with filter2.) +b must be a one-dimensional, Type I (even symmetric, odd-length) filter such as can be returned by +fir1, fir2, or firpm in the Signal Processing Toolbox software. The transform matrix t contains +coefficients that define the frequency transformation to use. If t is m-by-n and b has length Q, +then h is size ((m - 1) * (Q - 1) / 2 + 1)-by-((n - 1) * (Q - 1) / 2 + 1). + + + + + + + Examples + + + + + Authors + + Vinay + + + diff --git a/help/en_US/getParams.xml b/help/en_US/getParams.xml new file mode 100644 index 0000000..b11fe8d --- /dev/null +++ b/help/en_US/getParams.xml @@ -0,0 +1,91 @@ + + + + + + + + getParams + This function is used view the parameters of a trained classifier. + + + + + Calling Sequence + + param = getParams(classifier, modelName); + + + + + + Parameters + + classifier: + Image category classifier + modelName: + Name of the model to which the classifier belongs to. + + + + + Description + +This function can be used to view the parameters of a trained classifier and +make changes accordingly in the training process to get accurate results. + + + + + + + Examples + + + + + Examples + + + + + See also + + trainEMClassifier + trainLRClassifier + trainKNNClassifier + trainNBClassifier + trainSVMClassifier + trainSVMSGDClassifier + trainANNClassifier + trainRTreesClassifier + trainDTreesClassifier + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/getParams.xml~ b/help/en_US/getParams.xml~ new file mode 100644 index 0000000..b11fe8d --- /dev/null +++ b/help/en_US/getParams.xml~ @@ -0,0 +1,91 @@ + + + + + + + + getParams + This function is used view the parameters of a trained classifier. + + + + + Calling Sequence + + param = getParams(classifier, modelName); + + + + + + Parameters + + classifier: + Image category classifier + modelName: + Name of the model to which the classifier belongs to. + + + + + Description + +This function can be used to view the parameters of a trained classifier and +make changes accordingly in the training process to get accurate results. + + + + + + + Examples + + + + + Examples + + + + + See also + + trainEMClassifier + trainLRClassifier + trainKNNClassifier + trainNBClassifier + trainSVMClassifier + trainSVMSGDClassifier + trainANNClassifier + trainRTreesClassifier + trainDTreesClassifier + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/graydiffweight.xml b/help/en_US/graydiffweight.xml new file mode 100644 index 0000000..178db5d --- /dev/null +++ b/help/en_US/graydiffweight.xml @@ -0,0 +1,80 @@ + + + + + + + + graydiffweight + Calculate weights for image pixels based on grayscale intensity difference. + + + + + Calling Sequence + + W = graydiffweight(srcImage, refGrayVal) + + + + + + Parameters + + srcImage: + Input image. + refGrayVal: + Reference grayscale intensity value, specified as a scalar. + + + + + Description + +This function computes the pixel weight for each pixel in the grayscale image I. The weight is the absolute +value of the difference between the intensity of the pixel and the reference grayscale intensity +specified by the scalar refGrayVal. Pick a reference grayscale intensity value that is representative +of the object you want to segment. The weights are returned in the array W, which is the same size as +input image I. The weight of a pixel is inversely related to the absolute value of the grayscale intensity +difference at the pixel location. If the difference is small (intensity value close to refGrayVal), the +weight value is large. If the difference is large (intensity value very different from refGrayVal), the +weight value is small. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Dhruti Shah + + + diff --git a/help/en_US/imabsdiff.xml b/help/en_US/imabsdiff.xml new file mode 100644 index 0000000..130a44e --- /dev/null +++ b/help/en_US/imabsdiff.xml @@ -0,0 +1,82 @@ + + + + + + + + imabsdiff + Calculates the per-element absolute difference between two images. + + + + + Calling Sequence + + image = imabsdiff(img1, img2) + + + + + + Parameters + + img1: + First input image. + img2: + Second input image. + + + + + Description + +The function absdiff calculates- Absolute difference between two arrays when they have the same size and type- +dst(I) = saturate(|src1(I) − src2(I)|) +Absolute difference between an array and a scalar when the second array is constructed +from Scalar or has as many elements as the number of channels in src1- +dst(I) = saturate(|src1(I) − src2|) +Absolute difference between a scalar and an array when the first array is constructed from Scalar or has +as many elements as the number of channels in src2- +dst(I) = saturate(|src1 − src2(I)|) +where I is a multi-dimensional index of array elements. In case of multi-channel arrays, each channel is processed // independently. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/imboxfilt3.xml b/help/en_US/imboxfilt3.xml new file mode 100644 index 0000000..621aa10 --- /dev/null +++ b/help/en_US/imboxfilt3.xml @@ -0,0 +1,113 @@ + + + + + + + + imboxfilt3 + Blurs an image using the box filter. + + + + + Calling Sequence + + blurredImg = imboxfilt3(srcImg) + blurredImg = imboxfilt3(srcImg, filterWidth, filterHeight) + + + + + + Parameters + + srcImage: + Input image. + filterWidth: + The width of the filter to be applied. + filterHeight: + The height of the filter to be applied. + + + + + Description + +The function smoothes an image using the kernel: + + + +K = $$\alpha $$\begin{bmatrix} +1 & 1 & 1 & \dots & 1 & 1 \\ +1 & 1 & 1 & \dots & 1 & 1 \\ +$$\hdots \\ +1 & 1 & 1 & \dots & 1 & 1 +$$\end{bmatrix} + + + + + +where + + + +$$\alpha = \begin{cases} $$\frac{1}{ksize.width * ksize.height} & \hspace{2mm} when\hspace{2mm}normalize = true \\ 1 & {otherwise} +\end{cases}$ + + + + + +Unnormalized box filter is useful for computing various integral characteristics over each pixel +neighborhood, such as covariance matrices of image derivatives (used in dense optical flow algorithms, +and so on). If you need to compute pixel sums over variable-size windows. + + + + + + + Examples + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Yash S. Bhalgat + + + diff --git a/help/en_US/imboxfilt3.xml~ b/help/en_US/imboxfilt3.xml~ new file mode 100644 index 0000000..d7f935b --- /dev/null +++ b/help/en_US/imboxfilt3.xml~ @@ -0,0 +1,107 @@ + + + + + + + + imboxfilt3 + Blurs an image using the box filter. + + + + + Calling Sequence + + + + + + Parameters + + srcImage: + Input image. + filterWidth: + The width of the filter to be applied. + filterHeight: + The height of the filter to be applied. + + + + + Description + +The function smoothes an image using the kernel: + + + +K = $$\alpha $$\begin{bmatrix} +1 & 1 & 1 & \dots & 1 & 1 \\ +1 & 1 & 1 & \dots & 1 & 1 \\ +$$\hdots \\ +1 & 1 & 1 & \dots & 1 & 1 +$$\end{bmatrix} + + +where + + + + +$$\alpha = \begin{cases} $$\frac{1}{ksize.width * ksize.height} & \hspace{2mm} when\hspace{2mm}normalize = true \\ 1 & {otherwise} +\end{cases}$ + + + + +Unnormalized box filter is useful for computing various integral characteristics over each pixel +neighborhood, such as covariance matrices of image derivatives (used in dense optical flow algorithms, +and so on). If you need to compute pixel sums over variable-size windows. + + + + + + + Examples + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Yash S. Bhalgat + + + diff --git a/help/en_US/imcontrast.xml b/help/en_US/imcontrast.xml new file mode 100644 index 0000000..7adf4e0 --- /dev/null +++ b/help/en_US/imcontrast.xml @@ -0,0 +1,77 @@ + + + + + + + + imcontrast + Adjusts image contrast. + + + + + Calling Sequence + + new_image = imcontrast(srcImg, aplha, beta) + + + + + + Parameters + + srcImage: + Input image. + alpha: + Pixel multiplier controls the weight of each pixel. + beta: + Added to every pixel to change the range of pixel values. + + + + + Description + +This function is used to change the contrast of the image using +using the values alpha and beta. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Sukul Bagai + Siddhant Narang + + + diff --git a/help/en_US/imcrop.xml b/help/en_US/imcrop.xml new file mode 100644 index 0000000..8b31e4a --- /dev/null +++ b/help/en_US/imcrop.xml @@ -0,0 +1,79 @@ + + + + + + + + imcrop + Crops the image. + + + + + Calling Sequence + + new_image = imcrop(srcImg, xcoor, ycoor, width, height) + + + + + + Parameters + + srcImage: + Input image. + xcoor: + The x-coordinate of the starting point of the region of interest, ie region to be cropped. + ycoor: + The y-coordinate of the starting point of the region of interest. + width: + The total width of the region of interest wrt to the starting point. + height: + The total height of the region of interest wrt to the starting point. + + + + + Description + +This function can be used to crop the image to a given region of interest. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Sukul Bagai + + + diff --git a/help/en_US/imextendedmax.xml b/help/en_US/imextendedmax.xml new file mode 100644 index 0000000..5f6dd02 --- /dev/null +++ b/help/en_US/imextendedmax.xml @@ -0,0 +1,75 @@ + + + + + + + + imextendedmax + Extended-maxima transform. + + + + + Calling Sequence + + BW = imextendedmax(srcImage, Hmax) + + + + + + Parameters + + srcImage: + Input image. + Hmax: + H-maxima transform, specified as a real, nonnegative scalar. + + + + + Description + +This functoin returns the extended-maxima transform for I, which is the regional maxima of the +H-maxima transform. Regional maxima are connected components of pixels with a constant intensity +value, and whose external boundary pixels all have a lower value. H is a nonnegative scalar. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Vinay Bhat + + + diff --git a/help/en_US/imfindcircles.xml b/help/en_US/imfindcircles.xml new file mode 100644 index 0000000..d0add81 --- /dev/null +++ b/help/en_US/imfindcircles.xml @@ -0,0 +1,82 @@ + + + + + + + + imfindcircles + Finds circles in an image. + + + + + Calling Sequence + + [points] = imcontrast(srcImg, Rmin, Rmax) + [points radii] = imcontrast(srcImg, Rmin, Rmax) + + + + + + Parameters + + srcImage: + Input image. + Rmin: + The minimum value of the radius of the circles to find. + Rmax: + The maximum value of the radius of the circle to find. + points: + The returned coordinates of the center of all the circles found. + radii: + The returned values of the radiis of all the circles found. + + + + + Description + +This function can be used to find the circles of a definite range of radii +in an image. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Tess Zacharias + + + diff --git a/help/en_US/imwrite.xml b/help/en_US/imwrite.xml new file mode 100644 index 0000000..0572a59 --- /dev/null +++ b/help/en_US/imwrite.xml @@ -0,0 +1,73 @@ + + + + + + + + imwrite + Writes to a specified location. + + + + + Calling Sequence + + new_image = imwrite(srcImg, location) + + + + + + Parameters + + srcImg: + input image. + location: + The relative path of where you want to write the image. + + + + + Description + +This function is used write the image to a specified path + + + + + + + Examples + name of the image + + ]]> + + + + See also + + imread + + + + + Authors + + Sukul Bagai + + + diff --git a/help/en_US/integralFilter.xml b/help/en_US/integralFilter.xml new file mode 100644 index 0000000..b5a48d2 --- /dev/null +++ b/help/en_US/integralFilter.xml @@ -0,0 +1,81 @@ + + + + + + + + integralFilter + Integral Image based Filter. + + + + + Calling Sequence + + filter = integralFilter(intimage,bbox,weights,filterSize); + + + + + + Parameters + + intimage: + Integral Image, which can be obtained from the function integralImage. + bbox: + Bounding box of the filter object, which can be obtained from integralKernel function. + weight: + Weights of the bounding box, which can be obtained from integralKernel function. + filterSize: + Size of the filter, which can be obtained from integralKernel function. + + + + + Description + +This function filters image using box filters and integral images. + + + + + + + Examples + + + + + See also + + integralImage + integralKernel + imread + + + + + Authors + + Tanmay Chaudhari + + + diff --git a/help/en_US/isFilter.xml b/help/en_US/isFilter.xml new file mode 100644 index 0000000..92bbf92 --- /dev/null +++ b/help/en_US/isFilter.xml @@ -0,0 +1,77 @@ + + + + + + + + isFilter + Decides if a filter is separable or not. + + + + + Calling Sequence + + [isFilter s u] = isFilter(filter, size); + + + + + + Parameters + + filter: + Input filter (datatype- mat(double)). + size: + Size of the filter. + + + + + Description + +This function uses SVD to compute if the filter is separable or not. It takes as input the +filter matrix and is the filter is separable it returns the calculated singular and the left +singular values. + + + + + + + Examples + + + + + Examples + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/master_help.xml b/help/en_US/master_help.xml new file mode 100644 index 0000000..7962ab5 --- /dev/null +++ b/help/en_US/master_help.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + FOSSEE Image Processing Toolbox + + + +FOSSEE Image Processing Toolbox +&a6dbd35989820ebb5c796f995827da098; +&a7d219c26f9ace1d0a2f8552215507f6f; +&a976c5310205b661ca99613ee7032b5b1; +&a4a1e4fb236ebb505264c877754b6ef90; +&a9ac0094e789c5f226a4b308b0001abc2; +&a0931905e8f69405ab75f2c1d43d72fd8; +&af8d15f24157d0714cbfc1af4193dd7b1; +&a39b7627b986b999ce794d5ba0114844e; +&a7ef3d9042644c8366d33f0d9c6ff06cd; +&aa65b10f5debdda434b059e2eee47a80e; +&abaabec0228a36a19c11cf51d83737ce4; +&ad5bed013c69534648a6115bc0c3a09e1; +&a52f3b2468a8da46db3ff4c91172f62e8; +&ad4dfa0c3b90a5832f31d5d53907deebf; +&aa4cdc5e56e130a8f36dad69ce43dd281; +&a5a603975657458a7416db0a246b88bfe; +&ace0e74e22dac1aedbe0146f4f683519f; +&a4ba9aa4c8e5f298f08a1e85aec575990; +&a8acc2c79cdff8fb96e4e835e89d808c2; +&a05e6388a1ea2eaeea60794e89f4f2d7f; +&a334a0fc9d9f2de45a70ac7d0d9986377; +&acaf9e1c03376a50309258afbf9b2fb63; +&a2ca670b3de8b850e90e0e0834a0253dc; +&a8811795017c692701cc4b0dd9b49c6e2; +&a61a39a460fe8210fe93090d7a918c19d; +&a72ec37b7bf9fcfe6834dbae1a0ad8582; +&a2f826cc4060e581d71c8b85f91ddf723; +&a121886eeb3f1d84e514690d7a751b1e1; +&a329b4a9e5e2c67947ef555c181771f73; +&abb221d483f3441095d99be301b6f5ee3; +&a34bdfc3eff9e80872c09a9f61d8ef274; +&a43492df2f75f820fb7d9eedcfb8b66a5; + + diff --git a/help/en_US/matchFeatures.xml b/help/en_US/matchFeatures.xml new file mode 100644 index 0000000..a8e30b6 --- /dev/null +++ b/help/en_US/matchFeatures.xml @@ -0,0 +1,124 @@ + + + + + + + + matchFeatures + This function is used to find the corresponding matches between two features sets + + + + + Calling Sequence + + [ indexPairs ] = matchFeatures( features1, features2, Name, Value... ) + [ indexPairs matchMetric ] = matchFeatures( features1, features2, Name, Value... ) + + + + + + Parameters + + features1: + Feature Set 1, a set of M1-by-N Matrix, M1 corresponding to number of features and N corresponds to length of each feature vector + features2: + Feature Set 2, a set of M2-by-N Matrix, M2 corresponding to number of features and N corresponds to length of each feature vector + Method [Optional Input Argument]: + Method of matching to be used. Values: ['Exhaustive' (default) | 'Approximate'] + MatchThreshold [Optional Input Argument]: + Matching Threshold for selecting the percentage of strongest matches. Values in range [0 100], default - 10.0 + Unique [Optional Input Argument]: + Boolean value for selecting only unique matches between features. Default-False(0) + Metric [Optional Input Argument]: + Metric to be used for matching features. Values: ['SSD'(default)|'SAD'|'Hamming'|'Hamming_2'] + indexPairs: + P-by-2 matrix containing the indices of corresponding features matched between two input feature sets + matchMetric: + P-by-1 Vector containing the distance metric between matched Features + + + + + Description + +MatchFeatures function takes in the Feature Descriptors value of two images as its input and finds the best match between each feature vector of the first image to that of the second image and returns the corresponding indices of each feature matrix + + + + + + + Examples + + + + + Examples + + + + + See also + + imread + extractFeatures + drawMatch + matches + + + + + Authors + + Umang Agrawal + Sridhar Reddy + Siddhant Narang + + + diff --git a/help/en_US/mlPredict.xml b/help/en_US/mlPredict.xml new file mode 100644 index 0000000..7dd3df7 --- /dev/null +++ b/help/en_US/mlPredict.xml @@ -0,0 +1,96 @@ + + + + + + + + mlPredict + This function is used to predict the class of an image using an image classifier. + + + + + Calling Sequence + + label = mlpredict(classifier, image, modelName) + label = mlpredict(classifier, image, modelName, numberOfNeighnours) // only in case of KNN + + + + + + Parameters + + label: + Evaluated label of the input image + classifier: + Image classifier + image: + Input image + numberOfNeighbours: + Number of neighbours to consider during prediction. + Returns: + Label + + + + + Description + +This function predicts the class of an image based on the classifier provided. + + + + + + + Examples + + + + + Examples + + + + + See also + + imread + load + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/reconstructScene.xml b/help/en_US/reconstructScene.xml new file mode 100644 index 0000000..258ede2 --- /dev/null +++ b/help/en_US/reconstructScene.xml @@ -0,0 +1,93 @@ + + + + + + + + reconstructScene + This function converts a 2-D image to a 3-D image. + + + + + Calling Sequence + + reconstructScene(Q, disp_mat, handleMissingValues) + + + + + + Parameters + + Q(Depth Map): + It is a matrix whose values define the different characteristics of a camera image. + Disparity Map: + Refers to the apparent pixel difference or motion between a pair of stereo image. + handleMissingValues: + Flag whose default value is false, which controls the handling of missing values. + Returns: + 3D image + + + + + Description + +The function transforms a single-channel disparity map to a 3-channel image representing a 3D surface. +That is, for each pixel (x,y) and the corresponding disparity d = disparity(x,y). +The matrix Q can be an arbitrary 4×4 matrix (for example, the one computed by stereoRectify). To reproject +a sparse set of points {(x,y,d),...} to 3D space, use perspectiveTransform. + + + + + + + Examples + + + + + See also + + imread + genCheckerboardPoints + detectCheckerboardCorne + stereoCalibrateAndRect + disparity + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/scharr.xml b/help/en_US/scharr.xml new file mode 100644 index 0000000..0672c2d --- /dev/null +++ b/help/en_US/scharr.xml @@ -0,0 +1,82 @@ + + + + + + + + scharr + Calculates the first x- or y- image derivative using Scharr operator. + + + + + Calling Sequence + + new_image = imcontrast(srcImg, aplha, beta) + + + + + + Parameters + + srcImg: + input image. + ddepth: + output image depth. The possible ddepth values are the following CV_8U CV_16U/CV_16S CV_32F CV_64F + dx: + order of the derivative x. + dy: + order of the derivative y. + scale: + Scale factor for the computed derivative values. + delta: + Delta value that is added to the results. + + + + + Description + +This function is used to find the derivative of the source image using the +Scharr operator. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Sukul Bagai + + + diff --git a/help/en_US/scharr.xml~ b/help/en_US/scharr.xml~ new file mode 100644 index 0000000..ccdcc35 --- /dev/null +++ b/help/en_US/scharr.xml~ @@ -0,0 +1,82 @@ + + + + + + + + scharr + Calculates the first x- or y- image derivative using Scharr operator. + + + + + Calling Sequence + + new_image = imcontrast(srcImg, aplha, beta) + + + + + + Parameters + + srcImg: + input image. + ddepth: + output image depth. The possible ddepth values are the following- + dx: + order of the derivative x. + dy: + order of the derivative y. + scale: + Scale factor for the computed derivative values. + delta: + Delta value that is added to the results. + + + + + Description + +This function is used to find the derivative of the source image using the +Scharr operator. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Sukul Bagai + + + diff --git a/help/en_US/scilab_en_US_help/JavaHelpSearch/DOCS b/help/en_US/scilab_en_US_help/JavaHelpSearch/DOCS new file mode 100644 index 0000000000000000000000000000000000000000..63b18595a8694678b61da12193b90c6de9f18fba GIT binary patch literal 3569 zcmbtUZ%|WL7Js?tzE16a0hjGY+wGte#ci#_RAgJH+j$>4oo%NdGFDP**AiR;3yQng zwcWKteIFRRr4G%Okbpq2O9(X};=g2*3TZJ#2t+d$A`qxktF1+t-4%#qG?P8|y^w^; z;B1?7?!D*y&N;tx?wvP*gQc%o6z-_}i*WZfp|YbmiyRCbrkQYk&qR-v$8iVT~|_lLH!6k@&++@)of!p&&dPast_ z=q{jBbeW>X<)+g86Ie3Q;ksP<>9|PhZ=Ak#0;eu6uc;Z#7^`JN3lf=KqtWC=BPLzc z4 z&iCyTNB5j|atc3jy!nX$^`(zC2`q!yrwVLyJE8GVqwXb}K)R>@?bu%G3X9N?EkJ{$ z##HaPvtNL^qxMvnhp`^%{a7T{4JwgVUAu}TuH$bPt{D}<(@I^F30Sz5K?pMtaz=T}E7M>%}1{KxTe0$X~O*kU=_W-E?rt}9$_Azjv+QZinS zR;}!$RVp9ee`TjUmOPsss_jtk$j31Q%&fNa@2%9cMMgXV*e3HuGNKj1)?Zp;A;Gb^ zlHmf2)7?mW@(P%XYWKdHuMf#|z?b&o`!_?*jWUf1-Rv@9KwIVq2 zE9kEqBC}eNgpR)x)^Xs}JvKzHgZ<|gwvV8asT{|?QV#5?7HVEAF1FxISE&f@auL(1 zd6FG5E0*n(BN+xc!ggnIi2#mVa?72GolY8Y>)xai$n|*v`^Ef6oeY?>E<3SyOe9lN zatxe~92}3_YTWP{xz2w$qNhzepM8-_Sa_o~H8^U<8!vM54rj@F0erd*9=>{+9xmt# zU|{chfvJ4{=zh%l)8wLn`7v13^lZQ1zS!!TGTl7cg1*vOBCcLi3BEPkA2n+1A}vp9Uj`tM)({coEZ+1xH3T;aFs3UB#xN-|j#wZU0wb*M87(sc zWg*LJ=gnuKzj1j{4PXRMoFthp*JfFhAEZok- z|E}4%gfW@H^McMD0YX-#49~3Ii3uB5Bi-_slk;Zb&ed2^QhjIyu`ph2o^JjOpQVg2 zjM008vuwstj_WF(eAClvxNFS8F*0!utrIRSrYUx0ecPvYpx9QFMN|-JX{&S9LPa5B2h}oZWRBQaJ5cgyQ zGA%zq;;xh)+p1paNp_KEX_xP*OyR%aV%mEuVaLIHjed^zexi>rbY=BgVn!T^;T195 z$MK75K*bMpKS=`>to*(_f#>T7VJG9VeWikz^=pooHICeC zV8Xqij9laRpRV7k7|HiPMq%@+L&D;vlW7Tja-BZmBsZGo_#fzhIsT@KDH_RoGcDoH Xas1MHo8u!3^no5Rp&s#p|407^5VYqn literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/JavaHelpSearch/DOCS.TAB b/help/en_US/scilab_en_US_help/JavaHelpSearch/DOCS.TAB new file mode 100644 index 0000000..555056f --- /dev/null +++ b/help/en_US/scilab_en_US_help/JavaHelpSearch/DOCS.TAB @@ -0,0 +1,5 @@ +eÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷_ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷_ÿÿÿÿÿÿÿÿÿÿÿÿÿ÷_ÿÿÿÿÿÿÿÿÿÿÿÿÿÿý—ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷_ÿÿÿÿÿÿÿÿeÿÿÿÿÿÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿuÿÿÿö_ÿÿÿÿÿÿÿÿÿÿÿÿÝÿÿÿÿÿÿý×ÿÿÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿeÿÿ÷_ÿÿÿÝý×ÿÿÿÿÿÿÿÿuÿÿÿö_ÿÿÿ÷_ÿuÿÿÿÿÿÿÿÿÿuÿÙÿÿÝÿÿÿÿý—ÿÿÿÿÿö_ÿÿÿÿÿÿÿÿ÷_÷_ÿÿuÿÿÛ_Ý}—ÿÿÿÐ4oñ\oÕÅÅF±WÅ(¡±A¡FA±A±A¸\hVa!±HhR¨¡ˆRņëÅZMý +£Æ„b£ÆP¼`\£–(`LâìdH†…Dê0£JºËŒ¢ÎÐ`ZÆÅw©Y2Ìï/4¿2¹²ª¨ÒŒ(ÂãʪR*ª¨ÂºêŽRÊÎQGRŒ+ÏJªâÌ/2Ë0¿4³ +ãJª<¡:(ÒŒdj—®º©¤úöN©–®º¶Òúd»®®ºdº§Kª®‹ªª£ +4³Š£&*¨ÂøÂÌ+ºª¯þ«¨å‹4³r*«ê¯0¸ß*ªêê¸Âªª0¿ªª³K3‹ª7*Ì*Œ+Ì¢Ì*6/ê0£ +»êì£h³ró Ì+®úª0«*ªªêª£‹ú¨Ç*ªªªŒ*ªªªªªªºªªªªªª«®¨Âªªªªªªª¿ÿ4¿ÿÿüßÿÿâÿÿÿÿÌ¢ÿÿÿÿÿÿÿÿÿÿÿÿÿÿó ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ4¿ÿÿ0¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿý€ \ No newline at end of file diff --git a/help/en_US/scilab_en_US_help/JavaHelpSearch/OFFSETS b/help/en_US/scilab_en_US_help/JavaHelpSearch/OFFSETS new file mode 100644 index 0000000000000000000000000000000000000000..76aa3bd9790b7c9edc5eed3699ff324ba5c40a50 GIT binary patch literal 134 zcmV;10D1ogg2u?aU|UkzXQX@Ln#xC0m6nZ3Fmyk*cej>fmmk{ezW> om8XSns~dLkzOnURbVXg@UD-<>IXX3W>HL57O)xl?OQTxJ5IJW>>i_@% literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/JavaHelpSearch/POSITIONS b/help/en_US/scilab_en_US_help/JavaHelpSearch/POSITIONS new file mode 100644 index 0000000000000000000000000000000000000000..77243e52d0fdfc01bd463dbb35527cb8af7da49c GIT binary patch literal 13270 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 literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/JavaHelpSearch/SCHEMA b/help/en_US/scilab_en_US_help/JavaHelpSearch/SCHEMA new file mode 100644 index 0000000..594577d --- /dev/null +++ b/help/en_US/scilab_en_US_help/JavaHelpSearch/SCHEMA @@ -0,0 +1,2 @@ +JavaSearch 1.0 +TMAP bs=2048 rt=1 fl=-1 id1=1068 id2=1 diff --git a/help/en_US/scilab_en_US_help/JavaHelpSearch/TMAP b/help/en_US/scilab_en_US_help/JavaHelpSearch/TMAP new file mode 100644 index 0000000000000000000000000000000000000000..aa9d9fa80c7d4892eb24a21e8a914486d59e6a42 GIT binary patch literal 14336 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 aD=O!Sr{=JAUi=3y=EeVc@&Er%{Qn=;@Wjvn literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/ScilabCaution.png b/help/en_US/scilab_en_US_help/ScilabCaution.png new file mode 100644 index 0000000000000000000000000000000000000000..8edb56e4f6653724423c93e57debe7b2defd040f GIT binary patch literal 513 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMfy#SvOS0G)00~Inblrk`sGcc5a zNgxBl1`2jFF!V7nOkiM`#K15G%f+$IF{pDaK7#toh)Yu}d`S#}b30*a{v`G>;Ps&;E^duws)YsdENJ8$OPk$FCCPI}B*nI$ilMHbnp zMZW4%VJJhsbpkrg3HP eANM%?jr*3qG&jq-P+*WUFnGH9xvXZ9 zTG$*46!&pbOHNMC4mT@^wk#|xEG;cKCVzJ14z9eeidIkdV9XzYC>mroH=uDS;qNQndjFQ zURslN`SRs!*RI{Vb?f%++b>_feD&(p>y5UrU%!6y=FQuuN8Ua=`tH@SckkZ4e|`Mt zi(~))|6g#0PXy>P&XOR%UHqaJUX(p@y&8OX-}0mLMYig{-BkBWXu_{Y+*4#WSY0yK+9WGev2+fz z+;6VN&%Y+GysgNU^1=2t-yOB)ciYbj1U=c;cC=J-(NhNL!rhkg3$IVin>=yBHHZHe z)0*m!bZfo3d)4!#jr6q{N2F$JnZ4^W4&-6_>8)@?T4|1?n?{cRKTs%py85}Sb4q9e E0G)=$DgXcg literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/ScilabExecute.png b/help/en_US/scilab_en_US_help/ScilabExecute.png new file mode 100644 index 0000000000000000000000000000000000000000..4acd4b93668e93bd9b2cff9a33d64f4059cc4ccd GIT binary patch literal 535 zcmV+y0_gpTP)r#}QAt}{o3OX+9USER{C&U%eER(1|BDyT z{x4p#=vP3X-xoIz*QL6;x-t$9_KY|U2n`LD3keMb8}RMh*Z;qM|N8&)=gF^xxEJ zQ~u=SW$uoRjnV?D=Rh%_zP>>&E;8$|!BeM9m7F?d3M+;eR;^kko0**sG~gE`41WFmzij!EKb6(x-{&uyUAAV;8abdE zcASB@fByklpe?_D0yS>ly76CYd*km(Q~NjV+__T=D924O8n0ZvB3n^a{HwF8^-o)yXw}fYEF}A)NKTrVPLF+E}U|<>2Iomt;bWVeJz8IsMesFlX+4rLEz-9qk&J3F`nVo{ z_UuZ#+Kc^6s#(|kNnfJ(bZ*FohYunhZALQGgk+#GKL(qSzSLsSrdf6AA)%14*c-iu zO*A~LL2B2^O_FaMInuW`@*I713|FiNsIv_`vfzuMY+|9e8tKRhxlk#1rWouoG3El&TopOeZV^_ZHx ziPEec>3A2CzB(l426;X5q#@RlB z&S6_o3VKwyWZ55*&tU32T>H^oo+d)&KM5jcHT7NJF)!Z&$Ehz`2nl<#;=Qef*hDKh23p`Q{11Ku Xyand^#cQ2p00000NkvXXu0mjf@~bRY literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/ScilabNote.png b/help/en_US/scilab_en_US_help/ScilabNote.png new file mode 100644 index 0000000000000000000000000000000000000000..ed46c3ecdb39ee69f315fc025051e65f6c1badb2 GIT binary patch literal 687 zcmV;g0#N;lP)tj)XR+ddk$LwRRb=TSip@^b1Nt~`$ETa#{hoZP- zql6U`)D)w}Kn@(8aRm7aj;J6gf=}mMbV1Ov{&&y&JpbSGf8V{7QYvTjTFY3x1sao| zqp@1@Wo%xcqN-U&`I~4=-huKezF(;u13Zy}TrLlpjZN@}6YxT1hRV||(TeKkgMS1Z zuI7gvZVcAev+hVDrS<p|9QN@4vreL&CoRy9)p(YDFn5h{G2& zqMPzWUXg%NN8q_(8hfTNB3+H`CSgH{7l8|%v3?i<~ zBjld)l1jFZ95OwK+b+L7mbNTj- zLRWE;z4ccl^XvvmPCY0GjZO{&!*bwW7bl6{e#&;l;T+q;ciK-Oe$ zyMUdfK`d^BKJ5dLKEC#E08*qO5Hf8g(>8Fq-);R5po&gEq+&1_aVnMCPu8X8egauD VozoeJcRv6C002ovPDHLkV1g_-LQ((# literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/ScilabTip.png b/help/en_US/scilab_en_US_help/ScilabTip.png new file mode 100644 index 0000000000000000000000000000000000000000..ed46c3ecdb39ee69f315fc025051e65f6c1badb2 GIT binary patch literal 687 zcmV;g0#N;lP)tj)XR+ddk$LwRRb=TSip@^b1Nt~`$ETa#{hoZP- zql6U`)D)w}Kn@(8aRm7aj;J6gf=}mMbV1Ov{&&y&JpbSGf8V{7QYvTjTFY3x1sao| zqp@1@Wo%xcqN-U&`I~4=-huKezF(;u13Zy}TrLlpjZN@}6YxT1hRV||(TeKkgMS1Z zuI7gvZVcAev+hVDrS<p|9QN@4vreL&CoRy9)p(YDFn5h{G2& zqMPzWUXg%NN8q_(8hfTNB3+H`CSgH{7l8|%v3?i<~ zBjld)l1jFZ95OwK+b+L7mbNTj- zLRWE;z4ccl^XvvmPCY0GjZO{&!*bwW7bl6{e#&;l;T+q;ciK-Oe$ zyMUdfK`d^BKJ5dLKEC#E08*qO5Hf8g(>8Fq-);R5po&gEq+&1_aVnMCPu8X8egauD VozoeJcRv6C002ovPDHLkV1g_-LQ((# literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/ScilabWarning.png b/help/en_US/scilab_en_US_help/ScilabWarning.png new file mode 100644 index 0000000000000000000000000000000000000000..8edb56e4f6653724423c93e57debe7b2defd040f GIT binary patch literal 513 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 literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/_LaTeX_imboxfilt3.xml_1.png b/help/en_US/scilab_en_US_help/_LaTeX_imboxfilt3.xml_1.png new file mode 100644 index 0000000000000000000000000000000000000000..0315c00d260a37ec9b362b31c082c865e5d710bd GIT binary patch literal 919 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 literal 0 HcmV?d00001 diff --git a/help/en_US/scilab_en_US_help/blobAnalysis.html b/help/en_US/scilab_en_US_help/blobAnalysis.html new file mode 100644 index 0000000..50f88ca --- /dev/null +++ b/help/en_US/scilab_en_US_help/blobAnalysis.html @@ -0,0 +1,102 @@ + + + blobAnalysis + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > blobAnalysis + +

+

blobAnalysis

+

Detects blob in the source image

+ + +

Calling Sequence

+
[blob] = blobAnalysis(srcImg)
+[blob] = blobAnalysis(srcImg, Name, Value)
+ +

Parameters

+
srcImg: +

The input image Matrix.

+
ROI: +

This defines a particular in the image in of which you want the features.

+
filterByThreshold: +

This filter compares the intensity of a binary image at the center of a

+
filterByArea: +

Extracted blobs have an area between minArea (inclusive) and maxArea (exclusive).

+
filterByCircularity: +

Extracted blobs have circularity ( 4∗π∗Areaperimeter∗perimeter) between

+
filterByConvexity: +

Extracted blobs have convexity (area / area of blob convex hull) between minConvexity

+ +

Description

+

The function uses SimpleBlobDetector function to detect the blobs then it checks for different Name +Value pair arguments and accordingly returns the parameters of the blob such as 2D coordinates of the +blob, size of the blob.

+

The Name-Value pair may be any of following types

  • bool filterByArea, vector [minArea maxArea]

  • bool filterByCircularity, vector [minCircularity maxCircularity]

  • bool filterByConvexity, vector [minConvexity maxConvexity]

  • double ROI, vector

  • bool filterByThreshold, vector [minThreshold maxThreshold]

+

+ +

Examples

+
img_2 = imread("/images/blob.jpg", 0);
+
+lis1 = blobAnalysis(img_2, "filterByThreshold", [200, 255]);
+lis2 = blobAnalysis(img_2, "filterByCircularity", [0.1, 0.9]);
+lis3 = blobAnalysis(img_2, "filterByArea", [1500, 1600]);
+
+dimage1 = drawKeypoints(img_2, lis1.Points, "color", [0, 255, 0]);
+dimage2 = drawKeypoints(img_2, lis2.Points, "color", [0, 255, 0]);
+dimage3 = drawKeypoints(img_2, lis3.Points, "color", [0, 255, 0]);
+ +

See also

+
+ +

Authors

+
  • Deepshikha
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/c_code.css b/help/en_US/scilab_en_US_help/c_code.css new file mode 100644 index 0000000..948d2ee --- /dev/null +++ b/help/en_US/scilab_en_US_help/c_code.css @@ -0,0 +1,54 @@ +.ccomment { + font-style: italic; + color: #b22222 +} + +.cdefault { + font-style: normal; + color: #000000 +} + +.copenclose { + font-style: normal; + color: #000000 +} + +.coperator { + font-style: normal; + color: #000000 +} + +.cstring { + font-style: normal; + color: #a6557a +} + +.ctype { + font-style: normal; + color: #55a655 +} + +.cpreprocessor { + font-style: normal; + color: #9965a6 +} + +.cid { + font-style: normal; + color: #000000 +} + +.ckeyword { + font-style: normal; + color: #ad3ff2 +} + +.cmodifier { + font-style: normal; + color: #ad3ff2 +} + +.cnumber { + font-style: normal; + color: #008b8b +} diff --git a/help/en_US/scilab_en_US_help/decorrstretch.html b/help/en_US/scilab_en_US_help/decorrstretch.html new file mode 100644 index 0000000..367e224 --- /dev/null +++ b/help/en_US/scilab_en_US_help/decorrstretch.html @@ -0,0 +1,84 @@ + + + decorrstretch + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > decorrstretch + +

+

decorrstretch

+

Applies decorrelation stretch to an image.

+ + +

Calling Sequence

+
outputImage = decorrstretch(image);
+ +

Parameters

+
image: +

Input image.

+ +

Description

+

This function applies decorrelation stretch to an input image which causes the image to enhance +by way of amplifying image difference.

+

+ +

Examples

+
i = imread("images/lena.jpg");
+outputImage = decorrstretch(i);
+imshow(i);
+ +

See also

+
+ +

Authors

+
  • Dhruti Shah
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/detectAndComputeORB.html b/help/en_US/scilab_en_US_help/detectAndComputeORB.html new file mode 100644 index 0000000..5c4c884 --- /dev/null +++ b/help/en_US/scilab_en_US_help/detectAndComputeORB.html @@ -0,0 +1,114 @@ + + + detectAndComputeORB + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > detectAndComputeORB + +

+

detectAndComputeORB

+

Oriented FAST and rotated BRIEF (ORB) is used to detect and compute the corners in an image.

+ + +

Calling Sequence

+
[orb] = detectAndComputeORB(srcImg)
+[orb] = detectAndComputeORB(srcImg, Name(same as the ones given under description), Value, ...)
+ +

Parameters

+
srcImg: +

The input image Matrix

+
ROI: +

This defines a particular in the image in of which you want the features.

+
maxFeatures: +

The maximum number of features to retain.

+
scaleFactor: +

Pyramid decimation ratio, greater than 1. scaleFactor==2 means the classical pyramid,

+
nLevels: +

The number of pyramid levels. The smallest level will have linear size equal to

+
edgeThreshold: +

This is size of the border where the features are not detected. It should roughly match

+
firstLevel: +

It should be 0 in the current implementation.

+
scoreType: +

The default HARRIS_SCORE (flag value = 0) means that Harris algorithm is used to rank features

+
patchSize: +

Size of the patch used by the oriented BRIEF descriptor. Of course, on smaller pyramid layers

+
fastThreshold: +

The threshold value used for feature detection.

+ +

Description

+

Oriented FAST and rotated BRIEF (ORB) is a fast robust local feature detector, first presented +by Ethan Rublee in 2011,that can be used in computer vision tasks like object recognition +or 3D reconstruction. +It is based on the FAST keypoint detector and the visual descriptor BRIEF (Binary Robust +Independent Elementary Features). +Its aim is to provide a fast and efficient alternative to SIFT.

+

The Name-Value pair may be any of following types

  • edgeThreshold

  • fastThreshold

  • firstLevel

  • maxFeatures

  • nLevels

  • patchSize

  • scaleFactor

  • scoreType

+

+ +

Examples

+
img_1 = imread("images/checkerBoard.jpg", 0);
+img_2 = imread("images/chess.jpg", 0);
+lis1 = detectAndComputeORB(img_1);
+lis2 = detectAndComputeORB(img_2);
+dimage = drawKeypoints(img_2, lis2.Points);
+[matches, distance] = matchFeatures(lis1.Features, lis1.Features, "Method", "Exhaustive", "Metric", "Hamming");
+matchedImage = drawMatch(img_1, img_2, lis1.Points, lis2.Points, matches, distance);
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/detectBRISKFeatures.html b/help/en_US/scilab_en_US_help/detectBRISKFeatures.html new file mode 100644 index 0000000..38dd2f1 --- /dev/null +++ b/help/en_US/scilab_en_US_help/detectBRISKFeatures.html @@ -0,0 +1,104 @@ + + + detectBRISKFeatures + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > detectBRISKFeatures + +

+

detectBRISKFeatures

+

This function is used to detect BRISK(Binary Robust Invariant Scalable Keypoints) Features in a grayscale Image.

+ + +

Calling Sequence

+
result = detectBRISKFeatures(Image);
+result = detectBRISKFeatures(Image, Name, Value, ...)
+ +

Parameters

+
result: +

BRISKPoints struct which contains Location of KeyPoints, Orientation, Metric, SignOfLaplacian, Scale and Count of the features.

+
Image : +

Input image, specified as a A-by-N 2D grayscale.

+
MinContrast : +

(Optional) The minimum difference in intensity between a corner and its surrounding region. (Default: 0.2). The value must be between 0 and 1.

+
NumOctaves : +

(Optional)The number of Octaves that the detector uses. (Default - 3) The value must be an integer scalar in between 1 and 4.

+
MinQuality : +

(Optional) This specifies the minimum quality accepted for corners. (Default - 0.1) The value must be between 0 and 1.

+
ROI : +

(Optional) Region Of Interest. This is taken as a vector [u v width height]. When specified, the function detects the key points within region of area width*height with u and v being the top left corner coordinates.

+ +

Description

+

This function returns the BRISK features detected in a 2D grayscale image.

+

+ +

Examples

+
stacksize('max');
+img_1 = imread("images/table.jpg", 0);
+img_2 = imread("images/table1.jpg", 0);
+lis1 = detectBRISKFeatures(img_1);
+lis2 = detectBRISKFeatures(img_2);
+features_1 = extractFeatures(img_1, lis1.KeyPoints, "BRISKPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale);
+features_2 = extractFeatures(img_2, lis2.KeyPoints, "BRISKPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale);
+[matches, distance] = matchFeatures(features_1.Features, features_2.Features);
+matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance);
+ + + +

Authors

+
  • Shashank Shekhar
  • +
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/detectFASTFeatures.html b/help/en_US/scilab_en_US_help/detectFASTFeatures.html new file mode 100644 index 0000000..2553dd5 --- /dev/null +++ b/help/en_US/scilab_en_US_help/detectFASTFeatures.html @@ -0,0 +1,118 @@ + + + detectFASTFeatures + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > detectFASTFeatures + +

+

detectFASTFeatures

+

This function is used to detect the corner points using FAST Alogrithm

+ + +

Calling Sequence

+
[ Location Count Metric ] = detectFASTFeatures( Image, Name, Value... )
+ +

Parameters

+
Image: +

Input Image, should be a 2-D grayscale. The Input Image should be real

+
MinQuality [Optional Input Argument]: +

Minimum Accepted Quality of Corners, can be specified as a scalar value between [0,1]. Default: 0.1

+
MinContrast [Optional Input Argument]: +

Minimum Intensity difference for Corners to be detected, can be specified as a scalar value between[0,1]. Default: 0.2

+
ROI [Optional Input Argument]: +

Specify a rectangular region of operation. Format [ x y width height ]. Default: [1 1 size(Image,2) size(Image,1)]

+
Location: +

Set of x,y coordinates for the deteccted points

+
Count: +

Number of corner points detected

+
Metric: +

Value describing the strength of each detected Point

+ +

Description

+

The detectFASTFeatures function uses the Features from Accelerated Segment Test (FAST) algorithm to find feature points.

+

+ +

Examples

+
stacksize("max");
+img_1 = imread("images/table.jpg", 0);
+img_2 = imread("images/table1.jpg", 0);
+lis1 = detectFASTFeatures(img_1);
+lis2 = detectFASTFeatures(img_2);
+features_1 = extractFeatures(img_1, lis1.Location, "cornerPoints", "Metric", lis1.Metric);
+features_2 = extractFeatures(img_2, lis2.Location, "cornerPoints", "Metric", lis2.Metric)
+dimage = drawKeypoints(img_1, lis1.Location);
+[matches, distance] = matchFeatures(features_1.Features, features_2.Features);
+matchedImage = drawMatch(img_1, img_2, lis1.Location, lis2.Location, matches, distance);
+ +

Examples

+
stacksize("max");
+img_1 = imread("sample_image1.jpg", 0);
+img_2 = imread("sample_image2.jpg", 0);
+lis1 = detectFASTFeatures(img_1, "MinConstrast", 0.2);
+lis2 = detectFASTFeatures(img_2, "MinConstrast", 0.2);
+features_1 = extractFeatures(img_1, lis1.Location, "cornerPoints", "Metric", lis1.Metric);
+features_2 = extractFeatures(img_2, lis2.Location, "cornerPoints", "Metric", lis2.Metric)
+dimage = drawKeypoints(img_1, lis1.Location);
+[matches, distance] = matchFeatures(features_1.Features, features_2.Features);
+matchedImage = drawMatch(img_1, img_2, lis1.Location, lis2.Location, matches, distance);
+ + + +

Authors

+
  • Umang Agrawal
  • +
  • Sridhar Reddy
  • +
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/detectHarrisFeatures.html b/help/en_US/scilab_en_US_help/detectHarrisFeatures.html new file mode 100644 index 0000000..40d0312 --- /dev/null +++ b/help/en_US/scilab_en_US_help/detectHarrisFeatures.html @@ -0,0 +1,96 @@ + + + detectHarrisFeatures + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > detectHarrisFeatures + +

+

detectHarrisFeatures

+

This function is used to find corner points in an image using Harris algorithm.

+ + +

Calling Sequence

+
points = detectHarrisFeatures(I);
+points = detectHarrisFeatures(I, Name, Value, ...);
+ +

Parameters

+
points: +

Structure of corner points

+
I: +

Input image to detectHarrisFeatures()

+
MinQuality: +

(Optional) Minimum accepted quality of corners (Default- 0.01)

+
FilterSize: +

(Optional) Dimension of Gaussian Filter (Default: 5)

+
ROI: +

(Optional) Rectangular region for corner detection

+
SensitivityFactor: +

(Optional) SensitivityFactor of Harris algorithm (Default- 0.04)

+ +

Description

+

This function detects corners in an image I. These corner points are used to extract features and hence recognize the contents of an image.

+

+ +

Examples

+
img_1 = imread("images/checkerBoard.jpg", 0);
+lis1 = detectHarrisFeatures(img_1);
+dimage = drawKeypoints(img_1, lis1.Location, "color", [0, 255, 0]);
+ +

See also

+
+ +

Authors

+
  • Rohit Suri
  • +
  • Sridhar Reddy
  • +
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/detectSURFFeatures.html b/help/en_US/scilab_en_US_help/detectSURFFeatures.html new file mode 100644 index 0000000..4e68e11 --- /dev/null +++ b/help/en_US/scilab_en_US_help/detectSURFFeatures.html @@ -0,0 +1,105 @@ + + + detectSURFFeatures + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > detectSURFFeatures + +

+

detectSURFFeatures

+

This function is used to detect SURF(Speeded Up Robust Features) Features in a grayscale Image.

+ + +

Calling Sequence

+
result = detectSURFFeatures(Image);
+result = detectSURFFeatures(Image, Name, Value, ...)
+ +

Parameters

+
result: +

SURFPoints struct which contains Location of KeyPoints, Orientation, Metric, SignOfLaplacian, Scale and Count of the features.

+
Image : +

Input image, specified as a A-by-N 2D grayscale.

+
MetricThreshold : +

(Optional) With default value equal to 1000, it is to be specified as a scalar. Every interest point detected has a strength associated with it. In case, only the stronget ones are needed, this parameter has to be given a larger value. To get more no of interest points/blobs, it is to be reduced.

+
NumOctaves : +

(Optional)With default value equal to 3, it is to be specified as a scalar. Larger the number of octaves, larger is the size of blobs detected. This is because higher octave use large sized filters. Value must be an integer scalar in between 1 and 4.

+
NumScaleLevels : +

(Optional)With default value equal to 4, it is to be specified as a scalar. It denotes the number of scale level for each octave. The Value must be an integer scalar greater than or equal to 3.

+
ROI : +

(Optional) Region Of Interest. This is taken as a vector [u v width height]. When specified, the function detects the key points within region of area width*height with u and v being the top left corner coordinates.

+ +

Description

+

This function return the SURF(Speeded Up Robust Features) Interest Points for a 2D Grayscale image. It is scale- and rotation- invariant point detector and descriptor and its application include Camera Calibration, 3D Reconstruction, Object Recognition to name a few.

+

+ +

Examples

+
stacksize("max");
+img_1 = imread("images/table.jpg", 0);
+img_2 = imread("images/table1.jpg", 0);
+lis1 = detectSURFFeatures(img_1);
+lis2 = detectSURFFeatures(img_2);
+dimage = drawKeypoints(img_2, lis2.KeyPoints);
+features_1 = extractFeatures(img_1, lis1.KeyPoints, "SURFPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale, "SignOfLaplacian", lis1.SignOfLaplacian);
+features_2 = extractFeatures(img_2, lis2.KeyPoints, "SURFPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale, "SignOfLaplacian", lis2.SignOfLaplacian);
+[matches, distance] = matchFeatures(features_1.Features, features_2.Features, "Method", "Approximate");
+matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance);
+ + + +

Authors

+
  • Shashank Shekhar
  • +
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/disparity.html b/help/en_US/scilab_en_US_help/disparity.html new file mode 100644 index 0000000..d71971e --- /dev/null +++ b/help/en_US/scilab_en_US_help/disparity.html @@ -0,0 +1,108 @@ + + + disparity + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > disparity + +

+

disparity

+

This function returns the disparity map between two images which

+ + +

Calling Sequence

+
map, map1 = disparity(img1, img2)
+map, map1 = disparity(img1, img2, Name(same as the ones given under parameters), Value, ....)
+ +

Parameters

+
method: +

Disparity estimation algorithm, specified as the comma-separated pair consisting of 'Method'

+
numDisparities: +

Maximum disparity minus minimum disparity. This parameter must be divisible by 16.

+
SADWindowSize: +

Matched block size. It must be an odd number >=1

+
uniquenessRatio: +

Margin in percentage by which the best (minimum) computed cost function value should

+
textureThreshold: +

This controls the detailing in the disparity map.

+
disp12MaxDiff: +

Maximum allowed difference (in integer pixel units) in the left-right disparity check.

+
Returns: +

disparity map

+ +

Description

+

Validates disparity using the left-right check. The matrix "cost" should be computed by the +stereo correspondence algorithm.

+

+ +

Examples

+
stacksize("max");
+img_1 = imread("images/left1.jpg", 0);
+img_2 = imread("images/right1.jpg", 0);
+w1 = genCheckerboardPoints([10, 7], 8);
+ip1 = detectCheckerboardCorner(img_1, [7, 10]);
+ip2 = detectCheckerboardCorner(img_2, [7, 10]);
+ip1l = list(ip1);
+ip2l = list(ip2);
+op = stereoCalibrateAndRect(w1, ip1l, ip2l, size(img_1));
+[map map1] = disparity(img_1, img_2);
+img = reconstructScene(op.DepthMap, map1, 1);
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/disparity.html~ b/help/en_US/scilab_en_US_help/disparity.html~ new file mode 100644 index 0000000..74e469b --- /dev/null +++ b/help/en_US/scilab_en_US_help/disparity.html~ @@ -0,0 +1,107 @@ + + + disparity + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > disparity + +

+

disparity

+

This function returns the disparity map between two images which

+ + +

Calling Sequence

+
[map map1] = disparity(img_1, img_2);
+ +

Parameters

+
method: +

Disparity estimation algorithm, specified as the comma-separated pair consisting of 'Method' and // character vector 'blockMatching' or 'semi-blockMatching'.

+
numDisparities: +

Maximum disparity minus minimum disparity. This parameter must be divisible by 16.

+
SADWindowSize: +

Matched block size. It must be an odd number >=1

+
uniquenessRatio: +

Margin in percentage by which the best (minimum) computed cost function value should “winâ€

+
textureThreshold: +

This controls the detailing in the disparity map.

+
disp12MaxDiff: +

Maximum allowed difference (in integer pixel units) in the left-right disparity check.

+
Returns: +

disparity map

+ +

Description

+

Validates disparity using the left-right check. The matrix "cost" should be computed by the +stereo correspondence algorithm

+

+ +

Examples

+
stacksize("max");
+img_1 = imread("left1.jpg", 0);
+img_2 = imread("right1.jpg", 0);
+w1 = genCheckerboardPoints([10, 7], 8);
+ip1 = detectCheckerboardCorner(img_1, [7, 10]);
+ip2 = detectCheckerboardCorner(img_2, [7, 10]);
+ip1l = list(ip1);
+ip2l = list(ip2);
+op = stereoCalibrateAndRect(w1, ip1l, ip2l, size(img_1));
+[map map1] = disparity(img_1, img_2);
+img = reconstructScene(op.DepthMap, map1, 1);
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/filter.html b/help/en_US/scilab_en_US_help/filter.html new file mode 100644 index 0000000..2613b80 --- /dev/null +++ b/help/en_US/scilab_en_US_help/filter.html @@ -0,0 +1,96 @@ + + + filter + + + +
+ + + + +
+ << disparity + + + FOSSEE Image Processing Toolbox + + + ftrans2 >> + +
+
+
+ + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > filter + +

+

filter

+

Convolves an image with the kernel.

+ + +

Calling Sequence

+
img = filter(input_image, depth, kernelMatrix, -1, -1, 1);
+ +

Parameters

+
input_image: +

Input image.

+
depth: +

Destination image depth, given below are the possible values-

  • CV_8U
  • CV_16U/CV_16S
  • CV_32F
  • CV_64F

+
kernelMatrix: +

The matrix which defines the kernel of the filter to be applied on the input image.

+
anchor_x: +

X-coordinate of the anchor.

+
anchor_y: +

Y-coordinate of the anchor.

+
delta: +

Value added to the filtered results before storing them.

+ +

Description

+

The function applies an arbitrary linear filter to an image. In-place operation is supported. +When the aperture is partially outside the image, the function interpolates outlier pixel values +according to the specified border mode. +The function does actually compute correlation, not the convolution: +

+

+ +

Examples

+
img1 = imread("images/right1.jpg", 0);
+img2 = imread("images/left1.jpg", 0);
+image = imabsdiff(img1, img2);
+ +

See also

+
+ +

Authors

+
  • Sukul Bagai
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/ftrans2.html b/help/en_US/scilab_en_US_help/ftrans2.html new file mode 100644 index 0000000..a11063e --- /dev/null +++ b/help/en_US/scilab_en_US_help/ftrans2.html @@ -0,0 +1,86 @@ + + + ftrans2 + + + +
+ + + + +
+ << filter + + + FOSSEE Image Processing Toolbox + + + getParams >> + +
+
+
+ + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > ftrans2 + +

+

ftrans2

+

2-D FIR filter using frequency transformation.

+ + +

Calling Sequence

+
h = ftrans2(b, t);
+ +

Parameters

+
b: +

A bandpass filter

+
t: +

Transformation matrix

+ +

Description

+

Produces the two-dimensional FIR filter h that corresponds to the one-dimensional FIR filter b +using the transform t. +(ftrans2 returns h as a computational molecule, which is the appropriate form to use with filter2.) +b must be a one-dimensional, Type I (even symmetric, odd-length) filter such as can be returned by +fir1, fir2, or firpm in the Signal Processing Toolbox software. The transform matrix t contains +coefficients that define the frequency transformation to use. If t is m-by-n and b has length Q, +then h is size ((m - 1) * (Q - 1) / 2 + 1)-by-((n - 1) * (Q - 1) / 2 + 1).

+

+ +

Examples

+
b = [1, 1, 1]
+h = ftrans2(b);
+ +

Authors

+
  • Vinay
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/getParams.html b/help/en_US/scilab_en_US_help/getParams.html new file mode 100644 index 0000000..23e25be --- /dev/null +++ b/help/en_US/scilab_en_US_help/getParams.html @@ -0,0 +1,96 @@ + + + getParams + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > getParams + +

+

getParams

+

This function is used view the parameters of a trained classifier.

+ + +

Calling Sequence

+
param = getParams(classifier, modelName);
+ +

Parameters

+
classifier: +

Image category classifier

+
modelName: +

Name of the model to which the classifier belongs to.

+ +

Description

+

This function can be used to view the parameters of a trained classifier and +make changes accordingly in the training process to get accurate results.

+

+ +

Examples

+
load("argset3.dat", "knnclassi3"); // Use the scilab load function to load a trained classifier.
+params = getParamsKNN(knnclassi3, "KNN")
+ +

Examples

+
load("emclassi4.dat", "emclassi4"); // Use the scilab load function to load a trained classifier.
+params = getParams(emclassi4, "EM");
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/graydiffweight.html b/help/en_US/scilab_en_US_help/graydiffweight.html new file mode 100644 index 0000000..40f72b6 --- /dev/null +++ b/help/en_US/scilab_en_US_help/graydiffweight.html @@ -0,0 +1,90 @@ + + + graydiffweight + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > graydiffweight + +

+

graydiffweight

+

Calculate weights for image pixels based on grayscale intensity difference.

+ + +

Calling Sequence

+
W = graydiffweight(srcImage, refGrayVal)
+ +

Parameters

+
srcImage: +

Input image.

+
refGrayVal: +

Reference grayscale intensity value, specified as a scalar.

+ +

Description

+

This function computes the pixel weight for each pixel in the grayscale image I. The weight is the absolute +value of the difference between the intensity of the pixel and the reference grayscale intensity +specified by the scalar refGrayVal. Pick a reference grayscale intensity value that is representative +of the object you want to segment. The weights are returned in the array W, which is the same size as +input image I. The weight of a pixel is inversely related to the absolute value of the grayscale intensity +difference at the pixel location. If the difference is small (intensity value close to refGrayVal), the +weight value is large. If the difference is large (intensity value very different from refGrayVal), the +weight value is small.

+

+ +

Examples

+
image = imread("images/lena.jpg");
+W = graydiffweight(image, 120);
+ +

See also

+
+ +

Authors

+
  • Dhruti Shah
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/imabsdiff.html b/help/en_US/scilab_en_US_help/imabsdiff.html new file mode 100644 index 0000000..74359df --- /dev/null +++ b/help/en_US/scilab_en_US_help/imabsdiff.html @@ -0,0 +1,92 @@ + + + imabsdiff + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > imabsdiff + +

+

imabsdiff

+

Calculates the per-element absolute difference between two images.

+ + +

Calling Sequence

+
image = imabsdiff(img1, img2)
+ +

Parameters

+
img1: +

First input image.

+
img2: +

Second input image.

+ +

Description

+

The function absdiff calculates- Absolute difference between two arrays when they have the same size and type- +dst(I) = saturate(|src1(I) − src2(I)|) +Absolute difference between an array and a scalar when the second array is constructed +from Scalar or has as many elements as the number of channels in src1- +dst(I) = saturate(|src1(I) − src2|) +Absolute difference between a scalar and an array when the first array is constructed from Scalar or has +as many elements as the number of channels in src2- +dst(I) = saturate(|src1 − src2(I)|) +where I is a multi-dimensional index of array elements. In case of multi-channel arrays, each channel is processed // independently.

+

+ +

Examples

+
img1 = imread("images/left1.jpg", 0);
+img2 = imread("images/right1.jpg", 0);
+image = imabsdiff(img1, img2);
+ +

See also

+
+ +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/imboxfilt3.html b/help/en_US/scilab_en_US_help/imboxfilt3.html new file mode 100644 index 0000000..7e0e79c --- /dev/null +++ b/help/en_US/scilab_en_US_help/imboxfilt3.html @@ -0,0 +1,98 @@ + + + imboxfilt3 + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > imboxfilt3 + +

+

imboxfilt3

+

Blurs an image using the box filter.

+ + +

Calling Sequence

+
blurredImg = imboxfilt3(srcImg)
+blurredImg = imboxfilt3(srcImg, filterWidth, filterHeight)
+ +

Parameters

+
srcImage: +

Input image.

+
filterWidth: +

The width of the filter to be applied.

+
filterHeight: +

The height of the filter to be applied.

+ +

Description

+

The function smoothes an image using the kernel:

+

+

+

where

+

+

+

Unnormalized box filter is useful for computing various integral characteristics over each pixel +neighborhood, such as covariance matrices of image derivatives (used in dense optical flow algorithms, +and so on). If you need to compute pixel sums over variable-size windows.

+

+ +

Examples

+
image = imread("images/lena.jpg");
+blurredImage = imboxfilt3(input_img);
+ +

Examples

+
image = imread("images/blob.jpg");
+blurredImage = imboxfilt3(input_img, 5, 5);
+ +

See also

+
+ +

Authors

+
  • Yash S. Bhalgat
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/imcontrast.html b/help/en_US/scilab_en_US_help/imcontrast.html new file mode 100644 index 0000000..6f8c8b5 --- /dev/null +++ b/help/en_US/scilab_en_US_help/imcontrast.html @@ -0,0 +1,87 @@ + + + imcontrast + + + +
+ + + + +
+ << imboxfilt3 + + + FOSSEE Image Processing Toolbox + + + imcrop >> + +
+
+
+ + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > imcontrast + +

+

imcontrast

+

Adjusts image contrast.

+ + +

Calling Sequence

+
new_image = imcontrast(srcImg, aplha, beta)
+ +

Parameters

+
srcImage: +

Input image.

+
alpha: +

Pixel multiplier controls the weight of each pixel.

+
beta: +

Added to every pixel to change the range of pixel values.

+ +

Description

+

This function is used to change the contrast of the image using +using the values alpha and beta.

+

+ +

Examples

+
image = imread("images/lena.jpg");
+new_image = imcontrast(image, 1.2, 2);
+ +

See also

+
+ +

Authors

+
  • Sukul Bagai
  • +
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/imcrop.html b/help/en_US/scilab_en_US_help/imcrop.html new file mode 100644 index 0000000..85af9b2 --- /dev/null +++ b/help/en_US/scilab_en_US_help/imcrop.html @@ -0,0 +1,89 @@ + + + imcrop + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > imcrop + +

+

imcrop

+

Crops the image.

+ + +

Calling Sequence

+
new_image = imcrop(srcImg, xcoor, ycoor, width, height)
+ +

Parameters

+
srcImage: +

Input image.

+
xcoor: +

The x-coordinate of the starting point of the region of interest, ie region to be cropped.

+
ycoor: +

The y-coordinate of the starting point of the region of interest.

+
width: +

The total width of the region of interest wrt to the starting point.

+
height: +

The total height of the region of interest wrt to the starting point.

+ +

Description

+

This function can be used to crop the image to a given region of interest.

+

+ +

Examples

+
image = imread("images/lena.jpg");
+new_image = imcrop(image, 10, 10, 100, 100);
+ +

See also

+
+ +

Authors

+
  • Sukul Bagai
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/imextendedmax.html b/help/en_US/scilab_en_US_help/imextendedmax.html new file mode 100644 index 0000000..5d21c2b --- /dev/null +++ b/help/en_US/scilab_en_US_help/imextendedmax.html @@ -0,0 +1,85 @@ + + + imextendedmax + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > imextendedmax + +

+

imextendedmax

+

Extended-maxima transform.

+ + +

Calling Sequence

+
BW = imextendedmax(srcImage, Hmax)
+ +

Parameters

+
srcImage: +

Input image.

+
Hmax: +

H-maxima transform, specified as a real, nonnegative scalar.

+ +

Description

+

This functoin returns the extended-maxima transform for I, which is the regional maxima of the +H-maxima transform. Regional maxima are connected components of pixels with a constant intensity +value, and whose external boundary pixels all have a lower value. H is a nonnegative scalar.

+

+ +

Examples

+
image = imread("images/lena.jpg");
+new_image = imextendedmax(image, 80);
+ +

See also

+
+ +

Authors

+
  • Vinay Bhat
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/imfindcircles.html b/help/en_US/scilab_en_US_help/imfindcircles.html new file mode 100644 index 0000000..7737106 --- /dev/null +++ b/help/en_US/scilab_en_US_help/imfindcircles.html @@ -0,0 +1,92 @@ + + + imfindcircles + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > imfindcircles + +

+

imfindcircles

+

Finds circles in an image.

+ + +

Calling Sequence

+
[points] = imcontrast(srcImg, Rmin, Rmax)
+[points radii] = imcontrast(srcImg, Rmin, Rmax)
+ +

Parameters

+
srcImage: +

Input image.

+
Rmin: +

The minimum value of the radius of the circles to find.

+
Rmax: +

The maximum value of the radius of the circle to find.

+
points: +

The returned coordinates of the center of all the circles found.

+
radii: +

The returned values of the radiis of all the circles found.

+ +

Description

+

This function can be used to find the circles of a definite range of radii +in an image.

+

+ +

Examples

+
image = imread("blob.jpg");
+[points radii] = imfindcircles(image, 4, 5);
+nimage = drawKeypoints(image, points);
+ +

See also

+
+ +

Authors

+
  • Tess Zacharias
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/imwrite.html b/help/en_US/scilab_en_US_help/imwrite.html new file mode 100644 index 0000000..8039508 --- /dev/null +++ b/help/en_US/scilab_en_US_help/imwrite.html @@ -0,0 +1,83 @@ + + + imwrite + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > imwrite + +

+

imwrite

+

Writes to a specified location.

+ + +

Calling Sequence

+
new_image = imwrite(srcImg, location)
+ +

Parameters

+
srcImg: +

input image.

+
location: +

The relative path of where you want to write the image.

+ +

Description

+

This function is used write the image to a specified path

+

+ +

Examples

+
image = imread("images/lena.jpg");
+imwrite(image, "./imageName.jpg"); // imageName -> name of the image
+ +

See also

+
+ +

Authors

+
  • Sukul Bagai
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/index.html b/help/en_US/scilab_en_US_help/index.html new file mode 100644 index 0000000..0b6c5de --- /dev/null +++ b/help/en_US/scilab_en_US_help/index.html @@ -0,0 +1,241 @@ + + + + + + +
+ + + + +
+ + + + + +
+
+
+ + + + +

+

FOSSEE Image Processing Toolbox

+
    + +
  • FOSSEE Image Processing Toolbox +
    • blobAnalysisDetects blob in the source image
    • + + + + + +
    • decorrstretchApplies decorrelation stretch to an image.
    • + + + + + +
    • detectAndComputeORBOriented FAST and rotated BRIEF (ORB) is used to detect and compute the corners in an image.
    • + + + + + +
    • detectBRISKFeaturesThis function is used to detect BRISK(Binary Robust Invariant Scalable Keypoints) Features in a grayscale Image.
    • + + + + + +
    • detectFASTFeaturesThis function is used to detect the corner points using FAST Alogrithm
    • + + + + + +
    • detectHarrisFeaturesThis function is used to find corner points in an image using Harris algorithm.
    • + + + + + +
    • detectSURFFeaturesThis function is used to detect SURF(Speeded Up Robust Features) Features in a grayscale Image.
    • + + + + + +
    • disparityThis function returns the disparity map between two images which
    • + + + + + +
    • filterConvolves an image with the kernel.
    • + + + + + +
    • ftrans22-D FIR filter using frequency transformation.
    • + + + + + +
    • getParamsThis function is used view the parameters of a trained classifier.
    • + + + + + +
    • graydiffweightCalculate weights for image pixels based on grayscale intensity difference.
    • + + + + + +
    • imabsdiffCalculates the per-element absolute difference between two images.
    • + + + + + +
    • imboxfilt3Blurs an image using the box filter.
    • + + + + + +
    • imcontrastAdjusts image contrast.
    • + + + + + +
    • imcropCrops the image.
    • + + + + + +
    • imextendedmaxExtended-maxima transform.
    • + + + + + +
    • imfindcirclesFinds circles in an image.
    • + + + + + +
    • imwriteWrites to a specified location.
    • + + + + + +
    • integralFilterIntegral Image based Filter.
    • + + + + + +
    • isFilterDecides if a filter is separable or not.
    • + + + + + +
    • matchFeaturesThis function is used to find the corresponding matches between two features sets
    • + + + + + +
    • mlPredictThis function is used to predict the class of an image using an image classifier.
    • + + + + + +
    • reconstructSceneThis function converts a 2-D image to a 3-D image.
    • + + + + + +
    • scharrCalculates the first x- or y- image derivative using Scharr operator.
    • + + + + + +
    • sepFilter2DApplies a separable linear filter to an image.
    • + + + + + +
    • stereoCalibrateAndRectThis function returns a set of transformation matrices which helps to callibrate camera
    • + + + + + +
    • trainEMClassifierThis function is used to train an image classifier using the EM algorithm.
    • + + + + + +
    • trainKNNClassifierThis function is used to train an image classifier using the KNN algorithm.
    • + + + + + +
    • trainLRClassifierThis function is used to train an image classifier using the LR algorithm.
    • + + + + + +
    • triangulatePointsReturns the worldPoint coordinates of the feature points.
    • + + + + + +
    • whitepointReturns a three element vector defining the illumination xyz values for different lighting conditions.
+
+ +
+ + + + + + +
Report an issue
+ + + + + +
+
+
+ + diff --git a/help/en_US/scilab_en_US_help/integralFilter.html b/help/en_US/scilab_en_US_help/integralFilter.html new file mode 100644 index 0000000..c55d429 --- /dev/null +++ b/help/en_US/scilab_en_US_help/integralFilter.html @@ -0,0 +1,91 @@ + + + integralFilter + + + +
+ + + + +
+ << imwrite + + + FOSSEE Image Processing Toolbox + + + isFilter >> + +
+
+
+ + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > integralFilter + +

+

integralFilter

+

Integral Image based Filter.

+ + +

Calling Sequence

+
filter = integralFilter(intimage,bbox,weights,filterSize);
+ +

Parameters

+
intimage: +

Integral Image, which can be obtained from the function integralImage.

+
bbox: +

Bounding box of the filter object, which can be obtained from integralKernel function.

+
weight: +

Weights of the bounding box, which can be obtained from integralKernel function.

+
filterSize: +

Size of the filter, which can be obtained from integralKernel function.

+ +

Description

+

This function filters image using box filters and integral images.

+

+ +

Examples

+
i = imread("images/lena.jpg");
+intImg = integralImage(i);
+kernel = integralKernel([2 2 11 11], 1/51);
+filter = integralFilter(intImg, kernel.bbox, kernel.weights, kernel.filterSize);
+ + + +

Authors

+
  • Tanmay Chaudhari
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/isFilter.html b/help/en_US/scilab_en_US_help/isFilter.html new file mode 100644 index 0000000..050079f --- /dev/null +++ b/help/en_US/scilab_en_US_help/isFilter.html @@ -0,0 +1,86 @@ + + + isFilter + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > isFilter + +

+

isFilter

+

Decides if a filter is separable or not.

+ + +

Calling Sequence

+
[isFilter s u] = isFilter(filter, size);
+ +

Parameters

+
filter: +

Input filter (datatype- mat(double)).

+
size: +

Size of the filter.

+ +

Description

+

This function uses SVD to compute if the filter is separable or not. It takes as input the +filter matrix and is the filter is separable it returns the calculated singular and the left +singular values.

+

+ +

Examples

+
filter = [1 0; 0 1]; // Any matrix of dimensions n x n.
+[isfilter] = isFilter(filter);
+ +

Examples

+
filter = [1 0; 0 1]; // Any matrix of dimensions n x n.
+[isfilter s u] = isFilter(filter);
+ +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/jhelpidx.xml b/help/en_US/scilab_en_US_help/jhelpidx.xml new file mode 100644 index 0000000..aa5a66e --- /dev/null +++ b/help/en_US/scilab_en_US_help/jhelpidx.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/help/en_US/scilab_en_US_help/jhelpmap.jhm b/help/en_US/scilab_en_US_help/jhelpmap.jhm new file mode 100644 index 0000000..d00b229 --- /dev/null +++ b/help/en_US/scilab_en_US_help/jhelpmap.jhm @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/help/en_US/scilab_en_US_help/jhelpset.hs b/help/en_US/scilab_en_US_help/jhelpset.hs new file mode 100644 index 0000000..7c93217 --- /dev/null +++ b/help/en_US/scilab_en_US_help/jhelpset.hs @@ -0,0 +1,28 @@ + + + +FOSSEE Image Processing Toolbox + +top + + + +TOC + +javax.help.TOCView +jhelptoc.xml + + +Index + +javax.help.IndexView +jhelpidx.xml + + +Search + +javax.help.SearchView +JavaHelpSearch + + \ No newline at end of file diff --git a/help/en_US/scilab_en_US_help/jhelptoc.xml b/help/en_US/scilab_en_US_help/jhelptoc.xml new file mode 100644 index 0000000..3d47f35 --- /dev/null +++ b/help/en_US/scilab_en_US_help/jhelptoc.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/help/en_US/scilab_en_US_help/matchFeatures.html b/help/en_US/scilab_en_US_help/matchFeatures.html new file mode 100644 index 0000000..a3cdf19 --- /dev/null +++ b/help/en_US/scilab_en_US_help/matchFeatures.html @@ -0,0 +1,129 @@ + + + matchFeatures + + + +
+ + + + +
+ << isFilter + + + FOSSEE Image Processing Toolbox + + + mlPredict >> + +
+
+
+ + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > matchFeatures + +

+

matchFeatures

+

This function is used to find the corresponding matches between two features sets

+ + +

Calling Sequence

+
[ indexPairs ] = matchFeatures( features1, features2, Name, Value... )
+[ indexPairs matchMetric ] = matchFeatures( features1, features2, Name, Value... )
+ +

Parameters

+
features1: +

Feature Set 1, a set of M1-by-N Matrix, M1 corresponding to number of features and N corresponds to length of each feature vector

+
features2: +

Feature Set 2, a set of M2-by-N Matrix, M2 corresponding to number of features and N corresponds to length of each feature vector

+
Method [Optional Input Argument]: +

Method of matching to be used. Values: ['Exhaustive' (default) | 'Approximate']

+
MatchThreshold [Optional Input Argument]: +

Matching Threshold for selecting the percentage of strongest matches. Values in range [0 100], default - 10.0

+
Unique [Optional Input Argument]: +

Boolean value for selecting only unique matches between features. Default-False(0)

+
Metric [Optional Input Argument]: +

Metric to be used for matching features. Values: ['SSD'(default)|'SAD'|'Hamming'|'Hamming_2']

+
indexPairs: +

P-by-2 matrix containing the indices of corresponding features matched between two input feature sets

+
matchMetric: +

P-by-1 Vector containing the distance metric between matched Features

+ +

Description

+

MatchFeatures function takes in the Feature Descriptors value of two images as its input and finds the best match between each feature vector of the first image to that of the second image and returns the corresponding indices of each feature matrix

+

+ +

Examples

+
stacksize("max");
+
+img_1 = imread("images/table.jpg", 0);
+img_2 = imread("images/table1.jpg", 0);
+
+lis1 = detectSURFFeatures(img_1);
+lis2 = detectSURFFeatures(img_2);
+
+dimage = drawKeypoints(img_2, lis2.KeyPoints);
+
+features_1 = extractFeatures(img_1, lis1.KeyPoints, "SURFPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale, "SignOfLaplacian", lis1.SignOfLaplacian);
+features_2 = extractFeatures(img_2, lis2.KeyPoints, "SURFPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale, "SignOfLaplacian", lis2.SignOfLaplacian);
+
+[matches, distance] = matchFeatures(features_1.Features, features_2.Features, "Method", "Approximate");
+matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance);
+ +

Examples

+
stacksize('max');
+
+img_1 = imread("sample_image1.jpg", 0);
+img_2 = imread("sample_image2.jpg", 0);
+
+lis1 = detectBRISKFeatures(img_1);
+lis2 = detectBRISKFeatures(img_2);
+
+features_1 = extractFeatures(img_1, lis1.KeyPoints, "BRISKPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale);
+features_2 = extractFeatures(img_2, lis2.KeyPoints, "BRISKPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale);
+
+[matches, distance] = matchFeatures(features_1.Features, features_2.Features);
+matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance);
+ + + +

Authors

+
  • Umang Agrawal
  • +
  • Sridhar Reddy
  • +
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/mlPredict.html b/help/en_US/scilab_en_US_help/mlPredict.html new file mode 100644 index 0000000..cfdf8eb --- /dev/null +++ b/help/en_US/scilab_en_US_help/mlPredict.html @@ -0,0 +1,101 @@ + + + mlPredict + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > mlPredict + +

+

mlPredict

+

This function is used to predict the class of an image using an image classifier.

+ + +

Calling Sequence

+
label = mlpredict(classifier, image, modelName)
+label = mlpredict(classifier, image, modelName, numberOfNeighnours) // only in case of KNN
+ +

Parameters

+
label: +

Evaluated label of the input image

+
classifier: +

Image classifier

+
image: +

Input image

+
numberOfNeighbours: +

Number of neighbours to consider during prediction.

+
Returns: +

Label

+ +

Description

+

This function predicts the class of an image based on the classifier provided.

+

+ +

Examples

+
load("argset3.dat", "knnclassi3"); // Use the scilab load function to load a trained classifier.
+img = imread("bike.jpg");
+resp = mlPredict(knnclassi3, img, "knn", 5);
+img = imread("car.jpg");
+resp1 = mlPredict(knnclassi3, img, "knn", 5);
+ +

Examples

+
load("emclassi4.dat", "emclassi4"); // Use the scilab load function to load a trained classifier.
+img = imread("images/bike.jpg");
+[prob, resp] = mlPredict(emclassi4, img, "em");
+img = imread("images/plane.jpg");
+[prob1, resp1] = mlPredict(emclassi4, img, "em");
+ +

See also

+
+ +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/reconstructScene.html b/help/en_US/scilab_en_US_help/reconstructScene.html new file mode 100644 index 0000000..29fa736 --- /dev/null +++ b/help/en_US/scilab_en_US_help/reconstructScene.html @@ -0,0 +1,103 @@ + + + reconstructScene + + + +
+ + + + +
+ << mlPredict + + + FOSSEE Image Processing Toolbox + + + scharr >> + +
+
+
+ + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > reconstructScene + +

+

reconstructScene

+

This function converts a 2-D image to a 3-D image.

+ + +

Calling Sequence

+
reconstructScene(Q, disp_mat, handleMissingValues)
+ +

Parameters

+
Q(Depth Map): +

It is a matrix whose values define the different characteristics of a camera image.

+
Disparity Map: +

Refers to the apparent pixel difference or motion between a pair of stereo image.

+
handleMissingValues: +

Flag whose default value is false, which controls the handling of missing values.

+
Returns: +

3D image

+ +

Description

+

The function transforms a single-channel disparity map to a 3-channel image representing a 3D surface. +That is, for each pixel (x,y) and the corresponding disparity d = disparity(x,y). +The matrix Q can be an arbitrary 4×4 matrix (for example, the one computed by stereoRectify). To reproject +a sparse set of points {(x,y,d),...} to 3D space, use perspectiveTransform.

+

+ +

Examples

+
stacksize("max")
+img_1 = imread("images/left1.jpg", 0);
+img_2 = imread("images/right1.jpg", 0);
+w1 = genCheckerboardPoints([10, 7], 8);
+ip1 = detectCheckerboardCorner(img_1, [7, 10]);
+ip2 = detectCheckerboardCorner(img_2, [7, 10]);
+ip1l = list(ip1);
+ip2l = list(ip2);
+op = stereoCalibrateAndRect(w1, ip1l, ip2l, size(img_1));
+[map map1] = disparity(img_1, img_2);
+img = reconstructScene(op.DepthMap, map1, 1);
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/scharr.html b/help/en_US/scilab_en_US_help/scharr.html new file mode 100644 index 0000000..9ec5d1c --- /dev/null +++ b/help/en_US/scilab_en_US_help/scharr.html @@ -0,0 +1,92 @@ + + + scharr + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > scharr + +

+

scharr

+

Calculates the first x- or y- image derivative using Scharr operator.

+ + +

Calling Sequence

+
new_image = imcontrast(srcImg, aplha, beta)
+ +

Parameters

+
srcImg: +

input image.

+
ddepth: +

output image depth. The possible ddepth values are the following

  • CV_8U
  • CV_16U/CV_16S
  • CV_32F
  • CV_64F

+
dx: +

order of the derivative x.

+
dy: +

order of the derivative y.

+
scale: +

Scale factor for the computed derivative values.

+
delta: +

Delta value that is added to the results.

+ +

Description

+

This function is used to find the derivative of the source image using the +Scharr operator.

+

+ +

Examples

+
image = imread("lena.jpg");
+new_image = scharr(image, "CV_8U", 2, 3, 1.5, 2);
+ +

See also

+
+ +

Authors

+
  • Sukul Bagai
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/scilab_code.css b/help/en_US/scilab_en_US_help/scilab_code.css new file mode 100644 index 0000000..658f42e --- /dev/null +++ b/help/en_US/scilab_en_US_help/scilab_code.css @@ -0,0 +1,96 @@ +.scilabcomment { + font-style: italic; + color: #01a801 +} + +.scilabdefault { + font-style: normal; + color: #000000 +} + +.scilabspecial { + font-style: normal; + color: #ffaa00 +} + +.scilabconstants { + font-style: normal; + color: #da70d6 +} + +.scilaboperator { + font-style: normal; + color: #5c5c5c +} + +.scilabnumber { + font-style: normal; + color: #bc8f8f +} + +.scilabfkeyword { + font-style: normal; + color: #b01813 +} + +.scilabskeyword { + font-style: normal; + color: #a020f0 +} + +.scilabckeyword { + font-style: normal; + color: #5f9ea0 +} + +.scilabcommand { + font-style: normal; + color: #32b9b9 +} + +.scilabmacro { + font-style: normal; + color: #ae5cb0 +} + +a.scilabcommand { + font-style: normal; + text-decoration: underline; + color: #32b9b9 +} + +a.scilabmacro { + font-style: normal; + text-decoration: underline; + color: #ae5cb0 +} + +.scilabstring { + font-style: normal; + color: #bc8f8f +} + +.scilabid { + font-style: normal; + color: #000000 +} + +.scilabinputoutputargs { + font-weight: bold; + color: #834310 +} + +.scilabfunctionid { + font-weight: bold; + color: #000000 +} + +.scilabfield { + font-style: normal; + color: #aaaaaa +} + +.scilabopenclose { + font-style: normal; + color: #4a55db +} diff --git a/help/en_US/scilab_en_US_help/section_c28e37d78ba50cc67245894dd02440a0.html b/help/en_US/scilab_en_US_help/section_c28e37d78ba50cc67245894dd02440a0.html new file mode 100644 index 0000000..4815db1 --- /dev/null +++ b/help/en_US/scilab_en_US_help/section_c28e37d78ba50cc67245894dd02440a0.html @@ -0,0 +1,241 @@ + + + + + + +
+ + + + +
+ + + FOSSEE Image Processing Toolbox + + + +
+
+
+ + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox + +

+

FOSSEE Image Processing Toolbox

+
  • blobAnalysisDetects blob in the source image
  • + + + + + +
  • decorrstretchApplies decorrelation stretch to an image.
  • + + + + + +
  • detectAndComputeORBOriented FAST and rotated BRIEF (ORB) is used to detect and compute the corners in an image.
  • + + + + + +
  • detectBRISKFeaturesThis function is used to detect BRISK(Binary Robust Invariant Scalable Keypoints) Features in a grayscale Image.
  • + + + + + +
  • detectFASTFeaturesThis function is used to detect the corner points using FAST Alogrithm
  • + + + + + +
  • detectHarrisFeaturesThis function is used to find corner points in an image using Harris algorithm.
  • + + + + + +
  • detectSURFFeaturesThis function is used to detect SURF(Speeded Up Robust Features) Features in a grayscale Image.
  • + + + + + +
  • disparityThis function returns the disparity map between two images which
  • + + + + + +
  • filterConvolves an image with the kernel.
  • + + + + + +
  • ftrans22-D FIR filter using frequency transformation.
  • + + + + + +
  • getParamsThis function is used view the parameters of a trained classifier.
  • + + + + + +
  • graydiffweightCalculate weights for image pixels based on grayscale intensity difference.
  • + + + + + +
  • imabsdiffCalculates the per-element absolute difference between two images.
  • + + + + + +
  • imboxfilt3Blurs an image using the box filter.
  • + + + + + +
  • imcontrastAdjusts image contrast.
  • + + + + + +
  • imcropCrops the image.
  • + + + + + +
  • imextendedmaxExtended-maxima transform.
  • + + + + + +
  • imfindcirclesFinds circles in an image.
  • + + + + + +
  • imwriteWrites to a specified location.
  • + + + + + +
  • integralFilterIntegral Image based Filter.
  • + + + + + +
  • isFilterDecides if a filter is separable or not.
  • + + + + + +
  • matchFeaturesThis function is used to find the corresponding matches between two features sets
  • + + + + + +
  • mlPredictThis function is used to predict the class of an image using an image classifier.
  • + + + + + +
  • reconstructSceneThis function converts a 2-D image to a 3-D image.
  • + + + + + +
  • scharrCalculates the first x- or y- image derivative using Scharr operator.
  • + + + + + +
  • sepFilter2DApplies a separable linear filter to an image.
  • + + + + + +
  • stereoCalibrateAndRectThis function returns a set of transformation matrices which helps to callibrate camera
  • + + + + + +
  • trainEMClassifierThis function is used to train an image classifier using the EM algorithm.
  • + + + + + +
  • trainKNNClassifierThis function is used to train an image classifier using the KNN algorithm.
  • + + + + + +
  • trainLRClassifierThis function is used to train an image classifier using the LR algorithm.
  • + + + + + +
  • triangulatePointsReturns the worldPoint coordinates of the feature points.
  • + + + + + +
  • whitepointReturns a three element vector defining the illumination xyz values for different lighting conditions.
+
+ +
+ + + + + + +
Report an issue
+ + + FOSSEE Image Processing Toolbox + + + +
+
+
+ + diff --git a/help/en_US/scilab_en_US_help/sepFilter2D.html b/help/en_US/scilab_en_US_help/sepFilter2D.html new file mode 100644 index 0000000..01e0a09 --- /dev/null +++ b/help/en_US/scilab_en_US_help/sepFilter2D.html @@ -0,0 +1,97 @@ + + + sepFilter2D + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > sepFilter2D + +

+

sepFilter2D

+

Applies a separable linear filter to an image.

+ + +

Calling Sequence

+
new_image = sepFilter2D(image, ddepth, kernel_x, kernel_y, anchor_x, anchor_y, delta, border);
+ +

Parameters

+
image: +

Input image.

+
ddepth: +

Destination image depth, given below are the possible values

  • CV_8U

  • CV_16U/CV_16S

  • CV_32F

  • CV_64F

+
kernel_x: +

Coefficients for filtering each row.

+
kernel_y: +

Coefficients for filtering each column.

+
anchor_x: +

X-coordinate of the anchor.

+
anchor_y: +

Y-coordinate of the anchor.

+
delta: +

Value added to the filtered results before storing them.

+
borderType: +

Pixel extrapolation method, given below are the possible argument values

  • BORDER_CONSTANT 0

  • BORDER_REPLICATE 1

  • BORDER_REFLECT 2

  • BORDER_WRAP 3

  • BORDER_REFLECT_101 4

  • BORDER_TRANSPARENT 5

+ +

Description

+

The function applies a separable linear filter to the image. That is, first, every row of src +is filtered with the 1D kernel kernelX. +Then, every column of the result is filtered with the 1D kernel kernelY.

+

+ +

Examples

+
image = imread("images/lena.jpg");
+new_image = sepFilter2D(image, CV_8U, [1, 2, 1], [2, 1, 2], -1, -1, 2, 1)
+ +

See also

+
+ +

Authors

+
  • Sukul Bagai
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/stereoCalibrateAndRect.html b/help/en_US/scilab_en_US_help/stereoCalibrateAndRect.html new file mode 100644 index 0000000..ba7487a --- /dev/null +++ b/help/en_US/scilab_en_US_help/stereoCalibrateAndRect.html @@ -0,0 +1,105 @@ + + + stereoCalibrateAndRect + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > stereoCalibrateAndRect + +

+

stereoCalibrateAndRect

+

This function returns a set of transformation matrices which helps to callibrate camera

+ + +

Calling Sequence

+
params = stereoCalibrateAndRect(objectpoints, imagepoints1, imagepoints2, imageSize)
+ +

Parameters

+
objectpoints: +

Vector of vectors of the calibration pattern points.

+
imagepoints1: +

Vector of vectors of the projections of the calibration pattern points, observed

+
imagePoints2: +

Vector of vectors of the projections of the calibration pattern points, observed

+
imageSize: +

Size of the image used only to initialize intrinsic camera matrix.

+
Returns: +

A struct with the following values

  • cameraMatrix1

  • distortionCoefficients1

  • cameraMatrix2

  • distortionCoefficients2

  • rotationMatrix

  • TranslationVector

  • DepthMap

  • ProjectionMatrix1

  • ProjectionMatrix2

+ +

Description

+

The function estimates transformation between two cameras making a stereo pair and also +computes the rotation matrices for each camera that (virtually) make both camera image +planes the same plane. Consequently, this makes all the epipolar lines parallel and thus +simplifies the dense stereo correspondence problem

+

+ +

Examples

+
stacksize("max");
+img_1 = imread("images/left1.jpg", 0);
+img_2 = imread("images/right1.jpg", 0);
+w1 = genCheckerboardPoints([10, 7], 8);
+ip1 = detectCheckerboardCorner(img_1, [7, 10]);
+ip2 = detectCheckerboardCorner(img_2, [7, 10]);
+ip1l = list(ip1);
+ip2l = list(ip2);
+op = stereoCalibrateAndRect(w1, ip1l, ip2l, size(img_1));
+[map map1] = disparity(img_1, img_2);
+img = reconstructScene(op.DepthMap, map1, 1);
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/style.css b/help/en_US/scilab_en_US_help/style.css new file mode 100644 index 0000000..0fe8923 --- /dev/null +++ b/help/en_US/scilab_en_US_help/style.css @@ -0,0 +1,350 @@ +body { + color:#000000; + background-color:#ffffff; + font-family:sans-serif; + font-size:100%; + margin:5px; + padding:0; + background : url("/img/body.png"); + background-repeat : repeat-x; +} + +.para { + padding-left: 10px; +} + +.refname { + color: #ff6c0a; +} +.refpurpose { + font-size: 110%; +} + +.synopsis { + border: 1px solid black; + width:80%; + padding: 0.5em; +} + +.editbar { + text-align: right; +} + +.term { + color:#800000; + font-size:100%; +} + +h3 { + color: #000063; + font-weight: bold; + font-size:130%; + margin-bottom: 10px; +} + +.programlisting { + font-family: monospace; + font-size: 100%; + background-color:#EEEEFF; + border-color:#CCCCCC; + border-style:solid; + border-width:2px medium; + width:80%; + color:#333333; + line-height:120%; + padding:10px; +} + +.literal { + font-family: monospace; + font-size: 100%; +} + +.option { + font-family: monospace; + font-style: italic; + font-size: 100%; +} + +.command { + font-family: monospace; + font-size: 100%; + color: #32b9b9; +} + +.function { + font-family: monospace; + font-size: 100%; + color: #32b9b9; +} + +.varname { + font-family: monospace; + font-weight: bold; + font-size: 100%; +} + +.constant { + font-family: monospace; + font-size: 100%; + color: #da70d6; +} + +a { + color: blue; + text-decoration:none; +} + +a:hover { + text-decoration:underline; +} + +.itemizedlist { + list-style-type: disk; +} + +.inline-list li { + display: inline; + list-style-type: disk; +} + +.vert-list { + list-style-type: disk; +} + +pre { + margin-bottom: 0px; + margin-top: 0px; +} + +.leftpart { + position:absolute; + float:left; + width: 186px; + padding: 5px; + font-size: smaller; +} + +.content { + margin-top: 100px; + margin-left: 196px +} + +.container { + margin: 0 auto; + width:1024px; +} + +ul.toc li.list-active { + list-style-type:disc; + font-weight:bold; +} + +ul.toc li.parent { + font-size: 115%; + padding: 5px 0px 5px 11px; + border-bottom: 1px solid #cccccc; + margin-bottom: 5px; +} + +ul.toc li.root { + font-size: 135%; + padding: 5px 0px 5px 11px; + border-bottom: 1px solid #cccccc; + margin-bottom: 5px; +} + +ul.toc li { + font-size: 85%; + margin: 1px 0 1px 1px; + padding: 1px 0 1px 11px; + background-repeat: no-repeat; + background-position: center left; + list-style-type: circle; +} + +.next { + float:right; + text-align: right; +} + +.center { + text-align: center; +} + +.screen { + font-family: monospace; + font-size: 100%; + background-color:#FFFFFF; + border-color:#CCCCCC; + border-style:solid; + border-width:2px medium; + width:80%; + color:#333333; + line-height:120%; + padding:10px; +} + +/* Top and bottom navigation controls on manual pages --------------------- */ +div.manualnavbar { + background-color: #E0E0E0; + color: inherit; + padding: 4px; + margin-bottom: 10px; +} +div.manualnavbar .prev { + padding-right: 4px; +} +div.manualnavbar .next { + text-align: right; + padding-left: 4px; +} + +div.manualnavbar .top { + text-align: center; + display: block; +} + +div.manualnavbar hr { + color: #cccccc; + background-color: #cccccc; +} + +/* Footer navigation area ------------------------------------------------- */ + +#pagefooter { + position: relative; + font-size: 75%; + color: inherit; + background-color: #e5e5e5; + width: 100%; +} + +#pagefooterleft { + top: 0px; + left: 0px; + padding: 6px; + margin-right: 30%; +} + +#pagefooterright { + text-align: right; + margin-left: 50%; + padding: 6px; +} +#footnav { + color: inherit; + background-color: #9999cc; + border-width: 1px 0px; + border-color: #333366; + border-style: solid; + text-align: right; + padding-right: 6px; +} + + + + + #global{ +/* width: 90%; */ + max-width: 90em; +/* min-width: 850px; */ + margin-left: auto; + margin-right: auto; + } + + #myHeader{ + background-color:#000000; + color:white; + margin-bottom : 10px; + position : relative; + text-align: center; +/* width : 1024px;*/ + height : 100px; + padding-left : 20px; + background : url("http://atoms.scilab.org/images/homepage/cadre_head.png"); + background-repeat : no-repeat; + background-position : 0px 0px; + + } + + #myFooter{ + background-color:#E5E5E5; + font-color:black; +/* width: 90%;*/ + max-width: 90em; +/* min-width: 850px; + margin-left: 5%; + margin-right: 5%;*/ + margin-top:10px; + padding:10px; + } + + #mainArea{ + width: 100%; + overflow: hidden; + } + + #myLeftArea{ + color:white; + float: left; + width: 180px; + padding:5px; + } + + #myMiddleArea{ + color:black; + margin-left: 200px; + padding: 10px 20px; + } + + #myRightArea{ + color:white; + float: right; + width: 200px; + padding: 12px 20px; + } + + +div#cadre_head +{ + position : relative; + text-align: center; +/* width : 1024px;*/ + height : 100px; + padding-left : 20px; + background : url("/img/cadre_head.png"); + background-repeat : no-repeat; + background-position : 0px 0px; +} + + +div#slogan{ + position: absolute; + top : 50px; + left:251px; + color:#0000AA; + font: 120%, Georgia,Serif; +} +div#cadre_help +{ + position: absolute; + top:45px; + right:0px; + font-size:0.8em; + color:#0000AA; +} + +table.revhistory +{ + width:80%; + border-color:#CCCCCC; + border-style:solid; + border-width:2px medium; + margin-bottom: 10px; +} + +table.revhistory tr.title td +{ + background-color: #9999CC; +} \ No newline at end of file diff --git a/help/en_US/scilab_en_US_help/trainEMClassifier.html b/help/en_US/scilab_en_US_help/trainEMClassifier.html new file mode 100644 index 0000000..3033d54 --- /dev/null +++ b/help/en_US/scilab_en_US_help/trainEMClassifier.html @@ -0,0 +1,104 @@ + + + trainEMClassifier + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > trainEMClassifier + +

+

trainEMClassifier

+

This function is used to train an image classifier using the EM algorithm.

+ + +

Calling Sequence

+
classifier = trainEMClassifier(imgSets, bag, classifierName)
+classifier = trainEMClassifier(imgSets, bag, classifierName, numberOfClusters)
+ +

Parameters

+
classifier: +

Image category classifier

+
imgSets: +

Input imageSet to train the classifier on

+
bag: +

The bagOfFeatures of the imageSet provided

+
numberOfClusters: +

Defines the number of clusters to classify the image set into.

+ +

Description

+

The EM algorithm is a unsupervised learning algorithm. +This function trains a EM classifier which can be used to predict classes of images given to it as +input using the predictEM() function.

+

+ +

Examples

+
imgSet = imageSet('images/trainset_2/', 'recursive');
+[trainingSet testSet] = partition(imgSet,[0.8]);
+bag = bagOfFeatures(trainingSet);
+EMClassifier = trainEMClassifier(trainingSet, bag, classifierName);
+ +

Examples

+
imgSet = imageSet('images/trainset_3/', 'recursive');
+[trainingSet testSet] = partition(imgSet,[0.8]);
+bag = bagOfFeatures(trainingSet);
+numberOfClusters = 3;
+EMClassifier = trainEMClassifier(trainingSet, bag, classifierName, numberOfClusters);
+save("var.dat", "EMClassifier");
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/trainKNNClassifier.html b/help/en_US/scilab_en_US_help/trainKNNClassifier.html new file mode 100644 index 0000000..efd91f4 --- /dev/null +++ b/help/en_US/scilab_en_US_help/trainKNNClassifier.html @@ -0,0 +1,103 @@ + + + trainKNNClassifier + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > trainKNNClassifier + +

+

trainKNNClassifier

+

This function is used to train an image classifier using the KNN algorithm.

+ + +

Calling Sequence

+
classifier = trainKNNClassifier(imgSets, bag, classifierName)
+classifier = trainKNNClassifier(imgSets, bag, classifierName, algorithmType)
+ +

Parameters

+
classifier: +

Image category classifier

+
imgSets: +

Input imageSet to train the classifier on

+
bag: +

The bagOfFeatures of the imageSet provided

+
algorithmType: +

+ +

Description

+

This function trains a KNN classifier which can be used to predict classes of images given to it as +input using the predictKNN() function.

+

+ +

Examples

+
imgSet = imageSet('images/trainset_2/','recursive');
+[trainingSet testSet] = partition(imgSet,[0.8]);
+bag = bagOfFeatures(trainingSet);
+KNNClassifier = trainKNNClassifier(trainingSet, bag, classifierName);
+ +

Examples

+
imgSet = imageSet('images/trainset_3/','recursive');
+[trainingSet testSet] = partition(imgSet,[0.8]);
+bag = bagOfFeatures(trainingSet);
+algorithmType = 1;
+KNNClassifier = trainKNNClassifier(trainingSet, bag, classifierName, algorithmType);
+save("var.dat", "KNNClassifier");
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/trainLRClassifier.html b/help/en_US/scilab_en_US_help/trainLRClassifier.html new file mode 100644 index 0000000..51c7713 --- /dev/null +++ b/help/en_US/scilab_en_US_help/trainLRClassifier.html @@ -0,0 +1,114 @@ + + + trainLRClassifier + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > trainLRClassifier + +

+

trainLRClassifier

+

This function is used to train an image classifier using the LR algorithm.

+ + +

Calling Sequence

+
classifier = trainLRClassifier(imgSets, bag, classifierName)
+classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate)
+classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration)
+classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization)
+classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod)
+classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod, minibatch)
+ +

Parameters

+
classifier: +

Image category classifier

+
imgSets: +

Input imageSet to train the classifier on

+
bag: +

The bagOfFeatures of the imageSet provided

+
learningRate: +

Defines the rate at which the classifier will learn.

+
iteration: +

Number of iterations the training function will perform.

+
regularization: +

Controls the kind of regularization to be applied. The types are

  • REG_DISABLE- Regularization disabled, flag value = -1.
  • REG_L1- L1 norm, flag value = 0.
  • REG_L2- L2 norm, flag value = 1.

+
trainMethod: +

Controls the kind of training method to be applied. The types are

  • BATCH- flag value = 1.
  • MINI_BATCH- flag value = 0.

+
minibatch: +

Specifies the number of training samples taken in each step of Mini-Batch Gradient Descent.

+ +

Description

+

This function trains a LR classifier which can be used to predict classes of images given to it as +input using the predictLR() function.

+

+ +

Examples

+
imgSet = imageSet('images/trainset_2/','recursive');
+[trainingSet testSet] = partition(imgSet,[0.8]);
+bag = bagOfFeatures(trainingSet);
+lrclassi = trainLRClassifier(im, bag, "lrclassi", 1, 150, 0, 1, 5);
+ +

Examples

+
imgSet = imageSet('images/trainset_3/','recursive');
+[trainingSet testSet] = partition(imgSet,[0.8]);
+bag = bagOfFeatures(trainingSet);
+lrclassi = trainLRClassifier(im, bag, "lrclassi", 1, 150, 0);
+save("var.dat", "lrclassi");
+ + + +

Authors

+
  • Siddhant Narang
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/triangulatePoints.html b/help/en_US/scilab_en_US_help/triangulatePoints.html new file mode 100644 index 0000000..5f5baa9 --- /dev/null +++ b/help/en_US/scilab_en_US_help/triangulatePoints.html @@ -0,0 +1,89 @@ + + + triangulatePoints + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > triangulatePoints + +

+

triangulatePoints

+

Returns the worldPoint coordinates of the feature points.

+ + +

Calling Sequence

+
points4D = triangulatePoints(projMat1, projMat2, points1, points2)
+ +

Parameters

+
projMat1: +

3X4 projection matrix for the first Camera matrix

+
projMat2: +

3X4 projection matrix for the second Camera matrix

+
points1: +

2xN array of feature points in the 1st image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1

+
points2: +

2xN array of feature points in the 2nd image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1

+
points4D: +

4XN array or matrix of reconstructed points

+ +

Description

+

Returns 4D location of the matched feature points from the two projected matrices. The 4D location of the feature points is reconstructed using triangulation.

+

+ +

Examples

+
[projMat1] = [12 21 21 19; 34 12 0 2; 112 431 890 32.1]
+[projMat2] = [16 17 32 1; 64 90 12 11; 123 43.5 895 9.8]
+[points1] = [1 2 3 4;5 6 7 8]
+[points2] = [32 1 3 5; 9 8 3 4]
+[points4D] = triangulatePoints(projMat1, projMat2, points1, points2)
+ +

Authors

+
  • Deepshikha
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/whitepoint.html b/help/en_US/scilab_en_US_help/whitepoint.html new file mode 100644 index 0000000..a2a5594 --- /dev/null +++ b/help/en_US/scilab_en_US_help/whitepoint.html @@ -0,0 +1,89 @@ + + + whitepoint + + + + + + + + FOSSEE Image Processing Toolbox >> FOSSEE Image Processing Toolbox > whitepoint + +

+

whitepoint

+

Returns a three element vector defining the illumination xyz values for different lighting conditions.

+ + +

Calling Sequence

+
xyz = whitepoint(string);
+ +

Parameters

+
string: +

The following are the possible values for this argument and their descriptions

  • d65- CIE standard illuminant D65, [0.9504, 1.0000, 1.0888]. Reperesents noon daylight with correlated color temperature of 6504 K.

  • d50- CIE standard illuminant D50, [0.9642, 1.0000, 0.8251]. Represents warm daylight at sunrise or sunset with correlated color temperature of 5003 K.

  • a- CIE standard illuminant A, [1.0985, 1.0000, 0.3558]. Reperesents typical, domestic, tungsten-filament lighting with correlated color temperature of 2856 K.

  • c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Simulates average or north sky daylight with correlated color temperature of 6774 K.

  • icc- Profile Connection Space (PCS) illuminant used in ICC profiles. Approximation of [0.962, 1.000, 0.8249] using fixed-point, signed, 32-bit numbers with 16 fractional bits. Actual value: [31595,32768, 27030]/32768.

  • c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Represents average or north sky daylight with correlated color temperature of 6774 K.

  • d55- CIE standard illuminant D55, [0.9568, 1.0000, 0.9214]. Represents mid-morning or mid-afternoon daylight with correlated color temperature of 5500 K.

+ +

Description

+

This function is used to get a vector of xyz color space representation for different lighting +conditions which can be used to get images with different lighting properties.

+

+ +

Examples

+
xyz = whitepoint("a");
+img = imread("images/lena.jpeg");
+image = applycform(img, "srgb2xyz");
+temp1 = image(:, :, 1)
+temp3 = image(:, :, 3)
+image(:, :, 1) = temp3 * xyz(1);
+image(:, :, 2) = image(:, :, 2) * xyz(2);
+image(:, :, 3) = temp1 * xyz(3);
+imshow(image);
+ +

See also

+
+ +

Authors

+
  • Tess Zacharias
+
+ + + + diff --git a/help/en_US/scilab_en_US_help/xml_code.css b/help/en_US/scilab_en_US_help/xml_code.css new file mode 100644 index 0000000..9e4c27f --- /dev/null +++ b/help/en_US/scilab_en_US_help/xml_code.css @@ -0,0 +1,94 @@ +.xmlcomment { + font-style: italic; + color: #01a801 +} + +.xmldefault { + font-style: normal; + color: #000000 +} + +.xmlentity { + font-style: normal; + color: #ffaa00 +} + +.xmlopeninstr { + font-style: normal; + color: #000000 +} + +.xmlcloseinstr { + font-style: normal; + color: #000000 +} + +.xmlinstrname { + font-style: normal; + color: #9965a6 +} + +.xmllowtag { + font-style: normal; + color: #000000 +} + +.xmltagname { + font-style: normal; + color: #0303ff +} + +.xmllowclose { + font-style: normal; + color: #000000 +} + +.xmlopencomment { + font-style: italic; + color: #01a801 +} + +.xmlcommentend { + font-style: italic; + color: #01a801 +} + +.xmlcomment { + font-style: italic; + color: #01a801 +} + +.xmlopencdata { + font-style: normal; + color: #c45555 +} + +.xmlcdataend { + font-style: normal; + color: #c45555 +} + +.xmlcdata { + font-style: normal; + color: #000000 +} + +.xmlattributename { + font-style: normal; + color: #9965a6 +} + +.xmlequal { + font-style: normal; + color: #000000 +} + +.xmlattributevalue { + font-style: normal; + color: #973964 +} + +.xmlautoclose { + font-style: normal; + color: #000000 +} diff --git a/help/en_US/sepFilter2D.xml b/help/en_US/sepFilter2D.xml new file mode 100644 index 0000000..0336d5c --- /dev/null +++ b/help/en_US/sepFilter2D.xml @@ -0,0 +1,87 @@ + + + + + + + + sepFilter2D + Applies a separable linear filter to an image. + + + + + Calling Sequence + + new_image = sepFilter2D(image, ddepth, kernel_x, kernel_y, anchor_x, anchor_y, delta, border); + + + + + + Parameters + + image: + Input image. + ddepth: + Destination image depth, given below are the possible values CV_8U CV_16U/CV_16S CV_32F CV_64F + kernel_x: + Coefficients for filtering each row. + kernel_y: + Coefficients for filtering each column. + anchor_x: + X-coordinate of the anchor. + anchor_y: + Y-coordinate of the anchor. + delta: + Value added to the filtered results before storing them. + borderType: + Pixel extrapolation method, given below are the possible argument values BORDER_CONSTANT 0 BORDER_REPLICATE 1 BORDER_REFLECT 2 BORDER_WRAP 3 BORDER_REFLECT_101 4 BORDER_TRANSPARENT 5 + + + + + Description + +The function applies a separable linear filter to the image. That is, first, every row of src +is filtered with the 1D kernel kernelX. +Then, every column of the result is filtered with the 1D kernel kernelY. + + + + + + + Examples + + + + + See also + + imread + + + + + Authors + + Sukul Bagai + + + diff --git a/help/en_US/stereoCalibrateAndRect.xml b/help/en_US/stereoCalibrateAndRect.xml new file mode 100644 index 0000000..1a5b0ad --- /dev/null +++ b/help/en_US/stereoCalibrateAndRect.xml @@ -0,0 +1,95 @@ + + + + + + + + stereoCalibrateAndRect + This function returns a set of transformation matrices which helps to callibrate camera + + + + + Calling Sequence + + params = stereoCalibrateAndRect(objectpoints, imagepoints1, imagepoints2, imageSize) + + + + + + Parameters + + objectpoints: + Vector of vectors of the calibration pattern points. + imagepoints1: + Vector of vectors of the projections of the calibration pattern points, observed + imagePoints2: + Vector of vectors of the projections of the calibration pattern points, observed + imageSize: + Size of the image used only to initialize intrinsic camera matrix. + Returns: + A struct with the following values cameraMatrix1 distortionCoefficients1 cameraMatrix2 distortionCoefficients2 rotationMatrix TranslationVector DepthMap ProjectionMatrix1 ProjectionMatrix2 + + + + + Description + +The function estimates transformation between two cameras making a stereo pair and also +computes the rotation matrices for each camera that (virtually) make both camera image +planes the same plane. Consequently, this makes all the epipolar lines parallel and thus +simplifies the dense stereo correspondence problem + + + + + + + Examples + + + + + See also + + imread + genCheckerboardPoints + detectCheckerboardCorner + disparity + reconstructScene + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/trainEMClassifier.xml b/help/en_US/trainEMClassifier.xml new file mode 100644 index 0000000..56aab5a --- /dev/null +++ b/help/en_US/trainEMClassifier.xml @@ -0,0 +1,99 @@ + + + + + + + + trainEMClassifier + This function is used to train an image classifier using the EM algorithm. + + + + + Calling Sequence + + classifier = trainEMClassifier(imgSets, bag, classifierName) + classifier = trainEMClassifier(imgSets, bag, classifierName, numberOfClusters) + + + + + + Parameters + + classifier: + Image category classifier + imgSets: + Input imageSet to train the classifier on + bag: + The bagOfFeatures of the imageSet provided + numberOfClusters: + Defines the number of clusters to classify the image set into. + + + + + Description + +The EM algorithm is a unsupervised learning algorithm. +This function trains a EM classifier which can be used to predict classes of images given to it as +input using the predictEM() function. + + + + + + + Examples + + + + + Examples + + + + + See also + + imageSet + partition + bagOfFeatures + mlPredict + save + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/trainKNNClassifier.xml b/help/en_US/trainKNNClassifier.xml new file mode 100644 index 0000000..222d4a1 --- /dev/null +++ b/help/en_US/trainKNNClassifier.xml @@ -0,0 +1,98 @@ + + + + + + + + trainKNNClassifier + This function is used to train an image classifier using the KNN algorithm. + + + + + Calling Sequence + + classifier = trainKNNClassifier(imgSets, bag, classifierName) + classifier = trainKNNClassifier(imgSets, bag, classifierName, algorithmType) + + + + + + Parameters + + classifier: + Image category classifier + imgSets: + Input imageSet to train the classifier on + bag: + The bagOfFeatures of the imageSet provided + algorithmType: + + + + + + Description + +This function trains a KNN classifier which can be used to predict classes of images given to it as +input using the predictKNN() function. + + + + + + + Examples + + + + + Examples + + + + + See also + + imageSet + partition + bagOfFeatures + mlPredict + save + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/trainLRClassifier.xml b/help/en_US/trainLRClassifier.xml new file mode 100644 index 0000000..c851c8b --- /dev/null +++ b/help/en_US/trainLRClassifier.xml @@ -0,0 +1,109 @@ + + + + + + + + trainLRClassifier + This function is used to train an image classifier using the LR algorithm. + + + + + Calling Sequence + + classifier = trainLRClassifier(imgSets, bag, classifierName) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod, minibatch) + + + + + + Parameters + + classifier: + Image category classifier + imgSets: + Input imageSet to train the classifier on + bag: + The bagOfFeatures of the imageSet provided + learningRate: + Defines the rate at which the classifier will learn. + iteration: + Number of iterations the training function will perform. + regularization: + Controls the kind of regularization to be applied. The types areREG_DISABLE- Regularization disabled, flag value = -1.REG_L1- L1 norm, flag value = 0.REG_L2- L2 norm, flag value = 1. + trainMethod: + Controls the kind of training method to be applied. The types areBATCH- flag value = 1.MINI_BATCH- flag value = 0. + minibatch: + Specifies the number of training samples taken in each step of Mini-Batch Gradient Descent. + + + + + Description + +This function trains a LR classifier which can be used to predict classes of images given to it as +input using the predictLR() function. + + + + + + + Examples + + + + + Examples + + + + + See also + + imageSet + partition + bagOfFeatures + mlPredict + save + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/trainLRClassifier.xml~ b/help/en_US/trainLRClassifier.xml~ new file mode 100644 index 0000000..6df7af4 --- /dev/null +++ b/help/en_US/trainLRClassifier.xml~ @@ -0,0 +1,106 @@ + + + + + + + + trainLRClassifier + This function is used to train an image classifier using the LR algorithm. + + + + + Calling Sequence + + classifier = trainLRClassifier(imgSets, bag, classifierName) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod) + classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod, minibatch) + + + + + + Parameters + + classifier: + Image category classifier + imgSets: + Input imageSet to train the classifier on + bag: + The bagOfFeatures of the imageSet provided + learningRate: + Defines the rate at which the classifier will learn. + iteration: + Number of iterations the training function will perform. + regularization: + Controls the kind of regularization to be applied. The types are- + trainMethod: + Controls the kind of training method to be applied. The types are- + minibatch: + Specifies the number of training samples taken in each step of Mini-Batch Gradient Descent. + + + + + Description + +This function trains a LR classifier which can be used to predict classes of images given to it as +input using the predictLR() function. + + + + + + + Examples + + + + + Examples + + + + + See also + + imageSet + partition + bagOfFeatures + + + + + Authors + + Siddhant Narang + + + diff --git a/help/en_US/triangulatePoints.xml b/help/en_US/triangulatePoints.xml new file mode 100644 index 0000000..d1cc016 --- /dev/null +++ b/help/en_US/triangulatePoints.xml @@ -0,0 +1,75 @@ + + + + + + + + triangulatePoints + Returns the worldPoint coordinates of the feature points. + + + + + Calling Sequence + + points4D = triangulatePoints(projMat1, projMat2, points1, points2) + + + + + + Parameters + + projMat1: + 3X4 projection matrix for the first Camera matrix + projMat2: + 3X4 projection matrix for the second Camera matrix + points1: + 2xN array of feature points in the 1st image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1 + points2: + 2xN array of feature points in the 2nd image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1 + points4D: + 4XN array or matrix of reconstructed points + + + + + Description + +Returns 4D location of the matched feature points from the two projected matrices. The 4D location of the feature points is reconstructed using triangulation. + + + + + + + Examples + + + + + Authors + + Deepshikha + + + diff --git a/help/en_US/whitepoint.xml b/help/en_US/whitepoint.xml new file mode 100644 index 0000000..e3a7c91 --- /dev/null +++ b/help/en_US/whitepoint.xml @@ -0,0 +1,81 @@ + + + + + + + + whitepoint + Returns a three element vector defining the illumination xyz values for different lighting conditions. + + + + + Calling Sequence + + xyz = whitepoint(string); + + + + + + Parameters + + string: + The following are the possible values for this argument and their descriptions d65- CIE standard illuminant D65, [0.9504, 1.0000, 1.0888]. Reperesents noon daylight with correlated color temperature of 6504 K.d50- CIE standard illuminant D50, [0.9642, 1.0000, 0.8251]. Represents warm daylight at sunrise or sunset with correlated color temperature of 5003 K.a- CIE standard illuminant A, [1.0985, 1.0000, 0.3558]. Reperesents typical, domestic, tungsten-filament lighting with correlated color temperature of 2856 K. c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Simulates average or north sky daylight with correlated color temperature of 6774 K. icc- Profile Connection Space (PCS) illuminant used in ICC profiles. Approximation of [0.962, 1.000, 0.8249] using fixed-point, signed, 32-bit numbers with 16 fractional bits. Actual value: [31595,32768, 27030]/32768. c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Represents average or north sky daylight with correlated color temperature of 6774 K.d55- CIE standard illuminant D55, [0.9568, 1.0000, 0.9214]. Represents mid-morning or mid-afternoon daylight with correlated color temperature of 5500 K. + + + + + Description + +This function is used to get a vector of xyz color space representation for different lighting +conditions which can be used to get images with different lighting properties. + + + + + + + Examples + + + + + See also + + imshow + imread + applycform + + + + + Authors + + Tess Zacharias + + + diff --git a/help/en_US/whitepoint.xml~ b/help/en_US/whitepoint.xml~ new file mode 100644 index 0000000..47453c0 --- /dev/null +++ b/help/en_US/whitepoint.xml~ @@ -0,0 +1,81 @@ + + + + + + + + whitepoint + Returns a three element vector defining the illumination xyz values for different lighting conditions. + + + + + Calling Sequence + + xyz = whitepoint(string); + + + + + + Parameters + + string: + The following are the possible values for this argument and their descriptions d65- CIE standard illuminant D65, [0.9504, 1.0000, 1.0888]. Reperesents noon daylight with correlated color temperature of 6504 K.d50- CIE standard illuminant D50, [0.9642, 1.0000, 0.8251]. Represents warm daylight at sunrise or sunset with correlated color temperature of 5003 K.a- CIE standard illuminant A, [1.0985, 1.0000, 0.3558]. Reperesents typical, domestic, tungsten-filament lighting with correlated color temperature of 2856 K. c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Simulates average or north sky daylight with correlated color temperature of 6774 K. icc- Profile Connection Space (PCS) illuminant used in ICC profiles. Approximation of [0.962, 1.000, 0.8249] using fixed-point, signed, 32-bit numbers with 16 fractional bits. Actual value: [31595,32768, 27030]/32768. c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Represents average or north sky daylight with correlated color temperature of 6774 K.d55- CIE standard illuminant D55, [0.9568, 1.0000, 0.9214]. Represents mid-morning or mid-afternoon daylight with correlated color temperature of 5500 K. + + + + + Description + +This function is used to get a vector of xyz color space representation for different lighting +conditions which can be used to get images with different lighting properties. + + + + + + + Examples + + + + + See also + + imshow + imread + applycform + + + + + Authors + + Tess Zacharias + + + diff --git a/images/bike.jpg b/images/bike.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6423fbef2048f67a0f6fa4728c132408bf615417 GIT binary patch literal 7729 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 CGF$!t literal 0 HcmV?d00001 diff --git a/images/checkerBoard.jpg b/images/checkerBoard.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9fdd26b263ac0c7d64431523ece4e9c25a6804b1 GIT binary patch literal 58854 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 z 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%0AcM#z2hX{yV5b_3I2cV^wV2{v`>rY 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 literal 0 HcmV?d00001 diff --git a/images/left1.jpg b/images/left1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2d65251b5489f94811b68efb51161bea2b3fb36 GIT binary patch literal 52016 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 literal 0 HcmV?d00001 diff --git a/images/lena.jpg b/images/lena.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0fc150f322304e1c7e53e2c6c83f0454d4a8fabb GIT binary patch literal 1333 zcmex=>w#K0R~29CKeWERyKBs zEF%*$3#%Z5kfI@*V_>4NQlqkwQ{hCBq=g4Beqa|33f}neBT%0R$m6I0Br1q0dW(Sv zXf=}{vmk>#!`H7WhKii#5&36tL^Cf~^_1<;#<-5(lafQ_O77-W_U9V%&42dcP^r3u z)dQWSE^iEX95pL`shv6J@Y16nP1hX#H2a3ajfeF-3(K|b!upQ9tBYU9ux85IrMlZE z1#DdCwMALvWj?E8j(!m9`rAC&Ar@PAXl1)CWqgxT?D?Xq@5XcE>smA2#B-Jf^Z&@o z$?`m#H1XP>4O~e}cWnt@$sIZ;eoNQp54$X@dJWI5E=}FE^hke+RcmT#&83CA-0PNe zSS)?{#VaSho2%!`!8g;&^9~4q3fRYAu$KSl;-^2AK29jzf2_XxfzXFb`D_adKh#A` zJp3)xZ(j4Jc^=oFciR{gyRYbrv{!DvAh0OvM9$vJx$jRi<{T4TzOPlfWqnR~+O8u$ zYi*uRDV3XHeWY~4NYCl1 z#i^&czA{B%%72DEVYLB@f>sN*EIr%Y{k`+|;`NU^u9z!qeR%ny#hhM#yV#Sj?>}$0 z$u+$p`m$-h*6SjPsF2A;ml_$Jx6OKBYTsd6`jOXbws)eXx64$%%%Bq&V>vu_%6@2K zF?;!8R?nrJDeAAAWVl)O22^Ez<;|G1F3bAg?}vxaG4Q3_-mk;BkGsU8YlX7IjmsAv zg@lWXZksCY$;Z>MI$+AYve%bIelVSGwoNbPKP@2OJn2RzU#evOjIUA;Ol9md`ZYB? zKMK9Q6p}wXI`y6JhgH)eIz>Z7w4Nq?zUz6_+n&L;b^U!G-x)i;>{vBzO8>LGoo|kR zd%H5=eewPUM}Dy!F?z|j`pnjN!)JbsSItDMYUAddiB^$U407#c`=-A4+zxgTcks=FXi0uEAgu361Qc?&lNRX zP?@W{jCtmVEoqWvj$K?5lX-=NZr)T4-|@#lHK;4iqlWuQ$*sTo*|i4$8QNxgXM7H$Z)@NLK~J_rN?Y}~-^KkPq3!rW&qAc{+%dC)u# z76k~K0t<%%>#Q9F1_WZ`oJ;-N@bIy4aIp!1MHzAs77jKR!6iZ*92~rJz&RL~f)bAk z(5UhnpBAR9`V=ulKzH@FnvrkR8|t$6cN`qqTemm_{QTzu1_po`p#Pg2aBy(3u<`JL zHEs%E4GS9|8w(Hg3xb7>LqUa0NzKNuOrrwByL$U6LcsU+_8A&P3?Q&6a4101prcpV z|5YQSd^i?T`&_&)(gA)wRk>=Ixq$Xm|F0)@ugqDV2@AAWo^}w_E?WhI)|lE^C!YVW z=6`Qj{;$0h0+*5Z1Vn3#-g(I{?8NN`SwFf<_6xu6=xR162@=l?E4l<#M^%L(#_atb z+EzRr_4DgjYbv&%z)9Mlc0{D!-M8}iH*#k2J?G@P>PwDQK+98osFPoY#-oL#NQRRqXvJ)ID!k;BqhHHBQkvIM&afx*X;Ho}?0>b9a$~028Dz~2WQz2N~J2Se_rvy(OA0F$gH_dp+IwNg$ z8}=TyJraCwZlFIVB;e<#+SbG%bc=Q8Fj9zh#k1exQtpyaW3(Bm=+#E_volZ(#djgO zZZ?k;_@Y&@?A=0_N&Lh3`(fpA{@gkYEF+&6{HSg&#p_j4Qw+Z6S;^_ap`#M{^Eghx8PVEB6No+%&WyIzo27Q;>TTE%IMGK4Gy>w?!*X+ zZ?tjszA8#gVlFR~TRIz;M59F^)ZRn3oOa^c>JFw&N=w{s+o~+vFQ%@BrD8pJy)4(1 z#aPiV!|Prl!;$u!{NDJI=dIxUmK3_Dl0wXvpo(2c3rjFt*qcm7*-T`&V2>&;pT`7_ z!FN}RVgK+F?p-TbXQzT_DSiiTEZ=q8`5-!$Rw5|veJfB$i_eW~?7>B}79dwvl%YcE ztA{<+LUlDvbhNN-+GmgtBrzkzJ=xBWxrkRz_gf)<+2y%v6HMQj>+524ZNi7vh%3A- z_IEhH(n1@fUxf1EOj#V(I&Z zkz}Ov%j~VOuQ!uM<%dmOn8Nv)i;5)FB~qZx{O^{ft~Un{ag(Y@vXwAd3!R{J|BBeQ ztXny;9ey40Y~zsX2*OFyOvn!PflxXG#MYbI99B)I&6SDRu>=@HIWaqy*P^HCtJ9*3 z_STqiR^Q6~pdo^_e-28`M)w?Av)luJEVONB;CRPrmc{7o3<<7XcEMk-M-IwrF8Nar z@|Uf!#~6ytxNO0CH##IXhi8bOMMYv7P%A5qvZ7pBh@`GDUd&Lf-y`<7 zt21ugUyD}m>mo+Shlur`K ztc>NPw?ed4->ewFn+1aDs43cbW^?3J!HH%f)vBe*mXZ&zz6qNQW-GFfp^F#%q{ZY4 z^Vhq34`FG1-&bs7-r0u$N9bfyTsBu)nu+G5_Gq9w;pWHi>T<N{4uhf05L`LESkG^pg-dn0JuMxPC`4CgGoc+$-3d>_=Wbo59Xo$Lbjet*T~4{Ex+CCY2J3Ib98F9qSC`NvVA?YZ^46en-Ar?j zmGB%AZ+Sm`d>wdl2dg=3sC(MjBRn3I+PPwj+6(s z+g%f3){X+1W(p=K+e!#qBcE8{kY-P(hPWoOU+S`XV?A#jdo<#`xrjN(tV_Kcm#Bcj z8R&y%*?hKiC?~{}nj?--`wH?B(&hsD~3tqz+Ii?7oVtnjQrzo znl`XT+uXHNKok5k;M zNot)z66&j43HkeDYBn89&B4RqIssh-&&y3m!U_aDRSb=>P-If(YGhN!o-OfLQZsBlBKjpah@hk4f zdsf_nw}h@_zD#DoJDRSq<;SSE^hMd(c-1orz!QVf%l3P^Nb#}i)SlBfjmEapbvE6{ zX;Jx;tI5>@Mp!@6q@Nd8V{nyqQzRUohT3 zfOFly#w(ugB6QS$21=G&H{|4iA0YB0(wvWlO}!N~)H*v`bcs1hNcs%q*xmbpMkU~JZ2eS5Rsz1T?!Mb*+6$`m7Z1Z>mfVqF;U&m*^q}INv1DS)qlQf z`jN#5Qpta5137{{@66XsjumZ9!oxWYxl$Cl7ZXO>OiAUc8Rx8Y`fP&h`NlpESN0?u zvK)S5W&&>D1wB0dr@&7=F0-Kr*rvLKI^dd4;o@{fw@KVn$5LqSlT~zyX2>hexYBG} z%JCX#_O+;T#wQ*I$AMNeh5Mx0hP)nz$66hJm1iK8chs$9ycS|XxUOrkxaUx;r=#Si zSpNmX)llo**%=^?ozT+_ax>`Fu9S@t6&PXsYR)2&ccj$XxuoOl)|i6H+>j=$Q!VJ& zNOK$dmPQ1Q6>IRGSczqU?`u!zqdxBqT%c{$R=1BtKg*)MsT^`OLna3pq(-)q&$0b( zLwo5jE})K`5tYZ+mlR7_s@>;ho7{MStg<8HG-|Khd2=8wVshZ}KWWP6Y5oOWK;hr+ z`pQcdi{waWx095u3ta?2PXD3g83>T8Sin*(Iu9tIb>;dK@sssmX{rTX=Tz{0g>JDz zK;Z>{KFSzq=Ejc!ys!_c8q(H|t$2rR;1z5D8cU^2E0m&91ouo-xv1iHY9sn-}BxpeogjL?rN zL$j$8ZUb?_#Sjf2DQ4uSoVm$_gpr4sx7|mSeDBuA#+(ZucTH6`tdQyS61is5MeF&r zac)xAHWY8MV0=c_F1M8)tYk?9L+;Dlg_dH`gtLzX<&`|D+*4kt)m^GoP`8DTev|Eh zSD6|{^loDHh^2nnFSPEJ#5c5G6(y}FW&8|TDDZTV^7dj^4{PF!wo9*w!6@dO?s%#f zC2D@TeH1{(@y<1KAz4F=xM_|tDt|WOm5mk<_fK*bAKF$ZU}1@$W*q)I93acFdJezs zMDNv>wbQaEPnd7DCapO<)T9NBx!98;p@0p3NgtuD| z$_TOTsQ9SaoKNsvN0E(OGm!I-z%!8S#lp{i{zXd=^|K!)U^1kS&Sz$1|1tG^OfGke zA+07)nYk*xQ^WZNC>RPArFh{z!s|;C7vrd^;yM9vj&eXpH>->@dN*keWK8Ju*N7H* zAbpa^@cJm)ovbnE*l_U6ChqUrJ1@Bo>prlb7Wh;gz-WSTD2a_^+I@jNJ_qr`E0O%H z|Nmk1;`SLx_Y6eGTEY6FS6l3niB+N%{*w%okI@W2)|{X{Tyrl2+hPG7HyfCXyG z-46|C-N4;|<%;;G$n>+KKTI<4jMrs2;p7t({YTb*2Ar^7b6aLuz@=otPd8fKLCQmP z)4pZnK3+bacpP8l`Wc7?^F)T8Tp)=5oXi|>=r3g9{AB+>1H>x;^!mZowNaln*Db$Q z|CQNDhY+Luuwqi-SBK5DMUW`&C0$_}dDZN<>Ndj6Yh(3;A&ZD-(F$G2#o2s}NaN$N zM6OIC4z3_T^@Mt@BYq5uruoqbQ&8SseL~R6;~<3IMUzz7F~CBg6dyD;Mfxdcs)SANpvWyDF~n+qeWP_Q zRG?6nHzHlm`m;^Q#K?YU37til!QHq%Cw_J@T;K+*j`Z6L^r!&@nkBxHAMdqBP`Qn_ z9_jod96FkDXISa8e$6k?2S{ut@w=s1#)!N@x$0O{zC5j2mIG+)0RA_+wU>7WT#LT5 zhUEm#Yq@<(e1;d`Tuuyigkqwp@6BGFrTZ|ilt4maamD3CXvUpu`8R24Gl{>E`&+>w znaHCDQ@om`CEH;Jw})m{D0>+ory&C;h%*pzdacR=roP3e=M1D)|o-b*Umgfx?z zOuS<4#?32|;wadDqnXv(n@R<0F>kWYzVHOo5-7CSM?Xw!5yX z*8eW|5XJX6K0ZFZLaBhT>AG~;sil65K3-GTuOoPs)Idbd#O~8yl5;1w_l}qg&Gr*c zyAEpn>~kAS7yl2?AJR*3$*v1cn4zG^>zq6ETDg&fZqFD3cQN*yqmK4Kf1Yn{BsV#^d@#q|24|m zLy3HL!e66gWV(7@O@ddugiqQmUE}8rM(b~!p3m#oDG@}Ut5k4!{5ncmjXqU?;|k+P lh*gsFltFoQj+8b^nyj^-+flyQQhn&Z@PhrnP!OC={tp1dmC67B literal 0 HcmV?d00001 diff --git a/images/right1.jpg b/images/right1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..db4520ca88ed8713c4049fed8da3800cfdffb7fa GIT binary patch literal 52760 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 X*)A=FGcxTByKDN6lu<-C8$bWqr~SPH literal 0 HcmV?d00001 diff --git a/images/table.jpg b/images/table.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c4a157dc051b9e09be9c8c4abd3bfa20266f2f96 GIT binary patch literal 9756 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 literal 0 HcmV?d00001 diff --git a/macros/blobAnalysis.sci b/macros/blobAnalysis.sci new file mode 100644 index 0000000..98b93eb --- /dev/null +++ b/macros/blobAnalysis.sci @@ -0,0 +1,140 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Deepshikha +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function [blob] = blobAnalysis(srcImg, varargin) +// Detects blob in the source image +// +// Calling Sequence +// [blob] = blobAnalysis(srcImg) +// [blob] = blobAnalysis(srcImg, Name, Value) +// +// Parameters +// srcImg: The input image Matrix. +// ROI: This defines a particular in the image in of which you want the features. +// filterByThreshold: This filter compares the intensity of a binary image at the center of a +// blob to blobColor. If they differ, the blob is filtered out. Use blobColor = 0 to extract +// dark blobs and blobColor = 255 to extract light blobs. +// filterByArea: Extracted blobs have an area between minArea (inclusive) and maxArea (exclusive). +// filterByCircularity: Extracted blobs have circularity ( 4∗π∗Areaperimeter∗perimeter) between +// minCircularity (inclusive) and maxCircularity (exclusive). +// filterByConvexity: Extracted blobs have convexity (area / area of blob convex hull) between minConvexity +// (inclusive) and maxConvexity (exclusive). +// +// Description +// The function uses SimpleBlobDetector function to detect the blobs then it checks for different Name +// Value pair arguments and accordingly returns the parameters of the blob such as 2D coordinates of the +// blob, size of the blob. +// +// The Name-Value pair may be any of following typesbool filterByArea, vector [minArea maxArea]bool filterByCircularity, vector [minCircularity maxCircularity]bool filterByConvexity, vector [minConvexity maxConvexity]double ROI, vector bool filterByThreshold, vector [minThreshold maxThreshold] +// +// Examples +// img_2 = imread("/images/blob.jpg", 0); +// +// lis1 = blobAnalysis(img_2, "filterByThreshold", [200, 255]); +// lis2 = blobAnalysis(img_2, "filterByCircularity", [0.1, 0.9]); +// lis3 = blobAnalysis(img_2, "filterByArea", [1500, 1600]); +// +// dimage1 = drawKeypoints(img_2, lis1.Points, "color", [0, 255, 0]); +// dimage2 = drawKeypoints(img_2, lis2.Points, "color", [0, 255, 0]); +// dimage3 = drawKeypoints(img_2, lis3.Points, "color", [0, 255, 0]); +// +// See also +// imread, drawKeypoints +// +// Authors +// Deepshikha + +[lhs,rhs] = argn(0) + + // To check the number of input and output arguments + + if rhs < 1 then + error(msprintf(" Not enough input arguments")) + elseif rhs > 10 then + error(msprintf(" Too many input arguments to the function")) + elseif lhs < 1 then + error(msprintf(" Not enough output arguments")) + elseif lhs > 1 then + error(msprintf(" Too many output arguments")) + end + + srcMat = mattolist(srcImg) + + if modulo(rhs,2) == 0 then + error(msprintf("Number of input arguments must be odd")) + end + + select rhs + case 1 then + output = raw_blobAnalysis(srcMat) + + case 3 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + output = raw_blobAnalysis(srcMat, varargin(1), varargin(2)) + + case 5 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + output = raw_blobAnalysis(srcMat, varargin(1), varargin(2), varargin(3), varargin(4)) + + case 7 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + output = raw_blobAnalysis(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6)) + + case 9 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7)) <> "string" + error(msprintf("argument at position 8 must be string")) + end + output = raw_blobAnalysis(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8)) + + case 11 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7)) <> "string" + error(msprintf("argument at position 8 must be string")) + end + output = raw_blobAnalysis(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8), varargin(9), varargin(10)) + end + + blob = struct("Points", output(1), "Size", output(2)) + +endfunction + diff --git a/macros/decorrstretch.bin b/macros/decorrstretch.bin new file mode 100644 index 0000000000000000000000000000000000000000..94d0503eaab12fe4f5bdbb0b81a7ac1aa4391831 GIT binary patch literal 3972 zcmds)&2G~`6on0lzmU3ZpmmDvHnfo_rK_@F0TLTv!wawji8teQ`WPS~HmCx`3K7od z&Phj8Pl%AZsimvAp8GTBp1CtlR?6YHuA8NIS9 z^B9k>6~(ITJCeteeaWxcY__El*^rDRrKFKyXFcABlCh)?!W{ksNh=`^dnF-`c;@lP z7o8mI670O=k4_H9k!Lf^t!X6oiNv_2&UNSdsT#-u9@juV;>rJ6cJkbpY)jCwg9qKY zr_%8U7k*%b7wg}YC&h;Uk%TeF)gmq)DXy>P1I@EX#wK;H-;vIGUqan*O#NV^9&j@< z&)Uv$PdagZ>m3FgHNs6?cP=KkFYrptkH9+^m;(=MlN*fa?ipizuQ_5rDVF`khj`}j zVK2OQX%2kgf&7Sj0WO>)w@3I~R6j4vC-^54*9~Xxadc{BP}*yFs65#NY4a!yiB9>A{$LZ1{qSHGC#>7}+0e#3A7E9TH>A z_1pe;RQf&59x;d6xAvfPM^XYn6C*Je;e!>U4W57lY)a0|l$eIXs-H`aXDrHcwRmo?# zd;Oyve2=e7^yw||ML36yA0+j9(-#VaVq<{~EY$o)YmkeFzC&M>6TdV3CojPEOhO!3 zUrWdXC$5*8!O!>etJY&rsR58a1MX>J;R_pFa%STmXP)yyethBG-z|K}%U*$Jv)QUg zRlAxJ)W<8>i7D%PT&Dqg&&9AFv7FOEmEQ}v_+NgXE7ttJ40%{Ld*11Sg=6jt_xHzehHx567;lx; zaA&%b{*77&$9OwMe_D)j#8`5^F_vbum;O!b5-x+K*-MBFug1c+lKqN%p1oQWM=baL zp#)#|5E#|m+!z^0`w5W@1efAu2(X-h~*(}kzdSTj^kzc%l%L0dq!Pw$8Q{T I3%!W`7fZH2aR2}S literal 0 HcmV?d00001 diff --git a/macros/decorrstretch.sci b/macros/decorrstretch.sci new file mode 100644 index 0000000..9e653a9 --- /dev/null +++ b/macros/decorrstretch.sci @@ -0,0 +1,55 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Dhruti Shah +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function new_image = decorrstretch(image) +// Applies decorrelation stretch to an image. +// +// Calling Sequence +// outputImage = decorrstretch(image); +// +// Parameters +// image: Input image. +// +// Description +// This function applies decorrelation stretch to an input image which causes the image to enhance +// by way of amplifying image difference. +// +// Examples +// i = imread("images/lena.jpg"); +// outputImage = decorrstretch(i); +// imshow(i); +// +// See also +// imread +// imshow +// +// Authors +// Dhruti Shah + + [lhs rhs] = argn(0) + if rhs < 1 + error(msprintf("Not enough input arguments")); + elseif rhs > 1 + error(msprintf("Too many input arguments")); + end + if lhs > 1 + error(msprintf("Too many output arguments")); + end + + image_list = mattolist(image) + out = opencv_decorrstretch(image_list) + + sz = size(out) + for i = 1:sz + new_image(:, :, i) = out(i) + end + +endfunction diff --git a/macros/detectAndComputeORB.bin b/macros/detectAndComputeORB.bin new file mode 100644 index 0000000000000000000000000000000000000000..b2be40699f7c59115fb67b9cea52448786f6b84a GIT binary patch literal 47820 zcmeI*d#t2qT?g=Osj}U6mv(#Et!H;Rt?jmM*QP8;69IcfK)fJ=R%x-)QX`f~BpPq6 z(P$tT5{X74(LhYRMdK|RF9}|v(P+dQX@U_ol46_IqP4A+ztsBsoO!>y&%8Tx&dj^? z^>lJ3c{0!YJiq(z`&?({oc#xm9=Q1Er?1@q^r0)SI(GEHqYpiO{SEcnzh}>$^Qs(P zyU62Nuk)+#$lAq^UwO${T{paN-`c*lOAa3D_k7@{J$qhId@rnWXO$bOJo?Nt&#cw^ z!72x;9IA4(tFr;klST9CDi2lpmnz!!RY4mXG7eY4tFJHPzl!hSDvwurstTFpd|nkc z=tFa&p0%^*NLN4B)!7$)%o4)A0xU0{yQy;!7t6Wuu?C_yizqAT@oQdKEhge)v1>cLSB>q)BU8fJv)8#+!I zORLUjc3)KGmMZ#Ab?@`yC+FnrXWP8EwfU1zv7w7y@+}U0klWaJchz^AeJ|;3`q#2q z9@s6e@u_WNyXWAbj~lTPJN%&$135MRk~?zbGI7=}cG{B{{9>scKitx%9z9|k`ycG= zhoj&meK44UC;6!A={k(i|41i?-q!bw7wv3|41VF$rmvs>lU=_#q#a}Y;D0+F$|#e^a&^^X$Lp((&YS|9Fxb~kcJh)q1$)Lo&D(fg-1QUY2$NZ-1>P>N1JhmPCnVdU(ezm zxn#yqV?-Xbq2mu7Fhzf`g+G3yBg->8gOkW;`!a6L9q}dnZH(~1g}%r;uj>3{$1=X1 zDtg5p123QGitLP==+uXfj~NGO6h3Ols}G%VG%sfSmE(4gvR=;_KZyZ3v5EYQ3BGHG zRraAvE;H}Oj>IeeT+s2gJn$?2U>EnM?l-gJG#Xbk3MqgWeXYWRmk9vlK8*1>iUD>V33@&>ECKh>W3dZ^u`DJ z|%FfOBY+oXl0Sn`pR~=3g*rI84LYf(9^ah7QqBQdXtmH3?HB9rOz`v6X(#O zG5)-NCUf$(PG)~h(i49Y>$J5tt7jagOTVJH+qA~==O|89#YpA zygLVkr;QVxi4_~^Cttfb^FzORO@DAi7G3&-L%5jbr}p?59_M-SZ}A>FHlU}APw_{4 zi;FL;XZq+TOF!Sx&%#!)uxKnY|Ip#(ogO)uy+SGIi79bPt( zFV}DjgYqXwXuR`*tyu@ype<{GdU#qsbo9x4Xvj2ff=%}Ku}Mbu2YA^<7G8F=b+pM> zbkm78cB5BX8}OjRqmMmefzLCW)H5bCU&j{o?R=cEoqUjiSFZYN+{tPqyWg&DkzBX3 z@vw;>Y|5Awx8w(Xiy1mHkKoCi(DKjwtb%-W^zkop_?@_E%YMW95bP$F>_roslWTUd zg-`m#T#n=|xx=TQKK^+|gBCX8KYHzG*c*Mp$`@4|IsMp>8+!Jtx8pSOwZ%T;0v&mD z(&brQTl~&gPk&^!xe5m@t@uL zIS=QptYGRb9WTuD9}WGp##euhqEqhC1{Y+om+kuEPx|MLQTvPR%jSKa*y2o`pX9S6 zdNcR7ee%yHal+^MTym1UW)2WbabrWP*SORsp4w-{HF0_ESH)OT@5>}FIo2mOv7wdU zj@8?XhOGANhBkikC;sy@W2GOXc0HUm7857y2khaehs}x6ym_YeKUj+$cw60VF8Pl> zV=D6bCN5&c2KJEC>e*^8&==duCx>6+2>;}WTd+xXavD1E=6h^ngZQ>>ZETFUj3>AV zE!lk=#9zO5{p<)<_Jv37;q9-<{m=4m zDwpU$4SfJmwU1e8nG3iTBH@pi8{i z;5qk1@alf} z?DQ>a-=cK0bg{+QofUt%>D%3Zj;*s~r*BdF7Nwh|i(P3qHq6_`^sF;^-v`gJH8R$! zEptfv7PW6tx>>r|BJS*`pDc3}e0kQ+KXWe|`@Y21S+di&sC|pl&C=ES5nK6T&T7|& zzWsTQt+QmOZ&CZq-~Bbi^LA^G`PLflmHLHMXQTa)aW5z40d^)=@)!E+tB#&Nbk-pE zm$kHSwx8PUZwq90aoCM3~Pee${!3yZsNm^;Hk}%cKM$583kE= z+uvDj?0adItf%e#&3=5*6(6;s;|E*iAMGtwT7PHB+-|MrZ|f86@o780*my3y#;Nau z2HV+}^1B_w>Y0Pkh(mkcldqgV`h2Z?SU@X&eL9~Pk}HNvZ~+5o`?dX$czV9RuwthjAA?joa1KJCZe zs`JBoU|h&U#uC58Cwy>-HhV>WC>d9o3(@54o!IEZPnII~pIs#{c&Q(*ob|gEzhn8| zvJD15tIG4LpjFuF{hlgommcZ=?rtCApMOxrxv6&u?+!PwdmiX8drYZ>yMW=O>%4JaX0A z!9z!1&T(v$vr8`NGdA?ohhE!G&dpYHLYclL{$E@Da{R?r z`nfUo#BCY;XH1CSkg>i>ac;-JYbqY%{3TWTarV8?MaRG@#<$$xe0}JZlNi0ap2R3| zf{A&*5&iF)n=x&vPnW?93ot2W~| zYwOVUe7m(vpv>9ym^X}nZPBL=yV+-L#$bo7b!Fb>>lLq>#PciaDY>_&xxO}5-WB%G z%XxKezVOQ5ncO{b>+yP)tFNk(T#+>of5FeDzJ2T0?w|2H>qYQ=_}J0{ z+Zg)pDrC3gim(H-7$4GR<=85RoFIP54?JUk2~sVaeVCEFz$xnf2=w8&7D7E;KNv5)j9W$*G%wn zXA{ro(wsXzZx6%mw2VszV}Gl;-@Ko>-`?ij=l&xb*H)s;{dZMad~82)>rNlrcX$4b zF}B5GRmb)l>M{~O>@60@$FMOZj$_UJ-_-dt20m7K?*Dj)k8fTIAD0iFAIHMS+eXBP zxqMaUkGo$xnLqAr;%S^eSI%S8>-w;HZCb{#y}`7MVdH07#^J$ZaH~Da^DDR6qwKBv zx$jY~+4!3Rj5X+6t1P|-?fgB;J34>lMRB&juFCG6&tjhgR;V^#_thmce0*D##qlw0 zERVTId1vR(82DJ_J<9oCKEcPgFNKd`bL^P-_>K|rvC4at_jdUB&ZY2iWbpbq)*kk| zM#P7;epUCd2kS#O>&y2v@!Z|RE`PUc9W#$iUc=_sX&J-zu+uVzjpJz<>x1Wlt@hFv zR-m$%wkJIIz4Y;oZ>dctEZ<*c@x9W{-%EdA=a0N7yL;*B&jlC#tmk!KIl;&GFNKet zznA`j5%ICgd+CpL`1rx4@G)$zA9FALLnGp2mG{zjzHTyqylW|Z3|oW8#K*fw#K$V{ zr62C_@ty`B_ig+At!oDFub%C*mhWxZPyO%=d>pT~XX7rkp=7Z@o+qHw|l&#Ke#(U0ezGr;yXSNd?m(_;Sc=(Yjt8`|2U+2&6 znQbz^^|7+(neD@`pWx$1m%_)+KePSVi1=9LGutb_dV-H1UkV>P|IGIO5%ICgXSR=Y z`1pyX@UipHY#$gAAFF(3dt?3B#{T0c8+@$7neC@$;A8j9HtgQ`A3BVDa4C!&AG`-2 z>s6MfBg6Lb&ZJ}AFZ|}n7+K}}h5Ns5GLQV$QW!Zg_?$Kt zMt*x_jI8or^@92%H}->=yW%suY!}gHxsy_$@AAiurbFq8Qoqvz@hn+uT;A55d z1{dEx!N(shg^!(okM+kR;$xNXvEJX|<4=~t$IidU`qL5dvC8*YN9qqGT3`OG!N)4x zWBvIId>pT~-QPA$_O17b#Ww%5phz}fKi6U8FX}0K)a@~{^Y5`f()rWwL7q*Ftnxk9 z=hq)5HIMw&QWzO_)*JJ#^RGw7$SUtuf2YI9-!6rbn+Bid$GYqM=*SpZ<^Afd-!Pd+ z9%y2^d)K*p*9r5J*Z<$|=Gc9A-`Zq0O*j?wejA3)^w2Yev&(mAox!P~$ z&ei_n-0xgpym5Xdk*tqZ$$oYfzB~ALoj>xT?B2N!yK{Z8{wO?r{CyYCRk?Hhc<0X; z_*mtA?7iPO!N)%?g^!(o=lV}0;$xNfuupdQ_~)hYvGea-KQSUcR{75Ld*3pdKOSuG zvHgA8uzl~CcO{>kfsf%{js)YHCJ^@CLoRj~)ezf=Ej+=a?9IwDYIkr#_qW z$SUtuFS~n!k;j(8$gul>F){L~kukE$`_&J282R_5F!G|o_dR3X%RfFcM)sCIYso6E zHP^j$GLJmb#MF4-{hv5%`_?Wwc&Ps$f#>~yUTd1UWbztzConBzr~EzfVds-+UxxjC zyJ;E2_Q2CJhV7B2Wjwd<<)?iaHrG$fI5l{^*y{6vOKTwI^8x$zWj`P22I8LIf7N7u zd#W1jr4{zOLpNR@slWGnxZZO%aE5SZnD%ke`&MkFFiNc*g%QXP>=r;_3aYc&=U4pXxTBi}ZBde78va{tpT+d}ROt literal 0 HcmV?d00001 diff --git a/macros/detectAndComputeORB.sci b/macros/detectAndComputeORB.sci new file mode 100644 index 0000000..eb55757 --- /dev/null +++ b/macros/detectAndComputeORB.sci @@ -0,0 +1,257 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + + +function [orb] = detectAndComputeORB(srcImg, varargin) +// Oriented FAST and rotated BRIEF (ORB) is used to detect and compute the corners in an image. +// +// Calling Sequence +// [orb] = detectAndComputeORB(srcImg) +// [orb] = detectAndComputeORB(srcImg, Name(same as the ones given under description), Value, ...) +// +// Parameters +// srcImg: The input image Matrix +// ROI: This defines a particular in the image in of which you want the features. +// maxFeatures: The maximum number of features to retain. +// scaleFactor: Pyramid decimation ratio, greater than 1. scaleFactor==2 means the classical pyramid, +// where each next level has 4x less pixels than the previous, but such a big scale factor will +// degrade feature matching scores dramatically. On the other hand, too close to 1 scale factor will +// mean that to cover certain scale range you will need more pyramid levels and so the speed will suffer. +// nLevels: The number of pyramid levels. The smallest level will have linear size equal to +// input_image_linear_size / pow(scaleFactor, nLevels). +// edgeThreshold: This is size of the border where the features are not detected. It should roughly match +// the patchSize parameter. +// firstLevel: It should be 0 in the current implementation. +// scoreType: The default HARRIS_SCORE (flag value = 0) means that Harris algorithm is used to rank features +// (the score is written to KeyPoint score and is used to retain best nfeatures features); FAST_SCORE (flag +// value = 1) is alternative value of the parameter that produces slightly less stable keypoints, but it is +// a little faster to compute. +// patchSize: Size of the patch used by the oriented BRIEF descriptor. Of course, on smaller pyramid layers +// the perceived image area covered by a feature will be larger. +// fastThreshold: The threshold value used for feature detection. +// +// Description +// Oriented FAST and rotated BRIEF (ORB) is a fast robust local feature detector, first presented +// by Ethan Rublee in 2011,that can be used in computer vision tasks like object recognition +// or 3D reconstruction. +// It is based on the FAST keypoint detector and the visual descriptor BRIEF (Binary Robust +// Independent Elementary Features). +// Its aim is to provide a fast and efficient alternative to SIFT. +// +// The Name-Value pair may be any of following types edgeThreshold fastThreshold firstLevel maxFeatures nLevels patchSize scaleFactor scoreType +// +// Examples +// img_1 = imread("images/checkerBoard.jpg", 0); +// img_2 = imread("images/chess.jpg", 0); +// lis1 = detectAndComputeORB(img_1); +// lis2 = detectAndComputeORB(img_2); +// dimage = drawKeypoints(img_2, lis2.Points); +// [matches, distance] = matchFeatures(lis1.Features, lis1.Features, "Method", "Exhaustive", "Metric", "Hamming"); +// matchedImage = drawMatch(img_1, img_2, lis1.Points, lis2.Points, matches, distance); +// +// See also +// imread +// drawMatch +// drawKeypoints +// matchFeatures +// +// Authors +// Siddhant Narang + +[lhs,rhs] = argn(0) + + // To check the number of input and output arguments + + if rhs < 1 then + error(msprintf(" Not enough input arguments")) + elseif rhs > 10 then + error(msprintf(" Too many input arguments to the function")) + elseif lhs < 1 then + error(msprintf(" Not enough output arguments")) + elseif lhs > 1 then + error(msprintf(" Too many output arguments")) + end + + srcMat = mattolist(srcImg) + + if modulo(rhs,2) == 0 then + error(msprintf("Number of input arguments must be odd")) + end + + select rhs + case 1 then + output = raw_detectAndComputeORB(srcMat) + + case 3 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2)) + + case 5 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4)) + + case 7 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6)) + + case 9 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7)) <> "string" + error(msprintf("argument at position 8 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8)) + + case 11 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7)) <> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9)) <> "string" + error(msprintf("argument at position 10 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10)) + + case 13 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7)) <> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9)) <> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11)) <> "string" + error(msprintf("argument at position 12 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(12)) + + case 15 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7)) <> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9)) <> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11)) <> "string" + error(msprintf("argument at position 12 must be string")) + end + if typeof(varargin(13)) <> "string" + error(msprintf("argument at position 14 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(13), varargin(14)) + + case 17 then + if typeof(varargin(1)) <> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3)) <> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5)) <> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7)) <> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9)) <> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11)) <> "string" + error(msprintf("argument at position 12 must be string")) + end + if typeof(varargin(13)) <> "string" + error(msprintf("argument at position 14 must be string")) + end + if typeof(varargin(15)) <> "string" + error(msprintf("argument at position 16 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(13), varargin(14), varargin(15), varargin(16)) + + case 19 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7))<> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9))<> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11))<> "string" + error(msprintf("argument at position 12 must be string")) + end + if typeof(varargin(13))<> "string" + error(msprintf("argument at position 14 must be string")) + end + if typeof(varargin(15))<> "string" + error(msprintf("argument at position 16 must be string")) + end + if typeof(varargin(17))<> "string" + error(msprintf("argument at position 18 must be string")) + end + output = raw_detectAndComputeORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(13), varargin(14), varargin(15), varargin(16), varargin(17), varargin(18)) + end + + orb = struct("Points", output(1), "Features", output(2)) +endfunction \ No newline at end of file diff --git a/macros/detectBRISKFeatures.bin b/macros/detectBRISKFeatures.bin new file mode 100644 index 0000000000000000000000000000000000000000..c2addfa4365ff3bc69f3cefb98589b5bdd4571e9 GIT binary patch literal 12612 zcmeI(-;P|x5eD!HA;DR%7qj@!!t9uhu>@JbiA-!G6p2NGD=zW?x#S6W2O>qv6%UY` zAi;xhg?NW32uMPR5J@0cQB3`o^R0W2&zXN<%Nt>-I6d7}UsZio-P1EWoY|UfZO*>> z`16lG`(kTjc4@k``?P;&CX>kzN}kx5ZcNYaT$&xu-u}-6wYGg>eOP5tdkt`F*T}&%^{r&if^F|JmunvnDPvvk$MarBBcEYzaND`Jvm!m009; zq0?hy{`r#BvxY}w^@ROp*}#<(iGTLiaRBG>67d@2h=1c?KUHJ;kv1=Ou*2)MPH(K{ zL-k(7oqia~f4}CRDM_3+JKy5GUt;`a7t^O*Ez}UVng6h z*A6GW6hG?1pLx9%jNjFG9#7A9>qGV8YiKXPsW#?DHW`dyQ+#@QjZ07K z_%M&7)G@Ua8xDgN9CjIt$2whnnm30(dbqT1Zm%0h-+H*`M^1dhqGKE#bE#c?q<)_1 zIW}$oCO`IhuS$Mi!wQ#b#vi`bS`0W5BmBHKr7ksf*xPyo|FQ4aAomCMaNzQjT8JM% z=E7Gy9^VD7lUMqQAF;?SIi^;NYR&d)iRTYX)Y-V7@47XX7p`FT_mut=Z+H{G z+}P+P&#c83PWZ;hUI`2mKl+1Sd}m)hSaWUPyxHls=hk1k9!d<^i`nn1_D#zrtn{Df zymLHy{a#pf-sOHe7QcBM6P)GDH4aaDx9u&ud5vSb>LSK<`mD?j?bK<%q~!><*X#D% zqTVRz!QSYfDSztpe15Wry`PI~o%+L&SN}YQ2Rmm4ANb8a$1yuRn+w<3n{7X}W4h{m zu7rK|g}L;Vad@Vq#_UpOYd1=qE79}ZE8$D8(9gXz_a$rc^xFE(lEnSz$}f6}Nj&rR z0YAC>#GiP@f;aKOO8orGA^7a+vu*PX4}HvVmi;a^cyM9TkL_NK%?BeoVoU9YY7Q?o zSBL1PCVMpptL6CT^*Y>HYdLP~l32{8c5uZG&%C|mnZ1&@VVVy{c=lS%xUlYQwk8K_ z=Ely5b`6GH#Sx!kg8>h(?fG0U4}FLiKCIkZ=$eBEE9aOoKk^kH+t*6i4(%H{i+U*a z5hq=*;inJGr#AcyeGW9wmpqemu#!8Sv3{kK`h`3C=^1ylRqpR>;dnoRq4s=?@&A)r zWAm@t!#}Mj8@6~)Kj0&r!=`TzKlIhh{xWC%$r3)@QLdLH7WiK8mpoGvOn7bFV!l%1 z>^6U`dnT{cjc?rX^FhVW|4{s}VrxB|z{ks@CGs^7C+AYVTsl^Dx|^}WUo}>B5R*E} zA3uFg$NF-p*O&Q@Dm=F}?ALoJu0DTvJ1+kEalKV@_*%4|hk8@L>u-BPf9f;)!s~T; zOCR>@rw>;7ZbwfK)pP7Sp>_`#kA2V6>J7y>W|zF!yC>mG-{3Is#rVUW`JDTU{H=o3 z#?b#BTpWvh4cUB~e(LxCcim6$lXF`u^Y?o{CB}QzPw{sz`YFDa>8D>;t(;Hp?|DzP zN1QXcr#RzNXJ=^6eR}qk{Y77Y-7IO}vxYF2IlGoUFZJ0Xyu`i?X1H5~+25DH>GB@R z7cY1l`=0k&XGZxw23a(>PlPEM7)-Q`3dUvTGP(z_l1YvQ=D``C2*;_Tr*CqsOSna$R8x-;z?jMSj5 zxf*O-9IpYM^Y4=iUhL16g#SMd@IS9^ux|7J#Y=tuU#)dMu9l?l!#_Tk;a_dS`~O=F zUacm<&o4TD^wfLR0C+Uk3yb<6ull*I!^`y=?zNKe4r}Z@XwRFS%_pv$8TcL3P``@P z{`b^-L%(0r#W=R=-|8cwdD|{Pybm zek~GCc)uR+`Q5d8{y4_oS{RG=jqfJ1Z`>#E_kE)?{ClUn7yB%i{nFmQaOaLAzxKP0 zvA+Z0Y3#0;yDz-cC98Z_3U};&+Tx0R>^ol=WB1<{L+ysXTV+3Xx9;2LH;+C~<#Q_g pv3q;$>Fmy?mp1!fLe%}+eK)-o4%^S9K6{V-e-HH3m%QFRzXtG^d5{1A literal 0 HcmV?d00001 diff --git a/macros/detectBRISKFeatures.sci b/macros/detectBRISKFeatures.sci new file mode 100644 index 0000000..9626e06 --- /dev/null +++ b/macros/detectBRISKFeatures.sci @@ -0,0 +1,73 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Shashank Shekhar & Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function [varargout] = detectBRISKFeatures(image, varargin) +// This function is used to detect BRISK(Binary Robust Invariant Scalable Keypoints) Features in a grayscale Image. +// +// Calling Sequence +// result = detectBRISKFeatures(Image); +// result = detectBRISKFeatures(Image, Name, Value, ...) +// +// Parameters +// result: BRISKPoints struct which contains Location of KeyPoints, Orientation, Metric, SignOfLaplacian, Scale and Count of the features. +// Image : Input image, specified as a A-by-N 2D grayscale. +// MinContrast : (Optional) The minimum difference in intensity between a corner and its surrounding region. (Default: 0.2). The value must be between 0 and 1. +// NumOctaves : (Optional)The number of Octaves that the detector uses. (Default - 3) The value must be an integer scalar in between 1 and 4. +// MinQuality : (Optional) This specifies the minimum quality accepted for corners. (Default - 0.1) The value must be between 0 and 1. +// ROI : (Optional) Region Of Interest. This is taken as a vector [u v width height]. When specified, the function detects the key points within region of area width*height with u and v being the top left corner coordinates. +// +// Description +// This function returns the BRISK features detected in a 2D grayscale image. +// +// Examples +// stacksize('max'); +// img_1 = imread("images/table.jpg", 0); +// img_2 = imread("images/table1.jpg", 0); +// lis1 = detectBRISKFeatures(img_1); +// lis2 = detectBRISKFeatures(img_2); +// features_1 = extractFeatures(img_1, lis1.KeyPoints, "BRISKPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale); +// features_2 = extractFeatures(img_2, lis2.KeyPoints, "BRISKPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale); +// [matches, distance] = matchFeatures(features_1.Features, features_2.Features); +// matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance); +// +// See also +// imread +// drawMatch +// drawKeypoints +// matchFeatures +// extractFeatures +// +// Authors +// Shashank Shekhar +// Siddhant Narang + + image_list = mattolist(image); + [lhs, rhs] = argn(0) + if rhs > 9 then + error(msprintf("Too many input arguments")) + end + if lhs > 1 then + error(msprintf("Too many output arguments")) + end + select rhs + case 1 then + [a b c d e]= ocv_detectBRISKFeatures(image_list) + case 3 then + [a b c d e]= ocv_detectBRISKFeatures(image_list, varargin(1), varargin(2)) + case 5 then + [a b c d e]= ocv_detectBRISKFeatures(image_list, varargin(1), varargin(2), varargin(3), varargin(4)) + case 7 then + [a b c d e]= ocv_detectBRISKFeatures(image_list, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6)) + case 9 then + [a b c d e]= ocv_detectBRISKFeatures(image_list, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8)) + end + varargout(1) = struct('KeyPoints', a, 'Orientation', b, 'Metric', c ,'Scale', d, 'Count', e); +endfunction diff --git a/macros/detectFASTFeatures.bin b/macros/detectFASTFeatures.bin new file mode 100644 index 0000000000000000000000000000000000000000..af7e5afea756e8a8962af4016a169e3eec756ea9 GIT binary patch literal 13628 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 br~d8AnMJp!GkWa*cdDh69LU2@yYc@3!Y6Mh literal 0 HcmV?d00001 diff --git a/macros/detectFASTFeatures.sci b/macros/detectFASTFeatures.sci new file mode 100644 index 0000000..1c154a5 --- /dev/null +++ b/macros/detectFASTFeatures.sci @@ -0,0 +1,85 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function [cornerPoints] = detectFASTFeatures(image,varargin) +// This function is used to detect the corner points using FAST Alogrithm +// +// Calling Sequence +// [ Location Count Metric ] = detectFASTFeatures( Image, Name, Value... ) +// +// Parameters +// Image: Input Image, should be a 2-D grayscale. The Input Image should be real +// MinQuality [Optional Input Argument]: Minimum Accepted Quality of Corners, can be specified as a scalar value between [0,1]. Default: 0.1 +// MinContrast [Optional Input Argument]: Minimum Intensity difference for Corners to be detected, can be specified as a scalar value between[0,1]. Default: 0.2 +// ROI [Optional Input Argument]: Specify a rectangular region of operation. Format [ x y width height ]. Default: [1 1 size(Image,2) size(Image,1)] +// Location: Set of x,y coordinates for the deteccted points +// Count: Number of corner points detected +// Metric: Value describing the strength of each detected Point +// +// Description +// The detectFASTFeatures function uses the Features from Accelerated Segment Test (FAST) algorithm to find feature points. +// +// Examples +// stacksize("max"); +// img_1 = imread("images/table.jpg", 0); +// img_2 = imread("images/table1.jpg", 0); +// lis1 = detectFASTFeatures(img_1); +// lis2 = detectFASTFeatures(img_2); +// features_1 = extractFeatures(img_1, lis1.Location, "cornerPoints", "Metric", lis1.Metric); +// features_2 = extractFeatures(img_2, lis2.Location, "cornerPoints", "Metric", lis2.Metric) +// dimage = drawKeypoints(img_1, lis1.Location); +// [matches, distance] = matchFeatures(features_1.Features, features_2.Features); +// matchedImage = drawMatch(img_1, img_2, lis1.Location, lis2.Location, matches, distance); +// +// Examples +// stacksize("max"); +// img_1 = imread("sample_image1.jpg", 0); +// img_2 = imread("sample_image2.jpg", 0); +// lis1 = detectFASTFeatures(img_1, "MinConstrast", 0.2); +// lis2 = detectFASTFeatures(img_2, "MinConstrast", 0.2); +// features_1 = extractFeatures(img_1, lis1.Location, "cornerPoints", "Metric", lis1.Metric); +// features_2 = extractFeatures(img_2, lis2.Location, "cornerPoints", "Metric", lis2.Metric) +// dimage = drawKeypoints(img_1, lis1.Location); +// [matches, distance] = matchFeatures(features_1.Features, features_2.Features); +// matchedImage = drawMatch(img_1, img_2, lis1.Location, lis2.Location, matches, distance); +// +// See also +// imread +// drawMatch +// drawKeypoints +// matchFeatures +// +// Authors +// Umang Agrawal +// Sridhar Reddy +// Siddhant Narang + + [lhs rhs]=argn(0); + if lhs>3 + error(msprintf(" Too many output arguments")); + elseif rhs-1>6 + error(msprintf(" Too many input arguments")); + elseif modulo(rhs-1,2)<>0 + error(msprintf("Either Argument Name or its Value missing")); + end + imageList=mattolist(image); + select rhs-1 + case 0 then + [location count metric]=ocv_detectFASTFeatures(imageList); + case 2 then + [location count metric]=ocv_detectFASTFeatures(imageList,varargin(1),varargin(2)); + case 4 then + [location count metric]=ocv_detectFASTFeatures(imageList,varargin(1),varargin(2),varargin(3),varargin(4)); + case 6 then + [location count metric]=ocv_detectFASTFeatures(imageList,varargin(1),varargin(2),varargin(3),varargin(4),varargin(5),varargin(6)); + end + cornerPoints=struct('Type','cornerPoints','Location',location,'Metric',metric,'Count',count); +endfunction diff --git a/macros/detectHarrisFeatures.bin b/macros/detectHarrisFeatures.bin new file mode 100644 index 0000000000000000000000000000000000000000..414fd5480f901c44c3d2eff722d6256b41bf5463 GIT binary patch literal 9156 zcmeI&%WfQ15C-4@0yxHY923U_<8dxT5CV!&fP@7SMuHU^gkZ^vEqh*q7hug}AfA9N zJOJVnAc!Q~R)|pFxPQB6JUxy_Apyill|Fsy{#TvTr`uUx8Lli1uOA%@);4c0FAlc` zE1T!*x7_RX?kigA4>nc?S2xx+hNF2rzx#`~c5-obW#@M6-&2c&#lh;@#@J-te6i5$ z9V@+4MQ;|JFZ$}%ty{mH=%#qnD+9+Bo8W!RAi_Fn$%af(MQY3DCI^>PnBTqMc zcJT+zJY8e*j}_rXhpohxIdY3d?RZW$bE|b_k4$2V9-jH@l{bAp5q^A_UoRq?81cmc zD}J6Y3YIn89pkhAYh#}sH0l5A;*0U|A~6~VZ{yfLTVwWSVREUFfh}Eex~6trx!!DI zkS`r^z=AF;o-X>SWG>Y8nWDt>LXGcrOo`$924^)9cjmur=3yUv!&AG^WNyXU&GV5O z%kyeu3pTKdui$JRUcu*y8qdP#*@mwN*q|@Q)T>T-J~cNFZek2xY`|6y=7RNP?l(#&`H+pgIr_6=#ybd`(SW zdwSx3v`AchvXQe`-Hz5+`+O-T@yJ0ea+r*fT|R@aIE=gYirYEsChs;b7s_Tkw%6)j zZ2U)Fu5`rH#*qvR@J|>0Sb39iR_R(3Fpk}J9KmZ66WCsBFoywOa9~3n^k8&TJM-+g zimzRd%XRM;9q*Z*rzmqZ>|H6E#KwGjExnoNL9h`Y-)hQ#Fr?CUO#ysa1OvHCtf;i$TjyK`fVH8YsloCh+X#a=(C03|4>nWYFr--_I)q#{ov1v+1gY82a3odIlEdL zgX3eLCU!qN6sxyBgC~}SqR-0-+kWC?ca|Qxz4&juBDR-{=!y09B6iLeC0{x7VcmJ| zsvm+^o_TPhV-7FS=wSeI@;#brKt~t^e_+eS zYCg(oaX9R+uWb$|N_{))dSw6F@qN025{Lch({iF$JX84V>ce7B`qqe`{kBGY}T5cXDMoSX-I^ zwBfDymllU>{e90gdh+uQe7PaH*t@#UPw83fMQr+A&yv4Vbg3x%?AjYWnh=faTYa7@`ZwY{UaN)CbLz0Q8n>}JmyLt!t=6fx{=7H! z?r(oozSY}4@PEAvgx-Ah9`BhGbM?%)js9FV4(dDas_DCh8sD3~JH7o0q>H?l|KE27 z!oR%l#(Q^juHGHDae6Kr2lc;iJL!LCk-OFZD(v@hy+G)D=Qn-t%=K=OGnR9h^O^Sv z=Obf(zcufiWZpT+dx!nn)jc`y@;Rq@UwW~~`|R1edRJx7ob~2e3%|~bw-7q>&|<}^#6BL>`~9@yZ4&$Ul(hG AcmMzZ literal 0 HcmV?d00001 diff --git a/macros/detectHarrisFeatures.sci b/macros/detectHarrisFeatures.sci new file mode 100644 index 0000000..8e7817d --- /dev/null +++ b/macros/detectHarrisFeatures.sci @@ -0,0 +1,68 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function [cornerPoints] = detectHarrisFeatures(image,varargin) +// This function is used to find corner points in an image using Harris algorithm. +// +// Calling Sequence +// points = detectHarrisFeatures(I); +// points = detectHarrisFeatures(I, Name, Value, ...); +// +// Parameters +// points: Structure of corner points +// I: Input image to detectHarrisFeatures() +// MinQuality: (Optional) Minimum accepted quality of corners (Default- 0.01) +// FilterSize: (Optional) Dimension of Gaussian Filter (Default: 5) +// ROI: (Optional) Rectangular region for corner detection +// SensitivityFactor: (Optional) SensitivityFactor of Harris algorithm (Default- 0.04) +// +// Description +// This function detects corners in an image I. These corner points are used to extract features and hence recognize the contents of an image. +// +// Examples +// img_1 = imread("images/checkerBoard.jpg", 0); +// lis1 = detectHarrisFeatures(img_1); +// dimage = drawKeypoints(img_1, lis1.Location, "color", [0, 255, 0]); +// +// See also +// imread +// drawKeypoints +// +// Authors +// Rohit Suri +// Sridhar Reddy +// Siddhant Narang + + [lhs rhs]=argn(0); + if lhs>1 + error(msprintf("Too many output arguments")); + elseif rhs>9 + error(msprintf("Too many input arguments")); + elseif modulo(rhs, 2) == 0 + error(msprintf("Either Argument Name or its Value missing")); + end + imageList=mattolist(image); + select rhs-1 + case 0 then + [location metric count]=ocv_detectHarrisFeatures(imageList); + //[location metric]=ocv_detectHarrisFeatures(imageList); + case 2 then + [location metric count]=ocv_detectHarrisFeatures(imageList,varargin(1),varargin(2)); + case 4 then + [location metric count]=ocv_detectHarrisFeatures(imageList,varargin(1),varargin(2),varargin(3),varargin(4)); + case 6 then + [location metric count]=ocv_detectHarrisFeatures(imageList,varargin(1),varargin(2),varargin(3),varargin(4),varargin(5),varargin(6)); + case 8 then + [location metric count]=ocv_detectHarrisFeatures(imageList,varargin(1),varargin(2),varargin(3),varargin(4),varargin(5),varargin(6),varargin(7),varargin(8)); + end + //cornerPoints=struct('Type','cornerPoints','Location',location,'Metric',metric,'Count',count); + cornerPoints=struct('Location',location, 'Metric', metric); +endfunction diff --git a/macros/detectORB.bin b/macros/detectORB.bin new file mode 100644 index 0000000000000000000000000000000000000000..e26e1cad6e7543b3f7497907f0f7fa7679c35087 GIT binary patch literal 40036 zcmeI5e~4X2701{3Yr9Fd$u|3|Z(o{hlTC~H?tC|M@4jDmHgCK; zybFi>?)*4ð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 edgeThreshold int fastThreshold int firstLevel int setMaxFeatures int nLevels int patchSize int scaleFactor int scoreType +// +// Examples +// [srcImg] = imread('images/table.jpg'); +// [orb] = orbAnalysis(srcImg); +// [orb] = orbAnalysis(srcImg, "filterByArea", [0.01 1]); +// +// Authors +// Siddhant Narang + +[lhs,rhs] = argn(0) + + // To check the number of input and output arguments + + if rhs<1 then + error(msprintf(" Not enough input arguments")) + elseif rhs>10 then + error(msprintf(" Too many input arguments to the function")) + elseif lhs<1 then + error(msprintf(" Not enough output arguments")) + elseif lhs>1 then + error(msprintf(" Too many output arguments")) + end + + srcMat = mattolist(srcImg) + + if modulo(rhs,2) == 0 then + error(msprintf("Number of input arguments must be odd")) + end + + select rhs + case 1 then + output = raw_detectORB(srcMat) + + case 3 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2)) + + case 5 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4)) + + case 7 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6)) + + case 9 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7))<> "string" + error(msprintf("argument at position 8 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8)) + + case 11 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7))<> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9))<> "string" + error(msprintf("argument at position 10 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10)) + + case 13 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7))<> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9))<> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11))<> "string" + error(msprintf("argument at position 12 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(12)) + + case 15 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7))<> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9))<> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11))<> "string" + error(msprintf("argument at position 12 must be string")) + end + if typeof(varargin(13))<> "string" + error(msprintf("argument at position 14 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(13), varargin(14)) + + case 17 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7))<> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9))<> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11))<> "string" + error(msprintf("argument at position 12 must be string")) + end + if typeof(varargin(13))<> "string" + error(msprintf("argument at position 14 must be string")) + end + if typeof(varargin(15))<> "string" + error(msprintf("argument at position 16 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(13), varargin(14), varargin(15), varargin(16)) + + case 19 then + if typeof(varargin(1))<> "string" + error(msprintf("argument at position 2 must be string")) + end + if typeof(varargin(3))<> "string" + error(msprintf("argument at position 4 must be string")) + end + if typeof(varargin(5))<> "string" + error(msprintf("argument at position 6 must be string")) + end + if typeof(varargin(7))<> "string" + error(msprintf("argument at position 8 must be string")) + end + if typeof(varargin(9))<> "string" + error(msprintf("argument at position 10 must be string")) + end + if typeof(varargin(11))<> "string" + error(msprintf("argument at position 12 must be string")) + end + if typeof(varargin(13))<> "string" + error(msprintf("argument at position 14 must be string")) + end + if typeof(varargin(15))<> "string" + error(msprintf("argument at position 16 must be string")) + end + if typeof(varargin(17))<> "string" + error(msprintf("argument at position 18 must be string")) + end + output = raw_detectORB(srcMat, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(9), varargin(10), varargin(11), varargin(13), varargin(14), varargin(15), varargin(16), varargin(17), varargin(18)) + end + + orb = struct("Points", output(1), "Size", output(2)) +endfunction \ No newline at end of file diff --git a/macros/detectSURFFeatures.bin b/macros/detectSURFFeatures.bin new file mode 100644 index 0000000000000000000000000000000000000000..75345628e448fb6cf5967c4317acffbd1d0ab463 GIT binary patch literal 15540 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 literal 0 HcmV?d00001 diff --git a/macros/detectSURFFeatures.sci b/macros/detectSURFFeatures.sci new file mode 100644 index 0000000..f2d6b49 --- /dev/null +++ b/macros/detectSURFFeatures.sci @@ -0,0 +1,74 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Shashank Shekhar & Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function [varargout] = detectSURFFeatures(image, varargin) +// This function is used to detect SURF(Speeded Up Robust Features) Features in a grayscale Image. +// +// Calling Sequence +// result = detectSURFFeatures(Image); +// result = detectSURFFeatures(Image, Name, Value, ...) +// +// Parameters +// result: SURFPoints struct which contains Location of KeyPoints, Orientation, Metric, SignOfLaplacian, Scale and Count of the features. +// Image : Input image, specified as a A-by-N 2D grayscale. +// MetricThreshold : (Optional) With default value equal to 1000, it is to be specified as a scalar. Every interest point detected has a strength associated with it. In case, only the stronget ones are needed, this parameter has to be given a larger value. To get more no of interest points/blobs, it is to be reduced. +// NumOctaves : (Optional)With default value equal to 3, it is to be specified as a scalar. Larger the number of octaves, larger is the size of blobs detected. This is because higher octave use large sized filters. Value must be an integer scalar in between 1 and 4. +// NumScaleLevels : (Optional)With default value equal to 4, it is to be specified as a scalar. It denotes the number of scale level for each octave. The Value must be an integer scalar greater than or equal to 3. +// ROI : (Optional) Region Of Interest. This is taken as a vector [u v width height]. When specified, the function detects the key points within region of area width*height with u and v being the top left corner coordinates. +// +// Description +// This function return the SURF(Speeded Up Robust Features) Interest Points for a 2D Grayscale image. It is scale- and rotation- invariant point detector and descriptor and its application include Camera Calibration, 3D Reconstruction, Object Recognition to name a few. +// +// Examples +//stacksize("max"); +// img_1 = imread("images/table.jpg", 0); +// img_2 = imread("images/table1.jpg", 0); +// lis1 = detectSURFFeatures(img_1); +// lis2 = detectSURFFeatures(img_2); +// dimage = drawKeypoints(img_2, lis2.KeyPoints); +// features_1 = extractFeatures(img_1, lis1.KeyPoints, "SURFPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale, "SignOfLaplacian", lis1.SignOfLaplacian); +// features_2 = extractFeatures(img_2, lis2.KeyPoints, "SURFPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale, "SignOfLaplacian", lis2.SignOfLaplacian); +// [matches, distance] = matchFeatures(features_1.Features, features_2.Features, "Method", "Approximate"); +// matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance); +// +// See also +// imread +// drawMatch +// drawKeypoints +// matchFeatures +// extractFeatures +// +// Authors +// Shashank Shekhar +// Siddhant Narang + + image_list = mattolist(image); + [ lhs, rhs ] = argn(0) + if rhs > 9 then + error(msprintf("Too many input arguments")) + end + if lhs > 1 then + error(msprintf("Not enough input arguments")) + end + select rhs + case 1 then + [a b c d e f] = ocv_detectSURFFeatures(image_list) + case 3 then + [a b c d e f] = ocv_detectSURFFeatures(image_list, varargin(1), varargin(2)) + case 5 then + [a b c d e f] = ocv_detectSURFFeatures(image_list, varargin(1), varargin(2), varargin(3), varargin(4)) + case 7 then + [a b c d e f] = ocv_detectSURFFeatures(image_list, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6)) + case 9 then + [a b c d e f] = ocv_detectSURFFeatures(image_list, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8)) + end + varargout(1) = struct('KeyPoints', a, 'Orientation', b, 'Metric', c ,'SignOfLaplacian', d,'Scale', e, 'Count', f ); +endfunction diff --git a/macros/disparity.bin b/macros/disparity.bin new file mode 100644 index 0000000000000000000000000000000000000000..fd1000033f8d491a5c414e8003f1add8b19ea9c9 GIT binary patch literal 15176 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 +// uniquenessRatio: Margin in percentage by which the best (minimum) computed cost function value should +// “win†the second best value to consider the found match correct. Normally, a value within the 5-15 +// range is good enough. +// textureThreshold: This controls the detailing in the disparity map. +// disp12MaxDiff: Maximum allowed difference (in integer pixel units) in the left-right disparity check. +// Returns: disparity map +// +// Description +// Validates disparity using the left-right check. The matrix "cost" should be computed by the +// stereo correspondence algorithm. +// +// Examples +// stacksize("max"); +// img_1 = imread("images/left1.jpg", 0); +// img_2 = imread("images/right1.jpg", 0); +// w1 = genCheckerboardPoints([10, 7], 8); +// ip1 = detectCheckerboardCorner(img_1, [7, 10]); +// ip2 = detectCheckerboardCorner(img_2, [7, 10]); +// ip1l = list(ip1); +// ip2l = list(ip2); +// op = stereoCalibrateAndRect(w1, ip1l, ip2l, size(img_1)); +// [map map1] = disparity(img_1, img_2); +// img = reconstructScene(op.DepthMap, map1, 1); +// +// See also +// imread +// genCheckerboardPoints +// detectCheckerboardCorne +// stereoCalibrateAndRect +// reconstructScene +// +// Authors +// Siddhant Narang + + img_list1 = mattolist(img1); + img_list2 = mattolist(img2); + + [lhs rhs] = argn(0); + + if rhs > 14 then + error(msprintf("Too many input arguments")); + end + if rhs < 2 then + error(msprintf("Not enough input arguments")); + end + if lhs > 2 then + error(msprintf("Too many output arguments")); + end + + if rhs == 2 then + [tmap, tmap1] = raw_disparity(img_list1, img_list2); + end + if rhs == 4 then + [tmap, tmap1] = raw_disparity(img_list1, img_list2, varargin(1), varargin(2)); + end + if rhs == 6 then + [tmap, tmap1] = raw_disparity(img_list1, img_list2, varargin(1), varargin(2), varargin(3), varargin(4)); + end + if rhs == 8 then + [tmap, tmap1] = raw_disparity(img_list1, img_list2, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6)); + end + if rhs == 10 then + [tmap, tmap1] = raw_disparity(img_list1, img_list2, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8)); + end + if rhs == 12 then + [tmap, tmap1] = raw_disparity(img_list1, img_list2, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8), varargin(9), varargin(10)); + end + if rhs == 14 then + [tmap, tmap1] = raw_disparity(img_list1, img_list2, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5), varargin(6), varargin(7), varargin(8), varargin(9), varargin(10), varargin(11), varargin(12)); + end + + channel = size(tmap); + + for i = 1 : channel + map(:, :, i) = tmap(i); + end + + channel = size(tmap1); + + for i = 1 : channel + map1(:, :, i) = tmap1(i); + end +endfunction \ No newline at end of file diff --git a/macros/filter.bin b/macros/filter.bin new file mode 100644 index 0000000000000000000000000000000000000000..20e97355dfd5a2a952238402ccfddab83a65f9bf GIT binary patch literal 6528 zcmd7X+io015C-5RoDvgn;w3(@-ryt_gv1yKATDAFZg>Z-kRUI?D+2GpSwhMM0s>qi zLVeEstM+(?tPzM$vpU(HuN~7onp~O8HYe-%FU)7tYwhyN=Eb$G+1@do^-h1iwKZOytj|~a z%9`&Ns7rVk1dghzx?uiU+ZGMSaP+**!sn8oY;poXHQZ` zV%+KUY^})yfAGHA>BZeHk;ghN6RYLq?b6GmSH$2GKC(8($NjEe_P7%NT1os4YOMdp z=GJbN+%8G&HC&9JuQ6;tba~`}-M+%w)~yE;1Ha*JSswN~pC2n%-zTy9{nYlu3 z$Hacn?LVxr<4Z0zWu87C%Q==K9P1Ntof901&j*+0`bCc25_-AuYRw!D{hYaeU=K49 zTP$&6BbPXI>1(zJC3j2sWUp{&exroHzT-z1UJh%_PwwFJjJ|K*kIzmm&f_;FdjEXM zw>730`;C%i;>30g%b0$d*nN!7gF6{c_*(o~bB8?1H9S?g&z1cAgyY2X)Bh1pd)M#D zWqLmM*C*v~k57B==AQYkxNpyJ?k#6<)?vHW<=Cw!Tll<(@-EB!AnzIXi1X@r|qFSy*<=GO8)3HSWs>q(D8{AS$t{#bvt{bK*j^|pM$lwMEoiIsh1FCUxa&)Kq1 zdZ>>_f3^En)5UKVeZs!|jX;-}`c)pi1A`p!c=vu(!nc3!t*a+})A#3t=b^Kd+S7Nj zg$EySh-c2mQ*W`$nUoh#S+_Q}AJ)QSa`87FJDb+>d+ngcxew&SUG@lH*35%A&FT6J2U+@mQA&wqS0tunmX7ZH{LW-eDAn4g6x{ ztjOEPF~nh%r{)a4i}s-XDvLpnA11$g_*y&?pAs>^kcs{b0*l3^n!lK z9^xce+jDB2Prr6pvtQ!yO&`OQd&s$HbF_6h`_{4_ZSQBV z>Xq;Tm)g=d;=q!1J(<32_Yep2+VAv?F`c|aJSHYP`^Q$y0+2REsu=qDIyWn(QZk4dR(>-6QCwa4kA56IMUjMw#bUhXr_=)#UPdD}( z$X=&*_{IOMVvfaz?=-RP4=#605*x-bJmEu*mJ{>v@_LQM5Knyg<46BmNuP&$1M^Wv?&P7zTaeH#ctOw&z2=QR)-Eztle1OMW>E;_z2{a_!bw zEYgLEIEU8QW?yQ0;v0#x)5mhI(=Cf7 zHLCC5!l7RH)jq_Fb$29Q@q!Ea368>FxD5xbUY)l}ZkJ?lYPcAuC-SW=Smai--1;%T z&(*l)vcGq+E3<{q`OfF}+Na!IZJ)P&;|z!o4_jx_6Bhd4N*~@lTTa-hckCPOALU!i zM>ZQP^ZC~Lbf^EN_s_D?W6zZ2-{$7ob38Wj&$gdrYw4)w0UXEdS{!5Fja!>X-;nnT z^6`(zt CV_8U CV_16U/CV_16S CV_32F CV_64F +// kernelMatrix: The matrix which defines the kernel of the filter to be applied on the input image. +// anchor_x: X-coordinate of the anchor. +// anchor_y: Y-coordinate of the anchor. +// delta: Value added to the filtered results before storing them. +// +// Description +// The function applies an arbitrary linear filter to an image. In-place operation is supported. +// When the aperture is partially outside the image, the function interpolates outlier pixel values +// according to the specified border mode. +// The function does actually compute correlation, not the convolution: +// +// dst(x, y) = $$\sum_{0 < x' < kernel.cols}_{0 < y' < kernel.rows} kernel(x', y') * src(x + x' - anchor.y + y'- anchor.y) +// +// +// Examples +// img1 = imread("images/right1.jpg", 0); +// img2 = imread("images/left1.jpg", 0); +// image = imabsdiff(img1, img2); +// +// See also +// imread +// +// Authors +// Sukul Bagai + + input_image1 = mattolist(input_image); + a = raw_filter2D(input_image1, depth, kernel_matrix, anchor_x, anchor_y, delta); + dimension = size(a) + + for i = 1: dimension + out(:, :, i) = a(i); + end +endfunction diff --git a/macros/ftrans2.bin b/macros/ftrans2.bin new file mode 100644 index 0000000000000000000000000000000000000000..96fa9525d257e94103dd315604bb8211bda2272f GIT binary patch literal 4828 zcmcK8+iq256b0Z7o;TRino@MPP%Rh)EC!8U;=M26of>@yAI7IMp6(1D;+3(EZ?i^S zEV>FLvXhzrG!J8rIoH3sy1Bnv?(UtxIsLu9SS-#(wx$Qe`h3nV%$!|Yu9mAy+q=`_ z?_OLiHe+`!ayN1_!p~9UkK^NG>)$f|8u@8h)8CHlMD`;akyV85)yQ7N`EKM=#6BB3 zbl-~5GpBPg@=k;vfAp3SXMC}}60v_d;*6dc_UU~Xp(hW&&bKn>_s?Kw2Q!)C`!VNp z*zDKe8=3Q0zxRf<^V6{7^1aA~$VZXpcq{YUk^0T_WKNgfF9YWCA$M5DoR=SY%ZnZR zJH!01p=S2VsXlshShFYWV8P3@uEofv`0M|N_%FU^sTV)vTJjVTYS>jGdR$LeAHiaQ(JpoA7swvD8dfT)}lGvYcICX*gwm&)1H!t zIX~w7z{x-Sq?qO1xUjXB?Cdv(aZc6e<9X+#?^*|3!83P9G;g?yTdwU}x$#vV)S!Cf z=l`2w-*ZQw->DzZCEIdI2QKT@)Ol+HL%B6~)|$Yf4($19-R63Nz8pMfa^;6@*S#kW zvL`-2bc)5gSf-qb4GWQrIGwXAwsJhjCp$T|R@Fbq9zTsshYx$xdjrSnaw|f|9rbmD zP475dGzOnNYdm=E!J{trk0Q_V9F|XamG=xj>fd{ff4yQ4Mq_&w&uri%&fvtYoYkfN zVT6kuMOsh3ya&q}KE#~k&6&7(8P^>bt-F2e;>0IxZ0CB~Ic#+3%d2(yGV?JeKK!lG z+=|t{x^`dA_NKNt#+Q9O6=yjpR_|Ts_@N^wys;bK*Yaf}e^Q_Q`$BDDA?)R6?tQ`+ z8*6#Ma1arzT9V_2Fx5dwk1*ojmQ)Zyxol|GtWh_2n&Q zYrqdX`}M`14ZrXgi#;{3kH)he>vt_iIe8v`r!^)X%=_$%-x_!(;i#?=?&gT=qey$$ zy#3WWjr*K^IjN7iXOr&FiLbw5P>;_d#nRqrJnJbwG2lInlvno)X}`eC?p);7FuyyD z^k8s)n%)P4p68Ix`@>jYY{uL)b}^sk^Z$xHeh&x635Tx@7=KS*o(pxtg?pm4z*{-r z$XssnFy0%+k2A`%_s?|xNzUq{cSCDbAI|%nwqL}?C$7X)liQK{%JgLZYUVKc+gktj znd_Y}&g11l_xtGT2{jP2cQ60)r`I1G`B;1GTg|uIKk*~ymm)7j=n@!=-mj~zz3FG( zdYz-i&KYO06c1l>-;#d^17CD5FZcJa>}>DtPa>X%6K*(-xV=6TAV+H)u;A+3h*;*v zv+~RF+7>tear)r?yIJdpgUC3?ISk_*SIdLzo2Pt}KPgAGxN>#M%tNAbbduwvSQnq_ zaaa!r9sMEiCt-cGj~?7-Gxyy;hkecO8TmSI@4-E;>C@yJllAXL5|rbO$h7a~I2+ew zZ~Jg#(sJwNTwd)v7%y%ucXu~-9y155SYF8-zHtx9{VdxYuerICkuGlBN867@dbrU( uRJYF=$E*8bG~x4{{@%%I#&ixNcPsj^*y+5t-Zu}Q3x@6J- literal 0 HcmV?d00001 diff --git a/macros/ftrans2.sci b/macros/ftrans2.sci new file mode 100644 index 0000000..7fa2077 --- /dev/null +++ b/macros/ftrans2.sci @@ -0,0 +1,55 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Vinay +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function h = ftrans2(b, varargin) +// 2-D FIR filter using frequency transformation. +// +// Calling Sequence +// h = ftrans2(b, t); +// +// Parameters +// b: A bandpass filter +// t: Transformation matrix +// +// Description +// Produces the two-dimensional FIR filter h that corresponds to the one-dimensional FIR filter b +// using the transform t. +// (ftrans2 returns h as a computational molecule, which is the appropriate form to use with filter2.) +// b must be a one-dimensional, Type I (even symmetric, odd-length) filter such as can be returned by +// fir1, fir2, or firpm in the Signal Processing Toolbox software. The transform matrix t contains +// coefficients that define the frequency transformation to use. If t is m-by-n and b has length Q, +// then h is size ((m - 1) * (Q - 1) / 2 + 1)-by-((n - 1) * (Q - 1) / 2 + 1). +// +// Examples +// b = [1, 1, 1] +// h = ftrans2(b); +// +// Authors +// Vinay + + [lhs, rhs] = argn(0) + + _b = mattolist(b); + + select rhs + case 1 then + out = raw_ftrans2(_b) + + case 2 then + out = raw_ftrans2(_b, varargin(1)) + end + + channel = size(out) + + for i = 1: channel + h(:,:,i) = out(i) + end +endfunction diff --git a/macros/getParams.bin b/macros/getParams.bin new file mode 100644 index 0000000000000000000000000000000000000000..9048ddac2fa7db348de30af2f353b728db043a2a GIT binary patch literal 18584 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 Ne^c{< 1 + error(msprintf("Too many output arguments")); + elseif rhs < 2 + error(msprintf("Not enough input arguments")); + elseif rhs > 2 + error(msprintf("Too many input arguments")); + end + + select modelName +// case "SVM" then +// temp = raw_getParamsSVM(classifier_list); +// param = struct(); +// case "svm" then +// temp = raw_getParamsSVM(classifier_list); +// param = struct(); + +// case "SVMSGD" then +// temp = raw_getParamsSVMSGD(classifier_list, image); +// param = struct(); +// case "svmsgd" then +// temp = raw_getParamsSVMSGD(classifier_list, image); +// param = struct(); + + case "EM" then + temp = raw_getParamsEM(classifier_list); + param = struct("No. of Clusters", temp(1), "Means", temp(2), "Weights", temp(3)); + case "em" then + temp = raw_getParamsEM(classifier_list); + param = struct("No. of Clusters", temp(1), "Means", temp(2), "Weights", temp(3)); + + case "LR" then + temp = raw_getParamsLR(classifier_list); + param = struct("Iterations", temp(1), "Learning Rate", temp(2), "MiniBatchSize", temp(3), "Regularization", temp(4), "Train Method", temp(5), "Learnt Thetas", temp(6)); + case "lr" then + temp = raw_getParamsLR(classifier_list); + param = struct("Iterations", temp(1), "Learning Rate", temp(2), "MiniBatchSize", temp(3), "Regularization", temp(4), "Train Method", temp(5), "Learnt Thetas", temp(6)); + + case "KNN" then + temp = raw_getParamsKNN(classifier_list); + param = struct("Algorithm Type", temp(1), "No of Neighbours", temp(2), "Emax", temp(3)); + case "knn" then + temp = raw_getParamsKNN(classifier_list); + param = struct("Algorithm Type", temp(1), "No of Neighbours", temp(2), "Emax", temp(3)); + +// case "RT" then +// temp = raw_getParamsRT(classifier_list); +// param = struct("No. of Active Variables", temp(1), "CVfolds", temp(2), "maxCatgories", temp(3),"maxDepth", temp(4),"minSample", temp(5),"reg accuracy", temp(6),"isPruned", temp(7),"UseSurrogates", temp(8),"UseSE1Rule", temp(9)); +// case "rt" then +// temp = raw_getParamsRT(classifier_list); +// param = struct("No. of Active Variables", temp(1), "CVfolds", temp(2), "maxCax xtgories", temp(3),"maxDepth", temp(4),"minSample", temp(5),"reg accuracy", temp(6),"isPruned", temp(7),"UseSurrogates", temp(8),"UseSE1Rule", temp(9)); + +// case "ANN" then +// temp = raw_getParamsANN(classifier_list); +// param = struct(); +// case "ann" then +// temp = raw_getParamsANN(classifier_list); + +// case "DTree" then +// temp = raw_getParamsDTree(classifier_list); +// case "dtree" then +// temp = raw_getParamsDTree(classifier_list); +// param = struct(); + +// case "Prob" then +// temp = raw_getParamsNB(classifier_list,image_list); +// param = struct("Active Variables", temp(1)); +// case "prob" then +// temp = raw_getParamsNB(classifier_list,image_list); +// param = struct("Active Variables", temp(1)); + + else + mprintf("\nThe given modelName-%s is invalid\n", modelName); + end +endfunction diff --git a/macros/graydiffweight.bin b/macros/graydiffweight.bin new file mode 100644 index 0000000000000000000000000000000000000000..6fa0b875ff9e29a99960820d152c4fa0396d2caa GIT binary patch literal 5680 zcmciG%Whmn5C-6J5Vrx_lL@|n?c^ju!kDZA5=*u$cmTEt2}Obh@5xJm0A+_FKv_kY z`po%9oo3EB77in|x=(do{`#xBk9`(L^LyLN-Q8hlxwv_9y83O;X0xpthqoKyYWMW? zM(r*4=Zl?2mgUjT?xNh@neRpN&;0$Xv)OLh-Kp_Kjnf)`o}Zu3Yu>Bzc8%NPn(U;; zP7Qj)xL(%0sByD~{o@+;`8}+0G(OYYufY%f_<6V1_U?`{apU8yTGRJT9|wH%doZr~ z5`*5o8g$|I%va)w!6rFa(c`LHQ8)JD!IoN(!xSH>?PWM0lnwuKV566C$uGIw``p^PeLm{F zXr77pYsG^fUUTf*{t&;fk$i9--q;2w+wfsc7yh<4ozvK+XHqNr^5;_ww(yzBa(39$ z71!F_<06++%T+zD>cc;~KSmy6&qh2r;I__LO>Ms`8QY)BR!`Ci9y;<0kG&6eV)Lo4 zZN23fKkWDpzx2du?-;&@8g%TnXT%;X?fpd$FXHEnPx<9f4*c|3uF?~I@A9YD)x|m- zCeNW{Q~9(!_n746tm043?yH<5{!+WIYAx=%J|t&L*Se3<-%tEbof}x}^D&HT&r_U+ zZ~D=b3prWt_D%SvYKa?hbAI}~l7qZA<#d(0i?=D4)Z?4d!?j%D7hiwMn~s?**zp=J z`aJkxD_`|D%Z>jw$4&2n^rib=Z2sOEeel=&`oH)RcdBQ@1ANwWVaG>{7r)`b9_*=8 zY}tupudmUj-m|ARw?+_`OS#Bcq=%U|*iA8hW|fRBt0-PGvY zQ69`{o%@eI`E}mKZ7;wg#?<}O<{NzJG5n?8&TM#0t#Xd>)Yhi$m!3m-^di4-_U{5% zr_NHFSMT>_+<%V>3p`hOx5y7Rc0II(~fa;NUN|c^~SHoR9PaKM!k|v!6cZ7su-NL&f5AT`V|n z)exUwx@R?iR3jLMT8nX=|C7YWVe7$bu_e<{Ja<;N%mRa@IG|f4$b5 zxQbq>t!&;HZJrh{c~?5i{NlQ;m3xMN|1Z+99~=4FgVi34W-$$Tsi^=_Jz*= z{N&_tZ+YB*A^WRza95wZX0MF8o}DGLnqK(ddj9*Er`lSNWsPo&W$K&Tb2{_keIMrf z?|tyfIe202@y`DZ^+K`^@04zf<#>62-KWFT%eecx0&Xw&cMgu1hX);|7KaPXi8T^xK`W7);YWBNtUe954GY@GLXGAdKPYU|>+>c0f(=9a@Lo-gB2 U|4n_@ReO2i?t^jd8Sm!50l#={`Tzg` literal 0 HcmV?d00001 diff --git a/macros/graydiffweight.sci b/macros/graydiffweight.sci new file mode 100644 index 0000000..3c7b744 --- /dev/null +++ b/macros/graydiffweight.sci @@ -0,0 +1,51 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Yash S. Bhalgat +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function [out] = graydiffweight(image, refgrayval) +// Calculate weights for image pixels based on grayscale intensity difference. +// +// Calling Sequence +// W = graydiffweight(srcImage, refGrayVal) +// +// Parameters +// srcImage: Input image. +// refGrayVal: Reference grayscale intensity value, specified as a scalar. +// +// Description +// This function computes the pixel weight for each pixel in the grayscale image I. The weight is the absolute +// value of the difference between the intensity of the pixel and the reference grayscale intensity +// specified by the scalar refGrayVal. Pick a reference grayscale intensity value that is representative +// of the object you want to segment. The weights are returned in the array W, which is the same size as +// input image I. The weight of a pixel is inversely related to the absolute value of the grayscale intensity +// difference at the pixel location. If the difference is small (intensity value close to refGrayVal), the +// weight value is large. If the difference is large (intensity value very different from refGrayVal), the +// weight value is small. +// +// Examples +// image = imread("images/lena.jpg"); +// W = graydiffweight(image, 120); +// +// See also +// imread +// +// Authors +// Dhruti Shah + + image1 = mattolist(image); + + a = raw_graydiffweight(image1, refgrayval); + + dimension = size(a) + + for i = 1:dimension + out(:,:,i)=a(i); + end +endfunction; diff --git a/macros/imabsdiff.bin b/macros/imabsdiff.bin new file mode 100644 index 0000000000000000000000000000000000000000..19d0e193dea352ef03da179c8c9bafa1f9ee7adc GIT binary patch literal 6944 zcmdtn-HsGh5C`x9qv8O|?wH*HXIF=hm~|yYQDcl6Oi0uhFnaG5S3HH!;S2aCzJoWK z7!zagBU~A=eoOy{L({#iD*<$pN}sM%pZ}^l-7_=Wnx5P~Jv(z|_x{i6$z*b@Xtp(7 zU%P*6|L*wy-ukhDt=-wy`tc$DH_uHbXG-stqU%MwMStA6b7xxD&7xC9FL!Iaouaj( z?IN=7H;VAwpX=6(x?btl?AYJxuJgLmBhTi^BKFP}k>xLb$jEzEBu>N@`>t$>(V8q< z*7TR%I&${I=gU32;u6Pt5m~XkRTNxmxmwGWUW<{K*%1pH_J1f0*?Or+K8Yc*#<6ztF0Ykr@)3t#dAp~NuTS=h5<@LlYqt6QvFiai!zQ&$UGU))8|vQX5&xGv z{;y?EY|&#U@^GV{x`*GdOIs7TwsOfU{(?We)tV1@Mdv6!OMR6uyKMd5)fpCe@{^~0 z(goHrC)#h^vFDHcCVBS`P&sk`sqo`pIBjrtS=P7 zQf$kj-~$spn1n|b&plmdm^tgqxo4A1`ZzrGxmXlEGHtK$$4|~RxTTKfjU9DhpDf-l zh3Q^h?OpAz@lQsLldpTe>AhD(&Yn7&-@d(%i}`c$ZxY$ts0000FEys4hW1iFHiPpg zwWjNyEWi2=&$%>~4>|JW($k4U-dX2dlymTtt*^1X4mwNO7>bdP^f+H+Vuw!F_~Jv!$$pEwcN(=3D?M`TCy$&f zZxjzjzr~gfdM(dd{ov@_Y2VxHc6I*0P-`}StDaCJF~f?@)Icnm?PaYK1G#+1z`NSp zOV6<>5AQ|amLK+p{D|?zBEH!r8=UKQ|2^vUx+a$NRQi&Rd3_YI94kBjG#>B1EjDr# zliCc$WIylynJ>8^ShabHCs?$6`R*09xYX?mqtrLw#S#nO>Z=x+6Y)P^)aKByVX!Z; zm5&phj_0$pBhNB+>9_p@5B9|)4|${ZeJ0PkpGroYY`E%a`oT#2_0!4f1B>ZmeLnOX z%U@*+hR+r~Q$!Z=>BX=+UTi3+)L6LaG`e_k6 z7mE0hFA_gYeRqX15~O(yPIU0>r6%SoYkR?#4}AJLN8rMT8F;e@_Tt*wKDU_7cltkz z?GE892Rdtu#o5IGvST`Y(^Zq{e7q(w$>+OjCV5;cN`IWF^}H|=gHLL5P@T!$tI6b} zeobz4cDy(DYw}_74pS3-56`32BWFNreZK7EJV*`Imi^p2W7O3gr62bO@xcEZaFcVMk)AW=pgoUw*0#>|;NHI-ig!%5jb(dw zap-T9(dS8G`LZ0I+L+GgYnu;*)5hX`MvvV)({Ejq<3YOgVQ{&KEDYW)nmyp@E+aM4 vyI)YK4;}M8#3M3htG4z(t2r3)* 1 + error(msprintf("Too many output arguments.\n")); + end + + if rhs > 2 + error(msprintf("Too many input arguments, maximum number of arguments is 2.\n")); + elseif rhs < 2 + error(msprintf("The function needs atleast 2 arguments.\n")); + end + + img_list1 = mattolist(img1); + img_list2 = mattolist(img2); + + temp = raw_imabsdiff(img_list1, img_list2); + + channel = size(temp) + + for i = 1: channel + image(:, :, i) = temp(i) + end +endfunction \ No newline at end of file diff --git a/macros/imboxfilt3.bin b/macros/imboxfilt3.bin new file mode 100644 index 0000000000000000000000000000000000000000..9b9b5bfc8d107feeeb464bd1aef2cf1b17d1abb2 GIT binary patch literal 7052 zcmd7X*=`(F5C-50VKL6?NxXpVWK05t5V05p0wN{cfP{DeZc#3H65b360q=kiAR!?X zBDO0;sBhB$aNM4@$0(4DRO;$Jwfyy0oipS1cb(XooD+c|QfInY z{C+E}aPcGkyx-TlSWlP0Mu+QUrziHL?!|+vtsMqFxW8So)SQ}jOXnk}=WR{>dXCrn z3njP_Q~oyI)w&OscS?VdSYGe)_iIQ`z9}BmjFa^BFrS~hKJdez{_$<=uG<+0xWvH^ z<)^V1b)Y|X891p6-NkFBxMv&^*o?Aw`S zv*?+7zHIedU1HMBfxe}lQfK;7>Eb(&*vShcKj-%KlKABuXHR}AE?sxK`{(OQ@Fk9T zcr_dD*|s*BTl-br@P1h_Jr4)4q(}09QR~6;Ox*`d|9Y%jd%L?Hb`P^Xk{+cuhxzj( z!E~wgK9=_WFdY5${|i^!mzAnv9v5vL|5oqwHF*g5O7G6i!P4?#Pnc2M9A!?Q?Bd#E zuaq3N&&p&rPpw`*H4(D-u|?+O<&u(hxT&zy`B#3WoImZ z`w320dsv<}2mJOqTR!-;7ueFBYkZv(_Lx|{&n6|F=}FF3v0pB69r6o*eB0kD!Ipim zHnws*%YsjSxcnY>R+0ElN>6W+Zi5%&bdNNn+#OjM2xM=sqP|x){@$T22__)LLZDECB5$?>2I?OB{cDj4m)Q{_Y z2jYcoc%kRJSlxWw^RebWy>pKX_xfml*orM4tY(j$zs<~+eAf6RkM-CG7eBUql3Ol) zN}SAUd=guKgMp8GIpl;xU8$R%IGF);z=JpI@~5w#lrEOqtg*}f3g2RjB_Gj`{MLp= z-Kj+^`GYZh_W5EXr*(PxW$&mpwP!u?c+^(=i!{dhBTxRK+f60!6l z-y!@a-LvojuV-xAznSWG#$V2_Uy2X=K(5r4eEh>VU9O=S+wHBZ0cLUa#!P)xxe^;z zYw(>b!JYoIxmwp3OOpG!(&Y{pxD-D*#Ls&QG27Yim zv&7y!#jezuzEnD&KWauZ7x^CG-|iPP!uIR371LV2e_+%b>)vB}9-RE>W)21dzu(UJ z_{~-?O831d_1^Taig&Emac7>{67gJbm29qT^*(g2wFc|;&Sp`pd*|rR4fPGZb05M! z<@bPkt!MV&?)UWQ^)B6fzv8I(MoIR=BE7jE_3n)^y7^ylhNp1$Xz54gtX!s_56|D@ z>D{_(c^cxpo#CzVrPK2cg`qiU_vy)%<@NQ`tNYx6%9-K3)x&nr;qoBgTAuRaJBlq{ z%>H;^rh5-kvz~p#p+0<^=kuO18H!a)(+|Ic>{ +// K = $$\alpha $$\begin{bmatrix} +// 1 & 1 & 1 & \dots & 1 & 1 \\ +// 1 & 1 & 1 & \dots & 1 & 1 \\ +// $$\hdots \\ +// 1 & 1 & 1 & \dots & 1 & 1 +// $$\end{bmatrix} +// +// +// +// where +// +// +// $$\alpha = \begin{cases} $$\frac{1}{ksize.width * ksize.height} & \hspace{2mm} when\hspace{2mm}normalize = true \\ 1 & {otherwise} +// \end{cases}$ +// +// +// +// Unnormalized box filter is useful for computing various integral characteristics over each pixel +// neighborhood, such as covariance matrices of image derivatives (used in dense optical flow algorithms, +// and so on). If you need to compute pixel sums over variable-size windows. +// +// Examples +// image = imread("images/lena.jpg"); +// blurredImage = imboxfilt3(input_img); +// +// Examples +// image = imread("images/blob.jpg"); +// blurredImage = imboxfilt3(input_img, 5, 5); +// +// See also +// imread +// +// Authors +// Yash S. Bhalgat + + [lhs, rhs] = argn(0) + + srcMat = mattolist(srcImg) + + select rhs + case 1 then + out = raw_imboxfilt3(srcMat) + + case 2 then + out = raw_imboxfilt3(srcMat, varargin(1)) + + case 3 then + out = raw_imboxfilt3(srcMat, varargin(1), varargin(2)) + end + channel = size(out) + + for i = 1: channel + dstMat(:,:,i) = out(i) + end + +endfunction diff --git a/macros/imcontrast.bin b/macros/imcontrast.bin new file mode 100644 index 0000000000000000000000000000000000000000..0e5d4314492de04e80af8185d0fcb54753ee0af6 GIT binary patch literal 3180 zcmb`K-EPxB5QSa->xR&}#7#&Hp{;}|y(&mta6un~dmfj^0145H3h^f)A;S4AA8WJS zEkz>I$m^LiGiPRY-ECEmrhCo2Tr}<4?`}~P8xmX3HrD~yWn0Wg=k@lQTlZ2OVE!b#MqO7pG&~l z|GC!ArRA{R(Hj46$_swd3wek|4(uOfC)WcByjWu=FKfp>)*3uE^h?R1B**(iHt@Fp zt&XR{QWN!oJr^(f0nZl_Vo}FTLM_zCyKP%q!;2oFKa!Zcmctqxu|D>FaX-mrf1c>! z;~3P9Uy397JTvzR{`kO`zQQZ)N9YsI@Kuk)PM!F>R>y`reSIu}D>!0P1G#u79~k$G zwd(?#ng{y~UupzH407Yg`?6mXi+ZuSE_~?~IPmZ%2N-nlh&hLKpZ2(Tj;`6~hciTc zp62K?hMqIWllkpSa=Bw)bA>l^^E{0U``|qjLnKZJX@bP`W^N{ufx8B7k*zg zbLs+%4i28LXH9-MdC#6|jqiK;!XLb63x@pQi5JJfFT{hzH`n`r=^t2gC9nHQ{M3Fz z7xo`ssc)q@V)ty^3(g8Pr7-B@9Jx7x_58xKX+3$pH{-pWoAIW6@c*JY!ISvZ=dIWPhch<#?MleY{s(iU=QD|OKhc`l_~5&g{O`X5 z<_#yGLx1Ntq=Tpa#17wn)-g}12F~uU|JK3V^YZu3XP3F(?(OCg_s_i$Y{+q^_u)Im z9`k-8F8<8Se(Znp!w2kr2~W77|1Q02=Lrw{(hvKhXPyY>11xj#8T!=6@%h4rKd}(< z(YxHe=a>9t?l5)PG}B2HU#r^R!Z4GY67EpM;~fq>-%1q!tX#itb+;**Qe2YQkW219 z7GiRDvk)^cmxop2zDP~f;+k$~9oN*1>sjJT$Y?Iql*5Kx7S+Kx74J&@JxF=B0~hu) zbH4?-?)Uk1H}^~YfKmUk#4~-Vb(K!ldOxwJ-r%4gJ!5aCbU<>kWa@t2pE+FEzg&;6 U(!b08C!j8Rw=eOzVNbLE14B#xdH?_b literal 0 HcmV?d00001 diff --git a/macros/imcontrast.sci b/macros/imcontrast.sci new file mode 100644 index 0000000..06c36aa --- /dev/null +++ b/macros/imcontrast.sci @@ -0,0 +1,46 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Sukul Bagai & Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function contrastMat = imcontrast(srcImg, alpha, beta) +// Adjusts image contrast. +// +// Calling Sequence +// new_image = imcontrast(srcImg, aplha, beta) +// +// Parameters +// srcImage: Input image. +// alpha: Pixel multiplier controls the weight of each pixel. +// beta: Added to every pixel to change the range of pixel values. +// +// Description +// This function is used to change the contrast of the image using +// using the values alpha and beta. +// +// Examples +// image = imread("images/lena.jpg"); +// new_image = imcontrast(image, 1.2, 2); +// +// See also +// imread +// +// Authors +// Sukul Bagai +// Siddhant Narang + + srcMat = mattolist(srcImg) + + temp = raw_imcontrast(srcMat, alpha, beta) + + sz = size(temp) + for i = 1: sz + contrastMat(:, :, i) = temp(i) + end +endfunction diff --git a/macros/imcrop.bin b/macros/imcrop.bin new file mode 100644 index 0000000000000000000000000000000000000000..444c08b28f7f9f90d94fba96714aeb9682ac9cdd GIT binary patch literal 4272 zcmd^?&2JMi5XDmvUuhDOg`_D-%BJ)XO6j2>!HqKlapnwvE`J6{NE|A}*9kSeU%M|F zdDo4qa)L-B+v7Lm@td*ZEk>QmczaR%bz800hJ@MUVSkzeu4!&M=^T&x>C9p=?~KQj zx_Ysj(U(PcHfX>PdPRRQt52L!}3Wxr8}*LBM)$SN+^vsX5lA4$PtL%qR1##Td-K#CuhD z)!$T~SUxL0cq9f|Vuc56Y0xkN(&rI&9#9zWun)*cU#m2eZyEzTg%g*kNy8 zV?5EPb3yC4oO^KSS@%5O#D;%x

  • %g&lM32VoB0VoqLajBQhm=5hk|Q1ZXzB=YsT z;;U3kj^eq^@#P%RQg_^Ma9&DMALwJfU=!>2yjqBM>*~zwTzyn?XgcD2bX8RuP@fc4~`rhNWhYVXOg0}+cSmF1!v=`3iSG}`FhC0c literal 0 HcmV?d00001 diff --git a/macros/imcrop.sci b/macros/imcrop.sci new file mode 100644 index 0000000..a84c0bd --- /dev/null +++ b/macros/imcrop.sci @@ -0,0 +1,46 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Sukul Bagai +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function cropImgs = imcrop(srcImg, xcoor, ycoor, width, height) +// Crops the image. +// +// Calling Sequence +// new_image = imcrop(srcImg, xcoor, ycoor, width, height) +// +// Parameters +// srcImage: Input image. +// xcoor: The x-coordinate of the starting point of the region of interest, ie region to be cropped. +// ycoor: The y-coordinate of the starting point of the region of interest. +// width: The total width of the region of interest wrt to the starting point. +// height: The total height of the region of interest wrt to the starting point. +// +// Description +// This function can be used to crop the image to a given region of interest. +// +// Examples +// image = imread("images/lena.jpg"); +// new_image = imcrop(image, 10, 10, 100, 100); +// +// See also +// imread +// +// Authors +// Sukul Bagai + + srcMat = mattolist(srcImg) + cropImg = raw_imcrop(srcMat, xcoor, ycoor, width, height) + channel = size(cropImg) // for converting to hyper matrix + + for i = 1: channel + cropImgs(:, :, i) = (cropImg(i)) + end + cropImgs = double(cropImgs) +endfunction diff --git a/macros/imextendedmax.bin b/macros/imextendedmax.bin new file mode 100644 index 0000000000000000000000000000000000000000..785a3e5f99ba404bf4defed51d2a42e596fef422 GIT binary patch literal 3548 zcmb`~U2mI35Cvct#Ft4-YZNCCyEtuyN~v;DkhtW6KY@f0Li}9*1PBlk7j4DY6(XD` z^>JQY+f=2NM!WCsnKNf*XVdL;HaS~Njt?h?v+>#8tKZ>hG`bc$oG*SEFRs=*dntSK z(}Rbz>s`4TA07RRYQ6Er%cId-@p~_J8oL|&_2S~!d6`GeJ3b@Sbq?=aU7f|ZXv#CjOc?$d_rmYV>7@p5(E8J#2<+XkuOzZHxJ<+vvqxBfFS7`ei!18z07jt8&U$TWW!$ z{(NxDr*W#Iz3^4``2G-I{SV)~V4M}rV&LEpV{MqTJyjf*p2OFxy%*KbdPS_CRz2~& zy4!m_KlN(v?dA3cOz%f=YNG$@1H(@Z+9Si-z^bnvfpw3HTV`&r^^+fc#>Q*!!Psjo z7{2|k4&3Fum3hzO%gp(>mp$YDt#2Qdzd0|1)l2fhD+UhZu;+V6$_wM~Fu&e6oc3Yq zg4tJ_a;XfzNcxbY2Y(6k_ZsTo#zMg%*O^w#7x3%q?rZu8d{%YxLi+?S1`8Dol z?TQOz?L!BjKT|LL-TRA||M2Yk9{E04F70X<(=u4cR9Usu3nlq z^`6|^%<{?edz;=}*rAsB^!8-^fFDerrFI85#>dB#qk-4cTJ)Fu@hX9rzsH}-ai1@k z8r+Y;s=+6*=~I!OEVN(r%;y~P zUK1fl556I)i@a_dbW;)b@W`7YWD6o}o`@V*Y{4&z$L6~*pid0QzOiThgVynLTeK{K zCmy)q?R!H!`rD!7KF8I-I*Lj-! zU*!2$ofTDepzfYwdd597h>RM8fgXVYV%zo}Jh?@Uvd7>=0TzpjhYFU~J&OpU(j{BVDfft5Nj zYxEGFT2p7AeJ{mh>$3+P=Yx*>g1@p4?2wZyKDp-%1_Qj$7VbTx_y7az<#PfV>*tvt zeBlRMaBw9SF+>04g>PeXAHnVO9ox{Kb;6m$C$r;x@ax>eIw0qqMrQxvIVf?_gB#+B z{Z;+rEW`#|`WBwEj!j+BkHtW~Raz$x^2RT?d9HY?SoAp-3!Jw^#0NXN8@fIa8N)sC z#M%~Bon-T8MHtC3f+5VY>fL`>C;lBE)aj(F{Vej$f?9#sJ>_gK*GgY2 z`n7ti*BScKaoSV&Z8+!T;FbK4v;P;Ev!bsvm^0Xh<~W_pvdG63sU_3YV|ZU3@8iES z#wUKm`K7Ii;?~!lFHy0;waZMTqAB( sJnuoC?a(uww-;e8N2_?62)_R;zvN&zzvN(+^J7MM2KKyjJMg6Q;=E1%dRe^6*Pgu?H4kR7bmUaBngjEqMmbJ{@>%|zUk&J~ zr}X&I^QzBEr{wI_?7ZUJmw$T8IEl)Pe{;ZQx1CFUa8_~D#y_8R2dZ}ua>lkeqr=`A z9d*@g_kC2JrBByhO?4Ni*;gKaTQC1?iaWeI6XQ?b1O1*>%`u;GcPe{6KZUz1S;a8# zY|V>W#4FpXbzXn?*$J#AuUX+2C+_d-#46voB{T2m199DDIybZ43M%%q?7P0F`Q7K1 z|BB6TyW<2X?uEcA7jeI| zyz7@7^-xTpb3CZW|L>q#+t~Lfn}Z+mb2##2!O?&&;L-XrXwHr2nM&i(`T;VzsQE== z@a2)O{XstIb@G2Kw}$~cxjqm0G5b}on&t05)(qiP4U*JLbK?w$Z1GNpH!{AeC(d!I zCv=_HywT-XujDftZ#Bb>$!edVdA!P<%}Ud3HhqHyy2LB_kDeKqsDi;&SdQ#lrZPEAb_i)9K&S)^1Y_1Q-lV0x^ z%}Vv%9UP7ZYx}>jw^7~8W4>NDk44|yU7cnyy*8ZlT`yO))ceAn>&~cLm(3{N=vjXP D?oa@B literal 0 HcmV?d00001 diff --git a/macros/imwrite.sci b/macros/imwrite.sci new file mode 100644 index 0000000..fa1edb3 --- /dev/null +++ b/macros/imwrite.sci @@ -0,0 +1,43 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Sukul Bagai +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function imwrite(img, pstData) +// Writes to a specified location. +// +// Calling Sequence +// new_image = imwrite(srcImg, location) +// +// Parameters +// srcImg: input image. +// location: The relative path of where you want to write the image. +// +// Description +// This function is used write the image to a specified path +// +// Examples +// image = imread("images/lena.jpg"); +// imwrite(image, "./imageName.jpg"); // imageName -> name of the image +// +// See also +// imread +// +// Authors +// Sukul Bagai + + [lhs rhs] = argn(0) + if rhs < 2 + error(msprintf("Not enough input arguments")); + elseif rhs > 2 + error(msprintf("Too many input arguments")); + end + image = mattolist(img) + raw_imwrite(image, pstData) +endfunction diff --git a/macros/integralFilter.bin b/macros/integralFilter.bin new file mode 100644 index 0000000000000000000000000000000000000000..ddbe4a6fcbf10a78e7dc857b04834dae3aafd5b7 GIT binary patch literal 5512 zcmds*%W4!s6ox0>o#6DJojUKSEXK?Mab8&`r0T?m42=E`^RB?JQ^h!}4x zG5%kuzo$~^O4@9M3>>=p+|OU9PEU6+7XQ^*h~awWdVFg;B+e7e^#3 z2BTuO-R;DD*3;9&#gxbWxKng{qxl`8nS$8sz2(Hy?W3*MjN+UZjYO-WFPod2gK*!` zwJRz`ZBbujo!P)cjvoB!z?%;|YJ|TbpM|d269;{KUKcsOmesnaHFiH_=eXG7gWQOT zd|h&Uof9pHSR+3b*7kiz_vmw9mj|-7pyL?MGp#>Y%cbDk*x@I|=!SS;1Pw)tB6wpF zxnn~->L)%pBG2Vb{n#vvu)i$2B68hYR%>EX=f{Al_mmv5b-nP3YadUw#xBOCuC}W| zZ@>LRox~Z7sGk_@qkDlhy#T)GQ4e{u221X#0UhUx+&xG=)P^oKV~0Ne?FSwD$UTG{ zU)VUVeH*W|Kd3+5_qfkr%9ryeXZL~e`zd>P&V&3N(|sS?xqfob)r5U|_H2i*Ga@hm zW9s@Jd*K>$xPBHcb#Es9K_u+krm&!RC#x94s_owL| z9%Q_q1-!tjt`E~0X8cqBUYO_nA7pF=X*H)gyI}M^^eue~kMjcVb0W?bYtJ(<In%lMwwHfD7d-3jFE>kwU6&KN#Ir)T z6}~66#_pRi;<-&sY64g05VHh(V+zKO!*wmX$Buo$20!G@|A%+-ZC~JljC`2S!~q|4 zF6(+lZ9;bN9ebtXXE7*_=1fKL1eL*gq5BIO- z59X=&3O-naExPd86Z`S`A)nd#xl-@tGby%pxRN_Iow6K8ul|*3&W3o{GUMBW{9b^? ze(}94TjTpM_*v35#TN|eRjv?NxnIE;n}dj}%G&z96~JJ;B65Gf31Z1G5(K&p9{LC_|vCN@OQ7%I|rq=Rm#@ym4+WUUlf6lF`|Eq!Q4XKSF+#QBZ;?q ze6~Fr4g1A>`lYSO`J4Eks?IG7eAnl(T`$ff_uVem$$i6%b#mYHVx6)*UeTP|@$HeC z`L;+8GC#R8YqrgtZIw=Lq*m3;{C&;_=!ZSes5)NU_sHXW%-a+9+g45XCim@>y4)u` H&shHjC_|}b literal 0 HcmV?d00001 diff --git a/macros/integralFilter.sci b/macros/integralFilter.sci new file mode 100644 index 0000000..8b78b3f --- /dev/null +++ b/macros/integralFilter.sci @@ -0,0 +1,55 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Tanmay Chaudhari +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function out = integralFilter(intimage, bbox, weights, filterSize) +// Integral Image based Filter. +// +// Calling Sequence +// filter = integralFilter(intimage,bbox,weights,filterSize); +// +// Parameters +// intimage: Integral Image, which can be obtained from the function integralImage. +// bbox: Bounding box of the filter object, which can be obtained from integralKernel function. +// weight: Weights of the bounding box, which can be obtained from integralKernel function. +// filterSize: Size of the filter, which can be obtained from integralKernel function. +// +// Description +// This function filters image using box filters and integral images. +// +// Examples +// i = imread("images/lena.jpg"); +// intImg = integralImage(i); +// kernel = integralKernel([2 2 11 11], 1/51); +// filter = integralFilter(intImg, kernel.bbox, kernel.weights, kernel.filterSize); +// +// See also +// integralImage +// integralKernel +// imread +// +// Authors +// Tanmay Chaudhari + + + [lhs rhs] = argn(0) + if rhs < 4 + error(msprintf("Not enough input arguments")); + elseif rhs > 4 + error(msprintf("Too many input arguments")); + end + if lhs > 1 + error(msprintf("Too many output arguments")); + end + + inputimage1 = mattolist(inputimage); + a = raw_integralFilter(inputimage1, bbox, weights, filterSize); + out(:, :, 1) = a(1); +endfunction \ No newline at end of file diff --git a/macros/isFilter.bin b/macros/isFilter.bin new file mode 100644 index 0000000000000000000000000000000000000000..d431e73e29551a6a5c0dc00296f3aaf7848e3e98 GIT binary patch literal 4140 zcmeI#-)>Y@6bA4Ck?3Gs+E`jVGX;T|T8$xvv?O}LGjPET@yaLif>+^vh$h4v2x_<@ z*6&x(n(Q3sOiMzzVv?1;_Fn(Lwaz|gwq~z4x998K{@}MZnM^K(ZcMvrcXfAfK9FCG zY;8K94vtT^v)ju~_xE3YGMQ}f8TvM~ANuR$y;2&GB&%Rvft_V{N4*yzF`;qW_WggCwKn%LULk%HAMb4s}*0q3yY(i@geWmu^p?i>f`e`B-UZSo@FoA7=HJAAN=!kJ0#D8(08HAH|&Ck zrT8y;EDGamIb+-Qhu`w?LwI&$xqRQtU&b%Y^iaM0t+FFiqdC$W`nBE)&yTz+zC24_ zcIH8>c1~b`+L_Q-@rHO+?)u;2NSALlyLyJ?;Y<(2RjU|y zap73_KMBwFx8x`XI_xVC_1CNpeb6DNFZZ%j@AHs+=&%zPFE2d2+g?`f;=d~{{I+>l zKK$!x&0^a}Hu50DtI=MraCT{rc~XF-1S^g|!$tG)W`j9%^O;;l8O_AO4Z zBv%Lf!T}GPngRVi4$(dA*U}$*C$4&@9mEH$3iGfF{$sz!`{mt#-hR>3PpjwTL-p^o zKBoB=x9$M5X^v{f%wGFVW}eJ8av#)P!d?x3#Gf-hO2*y{A@h1UR6pOs`AFVb_SO4O ze0erM4dwH9LKlf;{Uy|G&X$=zF(rfa6D7T+N?Bx0=#82U; zUL^l-LcSSbj3in2iD&*+e+Faw_FYf6aOGdm+PeiNV%B?DoSWHK9CwiWg-^Wq2pha! z%KzHzdbhPR-xvbAtPg5sv)*;P|N8?J2V*v3vemok&Uo+ir+&|pWYt`K`}IBa?Z*VD zzC8{vhIy|!t-c-PtiGjT40}3AuV86~rM{_AzdrWyKa2v!>F-VegRwa*{0iesIrHsn z#^Gnxo3a1NZ=)OW>2t+)_TETX&Du+}8YhFOL1ck7!Y! HIalkygD)=+ literal 0 HcmV?d00001 diff --git a/macros/isFilter.sci b/macros/isFilter.sci new file mode 100644 index 0000000..3f3fd1a --- /dev/null +++ b/macros/isFilter.sci @@ -0,0 +1,47 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function varargout = isFilter(data, sz) +// Decides if a filter is separable or not. +// +// Calling Sequence +// [isFilter s u] = isFilter(filter, size); +// +// Parameters +// filter: Input filter (datatype- mat(double)). +// size: Size of the filter. +// +// Description +// This function uses SVD to compute if the filter is separable or not. It takes as input the +// filter matrix and is the filter is separable it returns the calculated singular and the left +// singular values. +// +// Examples +// filter = [1 0; 0 1]; // Any matrix of dimensions n x n. +// [isfilter] = isFilter(filter); +// +// Examples +// filter = [1 0; 0 1]; // Any matrix of dimensions n x n. +// [isfilter s u] = isFilter(filter); +// +// Authors +// Siddhant Narang + + [lhs rhs] = argn(0) + if rhs > 2 then + error(msprintf("Too many input arguments. Two expected")) + end + if rhs < 2 then + error(msprintf("Insufficient input arguments. Two expected")) + end + + varargout = raw_isFilter("Data", data, "Size", sz); +endfunction \ No newline at end of file diff --git a/macros/matchFeatures.bin b/macros/matchFeatures.bin new file mode 100644 index 0000000000000000000000000000000000000000..09740d42a4eef8169d09bbce07abbb63d9e9d4c1 GIT binary patch literal 17244 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 L6q!fg?B4$es$|@D literal 0 HcmV?d00001 diff --git a/macros/matchFeatures.sci b/macros/matchFeatures.sci new file mode 100644 index 0000000..b61830a --- /dev/null +++ b/macros/matchFeatures.sci @@ -0,0 +1,98 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function [indexPairs,varargout]=matchFeatures(features1,features2,varargin) +// This function is used to find the corresponding matches between two features sets +// +// Calling Sequence +// [ indexPairs ] = matchFeatures( features1, features2, Name, Value... ) +// [ indexPairs matchMetric ] = matchFeatures( features1, features2, Name, Value... ) +// +// Parameters +// features1: Feature Set 1, a set of M1-by-N Matrix, M1 corresponding to number of features and N corresponds to length of each feature vector +// features2: Feature Set 2, a set of M2-by-N Matrix, M2 corresponding to number of features and N corresponds to length of each feature vector +// Method [Optional Input Argument]: Method of matching to be used. Values: ['Exhaustive' (default) | 'Approximate'] +// MatchThreshold [Optional Input Argument]: Matching Threshold for selecting the percentage of strongest matches. Values in range [0 100], default - 10.0 +// Unique [Optional Input Argument]: Boolean value for selecting only unique matches between features. Default-False(0) +// Metric [Optional Input Argument]: Metric to be used for matching features. Values: ['SSD'(default)|'SAD'|'Hamming'|'Hamming_2'] +// indexPairs: P-by-2 matrix containing the indices of corresponding features matched between two input feature sets +// matchMetric: P-by-1 Vector containing the distance metric between matched Features +// +// Description +// MatchFeatures function takes in the Feature Descriptors value of two images as its input and finds the best match between each feature vector of the first image to that of the second image and returns the corresponding indices of each feature matrix +// +// Examples +//stacksize("max"); +// +// img_1 = imread("images/table.jpg", 0); +// img_2 = imread("images/table1.jpg", 0); +// +// lis1 = detectSURFFeatures(img_1); +// lis2 = detectSURFFeatures(img_2); +// +// dimage = drawKeypoints(img_2, lis2.KeyPoints); +// +// features_1 = extractFeatures(img_1, lis1.KeyPoints, "SURFPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale, "SignOfLaplacian", lis1.SignOfLaplacian); +// features_2 = extractFeatures(img_2, lis2.KeyPoints, "SURFPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale, "SignOfLaplacian", lis2.SignOfLaplacian); +// +// +// [matches, distance] = matchFeatures(features_1.Features, features_2.Features, "Method", "Approximate"); +// matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance); +// Examples +// stacksize('max'); +// +// img_1 = imread("sample_image1.jpg", 0); +// img_2 = imread("sample_image2.jpg", 0); +// +// lis1 = detectBRISKFeatures(img_1); +// lis2 = detectBRISKFeatures(img_2); +// +// features_1 = extractFeatures(img_1, lis1.KeyPoints, "BRISKPoints", "Metric", lis1.Metric, "Orientation", lis1.Orientation, "Scale", lis1.Scale); +// features_2 = extractFeatures(img_2, lis2.KeyPoints, "BRISKPoints", "Metric", lis2.Metric, "Orientation", lis2.Orientation, "Scale", lis2.Scale); +// +// [matches, distance] = matchFeatures(features_1.Features, features_2.Features); +// matchedImage = drawMatch(img_1, img_2, lis1.KeyPoints, lis2.KeyPoints, matches, distance); +// +// See also +// imread +// extractFeatures +// drawMatch +// matches +// +// Authors +// Umang Agrawal +// Sridhar Reddy +// Siddhant Narang + + [lhs rhs]=argn(0); + if lhs>2 + error(msprintf("Too many output arguments")); + elseif rhs>10 + error(msprintf("Too many input arguments")); + elseif modulo(rhs, 2) <> 0 + error(msprintf("Either Argument Name or its Value missing")); + end + select rhs-2 + case 0 then + [indexPairs, matchmetric]=raw_matchFeatures(features1,features2); + case 2 then + [indexPairs, matchmetric]=raw_matchFeatures(features1,features2,varargin(1),varargin(2)); + case 4 then + [indexPairs, matchmetric]=raw_matchFeatures(features1,features2,varargin(1),varargin(2),varargin(3),varargin(4)); + case 6 then + [indexPairs, matchmetric]=raw_matchFeatures(features1,features2,varargin(1),varargin(2),varargin(3),varargin(4),varargin(5),varargin(6)); + case 8 then + [indexPairs, matchmetric]=raw_matchFeatures(features1,features2,varargin(1),varargin(2),varargin(3),varargin(4),varargin(5),varargin(6),varargin(7),varargin(8)); + end + if lhs==2 then + varargout(1)=matchmetric; + end +endfunction diff --git a/macros/mlPredict.bin b/macros/mlPredict.bin new file mode 100644 index 0000000000000000000000000000000000000000..0706ad0ecab6e6a5b26147ab4ffeba462d5a69ca GIT binary patch literal 9940 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 3 then + error(msprintf("Too many input arguments")); +end +if rhs < 3 then + error(msprintf("Not enough input arguments")); +end +if lhs > 1 then + error(msprintf("Too many output arguments")); +end + +_disp_mat = mattolist(disp_mat); + +timage = raw_reconstructScene(Q, _disp_mat, handleMissingValues); + +channel = size(timage); + +for i = 1 : channel + image(:, :, i) = timage(i); +end + +endfunction diff --git a/macros/scharr.bin b/macros/scharr.bin new file mode 100644 index 0000000000000000000000000000000000000000..9626d4cf20d3c5124dacc121410bda44b68ed0df GIT binary patch literal 4904 zcmciG%Whj$6b4|I0xc#siA&NH+r?=zNH3}&Ab|uDGY0Si%y}nXil^WrF+<$S2sK@w z>)+ZvIR|+Vu(WjcUVH6-{p;VCV|%f8FrLrPuY4w>(db6m-RbIVb~N6fb|T)au|B`B z$z*zOdC-}_e{$8wGkMVOU+j$!yLs2~)5GPsXUcc4k4EnlulLKoEITjz>+85>LPviU#%HlWgs7#*yvS89x+Z-{t zhD-X1#Z_MZyJc|X`MGLR3$EtE3I}}dl_f{8!}FsWi$>Mlwqe0;^`co{ZrJaY;iruo zKH9;4Qf+v~_*Z3TW$^lRxhTK*jKjm(e7dVoEm?<$n>N4LUrQ6XH2Sya%H|JKW@R0(>%UDj?pLj;z`f!vFLzX_D{QZUzH!e z{ggcg!+f;{pN7HRB}XvT)Z)o)?5ENJzHxmqa;THxO*8c;W{9Kt+5h6RpWql%JMDs# z+R~@B+~zXvRarEp+taeFi6`98%EZ8fWi9njH+_8J@!=xw^RnRBE5Yf;b#cv;k4~w_ zlOKlj_CuMoal7otY6ts+>i5lqXKa_;;e1i?!QExvuAIFiybJKgsjVkt?yKa!&YJ$K zb+}n|yjJ#m@s8HlwGNL9H(FfhI#`2x{jE6%|2nnaZ+OG)?sNTJ&yO>YqjPpr*4|a~ zjo-P{7Ux{&>~`;f+0V=)z~7nrRi?jJ5r)cIFs&|JmPpPsmHxtWnk?ddksXJ=rU%%{=wD81m}VP#cC?!bQKWr@Gts0zJ(Q|Ey>B zCXJ(;yuRDye*U`J=H~s{@)v_czGrnY%xmMt%8h?tt?-h{KGMKPm3MhRHc48J>NYM_OfNA>hBN$y~q z19Mfj%lB=Ztw~omT>9$B_h%g1cm3^(_Z@&gG2WqRd#9#-quOeEqw$ID)>N)-eOU|Z ztUg9-`p_%;EPCA9jHiaK)`_dIZ4NcS{JV14gV}G{C+%A2tm7m0-7-&HU_2{7Zq~~a z4>_3_^$z`h{-@^F@H*ybyj&h1&KAqg@7?DWLq{6s`-(o!p5Kn#eFs*nB)HH^R4&!0G7Ev+w(9G*J?PV^DY_={g>tZsEc;FQ*&0GBkdQa*^yxY literal 0 HcmV?d00001 diff --git a/macros/scharr.sci b/macros/scharr.sci new file mode 100644 index 0000000..2e1a6cf --- /dev/null +++ b/macros/scharr.sci @@ -0,0 +1,50 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Sukul Bagai +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function new_image = scharr(image, ddepth, dx, dy, scale, delta) +// Calculates the first x- or y- image derivative using Scharr operator. +// +// Calling Sequence +// new_image = imcontrast(srcImg, aplha, beta) +// +// Parameters +// srcImg: input image. +// ddepth: output image depth. The possible ddepth values are the following CV_8U CV_16U/CV_16S CV_32F CV_64F +// dx: order of the derivative x. +// dy: order of the derivative y. +// scale: Scale factor for the computed derivative values. +// delta: Delta value that is added to the results. +// +// Description +// This function is used to find the derivative of the source image using the +// Scharr operator. +// +// Examples +// image = imread("lena.jpg"); +// new_image = scharr(image, "CV_8U", 2, 3, 1.5, 2); +// +// See also +// imread +// +// Authors +// Sukul Bagai + + image_list = mattolist(image) + + out = raw_scharr(image_list, ddepth, dx, dy, scale, delta) + + sz = size(out) + + for i = 1: sz + new_image(:, :, i) = out(i) + end + +endfunction diff --git a/macros/sepFilter2D.bin b/macros/sepFilter2D.bin new file mode 100644 index 0000000000000000000000000000000000000000..c473f66c9dcd964fe7b316d10ae78ae59c73f067 GIT binary patch literal 8928 zcmdto+iq1=6b4{CW3d~kloofZEi_t{fI*`dkjRBz=o5IQ7rumVW1^4XWB3l9jT#dJ zqFxzse7Js?&aSoDMxwwGmNe!3rD*?8jk=KLW4Fn)l4 zb+*2}(krR{kzT3eyZMRy=bjyRpC zKD>|Ao18iP(Xla%h1VS0^yAqsB14Zk{mr3GhP-k7CyR_7D;6+K;~&E6A3JG$SiKK{hAQ|-N?F`w{VDDrNxx>~lzVt%mruGQT0 z^&Zpr%AiYKB0j<%PU6h`iE5jJWBe2|KX;3k;XB>%1$$VqBPVqC`WErE`r> zd}FqHoMHU%;NzXfQr`MHU8df%N1ZQuKHY9l&wipttW9f+4#b|l+uOMHZ~a+cbmJj2 zZ~Ay)oONo>7+L!XIl8QIx^vFr%U;s%hZk!6c5yf(?v^;jBn}wZzwA?DZ)1A4`eK5C zx!@2ib3P`f&nq|Q20lFDv*!g{x`H{~c;rXhc)Jfz+5M+Jwzz-xKlpfgh%e`T>P~#Y z&c3ame5k!(-=4AB!3uV1x430Z#138R);sd)TO;xx-mICNo$cC*Pk7`i`Au%KZrVJm zt2SSs4EF~5BOhG&^mXANU-mWjf{(ioJG;X;f5nc+7@Oo_NS1Cq`sT6V7J=v4CdlJ3v-@eA|?R466`ZFoA@75eyxb$bbGa>h| zUY<& za>0Y#-H4a_ev4PRc{9(CSDW9?x!roJJGGhhlQ>fsVoscW4I97E%?B%b)rj9cKP_7@ zOPeA>;4RN&5r6%rlLrPX^J5zazkclR|51A2 z=iJP1RrvYl{eIE>_|}*xHx8{YnB$9>KOSu0=P$jBbmF_^|ITH;T`D5S*Efpj*)2-E zV&*?A?RDOWlc|4e1yY?(erX@Lnxe_&87D6O7dF)c5M& zD@Qf`*Vx2H+Rpm mu^a1ULKj&NxkY>}hEq5%gW=Twpg8lz1-sniv(B8G+J6Ei*Tm5P literal 0 HcmV?d00001 diff --git a/macros/sepFilter2D.sci b/macros/sepFilter2D.sci new file mode 100644 index 0000000..d025eb0 --- /dev/null +++ b/macros/sepFilter2D.sci @@ -0,0 +1,64 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Sukul Bagai +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function new_image = sepFilter2D(image, ddepth, kernel_x, kernel_y, anchor_x, anchor_y, delta, border) +// Applies a separable linear filter to an image. +// +// Calling Sequence +// new_image = sepFilter2D(image, ddepth, kernel_x, kernel_y, anchor_x, anchor_y, delta, border); +// +// Parameters +// image: Input image. +// ddepth: Destination image depth, given below are the possible values CV_8U CV_16U/CV_16S CV_32F CV_64F +// kernel_x: Coefficients for filtering each row. +// kernel_y: Coefficients for filtering each column. +// anchor_x: X-coordinate of the anchor. +// anchor_y: Y-coordinate of the anchor. +// delta: Value added to the filtered results before storing them. +// borderType: Pixel extrapolation method, given below are the possible argument values BORDER_CONSTANT 0 BORDER_REPLICATE 1 BORDER_REFLECT 2 BORDER_WRAP 3 BORDER_REFLECT_101 4 BORDER_TRANSPARENT 5 +// +// Description +// The function applies a separable linear filter to the image. That is, first, every row of src +// is filtered with the 1D kernel kernelX. +// Then, every column of the result is filtered with the 1D kernel kernelY. +// +// Examples +// image = imread("images/lena.jpg"); +// new_image = sepFilter2D(image, CV_8U, [1, 2, 1], [2, 1, 2], -1, -1, 2, 1) +// +// See also +// imread +// +// Authors +// Sukul Bagai + + [lhs, rhs] = argn(0) + if rhs > 8 then + error(msprintf("Too many input arguments")) + end + if rhs < 8 then + error(msprintf("Too less input arguments")) + end + if lhs > 1 then + error(msprintf("Too many output arguments")) + end + + image_list = mattolist(image) + + out = raw_sepFilter2D(image_list, ddepth, kernel_x, kernel_y, anchor_x, anchor_y, delta, border) + + sz = size(out) + + for i = 1 : sz + new_image(:, :, i) = out(i) + end + +endfunction diff --git a/macros/stereoCalibrateAndRect.bin b/macros/stereoCalibrateAndRect.bin new file mode 100644 index 0000000000000000000000000000000000000000..2337e91379086ee3e8c03a7960d8246ddbed228d GIT binary patch literal 14804 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 cDEp cameraMatrix1 distortionCoefficients1 cameraMatrix2 distortionCoefficients2 rotationMatrix TranslationVector DepthMap ProjectionMatrix1 ProjectionMatrix2 +// +// +// Description +// The function estimates transformation between two cameras making a stereo pair and also +// computes the rotation matrices for each camera that (virtually) make both camera image +// planes the same plane. Consequently, this makes all the epipolar lines parallel and thus +// simplifies the dense stereo correspondence problem +// +// Examples +// stacksize("max"); +// img_1 = imread("images/left1.jpg", 0); +// img_2 = imread("images/right1.jpg", 0); +// w1 = genCheckerboardPoints([10, 7], 8); +// ip1 = detectCheckerboardCorner(img_1, [7, 10]); +// ip2 = detectCheckerboardCorner(img_2, [7, 10]); +// ip1l = list(ip1); +// ip2l = list(ip2); +// op = stereoCalibrateAndRect(w1, ip1l, ip2l, size(img_1)); +// [map map1] = disparity(img_1, img_2); +// img = reconstructScene(op.DepthMap, map1, 1); +// +// See also +// imread +// genCheckerboardPoints +// detectCheckerboardCorner +// disparity +// reconstructScene +// +// Authors +// Siddhant Narang + + [lhs rhs] = argn(0); + + if lhs > 1 + error(msprintf("Too many output arguments\n")); + elseif rhs > 8 + error(msprintf("Too many input arguments, maximum number of arguments is 7\n")); + elseif rhs < 4 + error(msprintf("The function needs atleast 3 arguments\n")); + end + + if rhs == 4 + [a b c d e f g h i] = raw_stereoCalibrateAndRect(objectpoints, imagepoints1, imagepoints2, imageSize); + elseif rhs == 5 + [a b c d e f g h i] = raw_stereoCalibrateAndRect(objectpoints, imagepoints1, imagepoints2, imageSize, varargin(1)); + elseif rhs == 6 + [a b c d e f g h i] = raw_stereoCalibrateAndRect(objectpoints, imagepoints1, imagepoints2, imageSize, varargin(1), varargin(2)); + elseif rhs == 7 + [a b c d e f g h i] = raw_stereoCalibrateAndRect(objectpoints, imagepoints1, imagepoints2, imageSize, varargin(1), varargin(2), varargin(3)); + elseif rhs == 8 + [a b c d e f g h i] = raw_stereoCalibrateAndRect(objectpoints, imagepoints1, imagepoints2, imageSize, varargin(1), varargin(2), varargin(3), varargin(4)); + end + + params = struct('cameraMatrix1', a, 'distortionCoefficients1', b, 'cameraMatrix2', c,'distortionCoefficients2', d, 'rotationMatrix', e, 'TranslationVector', f, "DepthMap", g, "ProjectionMatrix1", h, "ProjectionMatrix2", i); + +endfunction \ No newline at end of file diff --git a/macros/trainEMClassifier.bin b/macros/trainEMClassifier.bin new file mode 100644 index 0000000000000000000000000000000000000000..d637888b917f0650b3d5eb34e5b12f389720c948 GIT binary patch literal 8600 zcmeI%-ELG>6bJD7nKD2rle7h=14xKL^a4@A_yJs~G4aCag)hK^`3k;=k3kbf5=20+ z47h&n`FD0tXQtC~VFFIFa`xGKeg4_Uzf|dJc;=yE#1PiZ+T)6pf3lpD8j&uI0x|cBM$1*2&<{cvRy-5xMB_ zp0WA$B6F)nbdhC$t;jqZ2rnN!@zISpe#8bnu`kBxd{i<2USy44`tkCYF7o^*!>136 zf?ExD$JXh1Qo5ptuD<=PT4(#MB0d@iTjS{dqQ>+cCgy9M41fC=Cr4NF69qy@-;NRDiT)flCEt=Q&JN^e{hwjt|ACpsavDfamiw(~rbs8V- zOS{ExfX=x3AOHm-gi zX4&mykbKSBU%@GL5PlfJ6!C{&spq~g({QDitQhcnPh8&Fn|1#10e>)|$DF*-AxCr= z_iOA%&5`ZbQ_c))Vms(;jK6G0#uJXPH*d@rG4d_-lDKncU<(hs_{awf{UZ7g@~Oq^ zPA8W*>5H#&6+hwD$BI33eBo1kiM%;HEoSrTf_yL_ccI9>Gf&RgyfNM4_nz~>IQ2us-^7jN?7UUQ{LOb6w>t({`u_4imOPv_e;77uLLPu;fhy;t)shWziJE7y8F zbmD_&%gcYchJ{+Ro_dupb9zqh5+8SS;e#a}{?U<~;e!ibla~)_%n~&B< zGWgkK$GBa;QSW#XGu*^WKVEwCOs|@E9~CPfedKJph>dBa3i+4|AWFM59Ri?54f z)A#AilI26{Gj}_9z%F@`6S%;Xt=8{p_7AJ?uyLfmTFf%HXy2Q5|8MKB!rZOJV_nSu z@41~GIjx7Nga7y3{_m^(J*QXOKh7Hc(7QU$-pbz3Ud;IueC+0QoFBT z<=j(Sd}ZGqfzP>L@iYBRk5`ZQrk(#eo2}Eg$k`d0_|W$3)cQf+6Qd(``6v#*CBT>N z+)HvFiOd_dHZ4zCujO6bmOI|RORs$=SMGSZ+rTYyxg*0EZtNrT{8Vq`+0I$R*Q~+U z8huDSuNKYvjrE_hQ_JDm8jsGM7~kEvKinMe{=E9Mc>K02W<7yE@BHx8BTE0JwN|K; zuBAPG%=!(u^<%g`SY6pV$&J&E8}}sw)jr~6dIPL3c5~LUSIA_H ze-W(tvc7qCG~5`Uf<^n8hAF?vtc*ry@}I^cGVLB1Y|PFB9D?n8_x*d#q+1 1 + error(msprintf("Too many output arguments")); + elseif rhs < 3 + error(msprintf("Not enough input arguments")); + elseif rhs > 4 + error(msprintf("Too many input arguments")); + end + + if rhs == 3 + temp = raw_trainEMClassifier(imgSets_list, bag_list, classifierName); + end + + if rhs == 4 + temp = raw_trainEMClassifier(imgSets_list, bag_list, classifierName, varargin(1)); + end + + classifier = struct("ClassifierType", temp(1), "ClassifierLocation", temp(2), "BagofFeaturesLocation", temp(3), "Description", temp(4)) + +endfunction diff --git a/macros/trainKNNClassifier.bin b/macros/trainKNNClassifier.bin new file mode 100644 index 0000000000000000000000000000000000000000..99aae6b6a11d44a9f26659ebf35a03ed1859c953 GIT binary patch literal 8048 zcmeI1-)$pdsg z*_`;U?_a*c*2ZAmbxub_~bdAGv;K%b5qkTS6%#V^Vj&J5bAI$i}2Qgp=t`8*U zPR)6naeSP}pZ(w~$8e-^=6_8BPTJ;|wtau5HvZO$`!LynH|IIV3dSy6z9m24CvG?~ zcKpNthY~Pel6bw`*A+MXW6K=Ge_LV>zE%5KQIO zU+h0{MB9ir<~us*o>$Azi8ZF{KES{0s^fZ3ee}ou#xAoZ5jFS)88*9YExaTDvY`w;B zstq1=u+8_X$g=1_g+A?G^kf}g#HFYj;i#C+37ZRK3KBZ)e$3Gk1-*9<){zAZ84_tgf^T?xMP z{Kua4s*44Eb3i-dzo%#XI$k(~Km4PMU*Elt+ulux6O3G}*Or7i@_2mS#M&8g#Qv@| z6f6 zm;CaM!g{g)yeIKtJHP+IF}yK9f<8ETC&8Y%eYW^~_WKIH5Mp^=()6wEZ_S}$>l{t0 zYde#NqsQfVGXKo>k94R5#QQ?htaS9{M;W%s=d{3tJrF&x8E`b7v$xMCShHnWHJMl%F$#OF5*?kDY&ue zSJl<@X*-(Ku0y^Dic#}Az=OGMTQ8{vZny5k?I#j*%lkBb`0bK&%Qsl+0o*yiorC5R zTj~frI?tb7eg`vtWA1(-Uf?M1Rp%}ocFEoU8?Op`c0Ijv#?2i)k$cpR@0D-lCfBC< zeJES!_r2ujuI|on#+vGSJU5!ops3UI-%`}6iW|2kHUD=}H>hDg2l;O+uK|<(@L;KM zqz9?a;#r@gvmA{aeJx-3`6&4$KmSXPm@n3U=5G3LuC3O#@eH@-nftmt%Vc)(#}Hh7 zEFqtqQ>-JkvFo>p{5Mh^2Tg0=!~qzn6JU0LU literal 0 HcmV?d00001 diff --git a/macros/trainKNNClassifier.sci b/macros/trainKNNClassifier.sci new file mode 100644 index 0000000..e0309dc --- /dev/null +++ b/macros/trainKNNClassifier.sci @@ -0,0 +1,73 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function classifier = trainKNNClassifier(imgSets, bag, classifierName, varargin) +// This function is used to train an image classifier using the KNN algorithm. +// +// Calling Sequence +// classifier = trainKNNClassifier(imgSets, bag, classifierName) +// classifier = trainKNNClassifier(imgSets, bag, classifierName, algorithmType) +// +// Parameters +// classifier: Image category classifier +// imgSets: Input imageSet to train the classifier on +// bag: The bagOfFeatures of the imageSet provided +// algorithmType: +// +// Description +// This function trains a KNN classifier which can be used to predict classes of images given to it as +// input using the predictKNN() function. +// +// Examples +// imgSet = imageSet('images/trainset_2/','recursive'); +// [trainingSet testSet] = partition(imgSet,[0.8]); +// bag = bagOfFeatures(trainingSet); +// KNNClassifier = trainKNNClassifier(trainingSet, bag, classifierName); +// +// Examples +// imgSet = imageSet('images/trainset_3/','recursive'); +// [trainingSet testSet] = partition(imgSet,[0.8]); +// bag = bagOfFeatures(trainingSet); +// algorithmType = 1; +// KNNClassifier = trainKNNClassifier(trainingSet, bag, classifierName, algorithmType); +// save("var.dat", "KNNClassifier"); +// +// See also +// imageSet +// partition +// bagOfFeatures +// mlPredict +// save +// +// Authors +// Siddhant Narang + + bag_list = bagStructToList(bag); + imgSets_list = imageSetToList(imgSets); + + // Handling variable arguments. + [lhs rhs] = argn(0) + if lhs > 1 + error(msprintf("Too many output arguments")); + elseif rhs < 3 + error(msprintf("Not enough input arguments")); + elseif rhs > 4 + error(msprintf("Too many input arguments")); + end + if rhs == 3 + temp = raw_trainKNNClassifier(imgSets_list, bag_list, classifierName); + elseif rhs == 4 + temp = raw_trainKNNClassifier(imgSets_list, bag_list, classifierName, varargin(1)); + end + + classifier = struct("ClassifierType", temp(1), "ClassifierLocation", temp(2), "BagofFeaturesLocation", temp(3), "Description", temp(4)) + +endfunction diff --git a/macros/trainLRClassifier.bin b/macros/trainLRClassifier.bin new file mode 100644 index 0000000000000000000000000000000000000000..7960561a279fe7604fbb0b38f33670f74eca796a GIT binary patch literal 15460 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 literal 0 HcmV?d00001 diff --git a/macros/trainLRClassifier.sci b/macros/trainLRClassifier.sci new file mode 100644 index 0000000..dfeb6a4 --- /dev/null +++ b/macros/trainLRClassifier.sci @@ -0,0 +1,94 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Siddhant Narang +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function classifier = trainLRClassifier(imgSets, bag, classifierName, varargin) +// This function is used to train an image classifier using the LR algorithm. +// +// Calling Sequence +// classifier = trainLRClassifier(imgSets, bag, classifierName) +// classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate) +// classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration) +// classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization) +// classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod) +// classifier = trainLRClassifier(imgSets, bag, classifierName, learningRate, iteration, regularization, trainMethod, minibatch) +// +// Parameters +// classifier: Image category classifier +// imgSets: Input imageSet to train the classifier on +// bag: The bagOfFeatures of the imageSet provided +// learningRate: Defines the rate at which the classifier will learn. +// iteration: Number of iterations the training function will perform. +// regularization: Controls the kind of regularization to be applied. The types areREG_DISABLE- Regularization disabled, flag value = -1.REG_L1- L1 norm, flag value = 0.REG_L2- L2 norm, flag value = 1. +// +// trainMethod: Controls the kind of training method to be applied. The types areBATCH- flag value = 1.MINI_BATCH- flag value = 0. +// +// minibatch: Specifies the number of training samples taken in each step of Mini-Batch Gradient Descent. +// Will only be used if trainMethod flag value is set to 0 training algorithm. +// It has to take values less than the total number of training samples. +// +// +// Description +// This function trains a LR classifier which can be used to predict classes of images given to it as +// input using the predictLR() function. +// +// Examples +// imgSet = imageSet('images/trainset_2/','recursive'); +// [trainingSet testSet] = partition(imgSet,[0.8]); +// bag = bagOfFeatures(trainingSet); +// lrclassi = trainLRClassifier(im, bag, "lrclassi", 1, 150, 0, 1, 5); +// +// Examples +// imgSet = imageSet('images/trainset_3/','recursive'); +// [trainingSet testSet] = partition(imgSet,[0.8]); +// bag = bagOfFeatures(trainingSet); +// lrclassi = trainLRClassifier(im, bag, "lrclassi", 1, 150, 0); +// save("var.dat", "lrclassi"); +// +// See also +// imageSet +// partition +// bagOfFeatures +// mlPredict +// save +// +// Authors +// Siddhant Narang + + bag_list = bagStructToList(bag); + imgSets_list = imageSetToList(imgSets); + + // Handling variable arguments. + [lhs rhs] = argn(0) + if lhs > 1 + error(msprintf("Too many output arguments")); + elseif rhs < 3 + error(msprintf("Not enough input arguments")); + elseif rhs > 8 + error(msprintf("Too many input arguments")); + end + if rhs == 3 + temp = raw_trainLRClassifier(imgSets_list, bag_list, classifierName); + elseif rhs == 4 + temp = raw_trainLRClassifier(imgSets_list, bag_list, classifierName, varargin(1)); + elseif rhs == 5 + temp = raw_trainLRClassifier(imgSets_list, bag_list, classifierName, varargin(1), varargin(2)); + elseif rhs == 6 + temp = raw_trainLRClassifier(imgSets_list, bag_list, classifierName, varargin(1), varargin(2), varargin(3)); + msprintf("6 arguments"); + elseif rhs == 7 + temp = raw_trainLRClassifier(imgSets_list, bag_list, classifierName, varargin(1), varargin(2), varargin(3), varargin(4)); + elseif rhs == 8 + temp = raw_trainLRClassifier(imgSets_list, bag_list, classifierName, varargin(1), varargin(2), varargin(3), varargin(4), varargin(5)); + end + + classifier = struct("ClassifierType", temp(1), "ClassifierLocation", temp(2), "BagofFeaturesLocation", temp(3), "Description", temp(4)) + +endfunction diff --git a/macros/triangulatePoints.bin b/macros/triangulatePoints.bin new file mode 100644 index 0000000000000000000000000000000000000000..e36e8bae766cb17c8a8e026e0124b73906dbd42f GIT binary patch literal 5092 zcmeI$&2Cgj5CvdE2*D=&8H`QLfJs7^!?wNm6eraC0E`p zp4e;4v*85Y_SVJS)yc8hVw<$}<8$lpe9gh9?_$&?S;WmalKEN%i<xa_mm$6(JFy?Asz zx1-du_bJ9s^L@8Qah)?9aVL1=i$m(l4lgy(2Sa{xqx+^LdD|!0^i0pg8XZi|FMKKQrBznPY?poW zre?727=FZ1pP}#ciWuhf{Wn2hJ3gXI?(F0d-~ZLA7T)zgmcTzK8SdrqyZ?uVz1P`zmw6ZPVe~wlTf^&i z)A^pZuW-G6JrXX@S(YpNv0P6!AAEn&=84I- z^>Bwxo;^pH)XcoMiH=YHlCOL|Z)>M&BR0aYS-7}*QP(H9&Ee|hBZ0t8Fjw?3;$cE zmVZ?(^pX7C%X-LNrFU|!PS;%B^A1%5cL@v|J$I?i-AC*q?j-v^_FL886~ELyX6}cm ye_%#_!QJEN}V48s7rLxJ&>5 literal 0 HcmV?d00001 diff --git a/macros/triangulatePoints.sci b/macros/triangulatePoints.sci new file mode 100644 index 0000000..ac94b1e --- /dev/null +++ b/macros/triangulatePoints.sci @@ -0,0 +1,42 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Deepshikha +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function points4D = triangulatePoints(projMat1, projMat2, points1, points2) +// Returns the worldPoint coordinates of the feature points. +// +// Calling Sequence +// points4D = triangulatePoints(projMat1, projMat2, points1, points2) +// +// Parameters +// projMat1: 3X4 projection matrix for the first Camera matrix +// projMat2: 3X4 projection matrix for the second Camera matrix +// points1: 2xN array of feature points in the 1st image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1 +// points2: 2xN array of feature points in the 2nd image. In case of c++ version it can be also a vector of feature points or two-channel matrix of size 1xN or Nx1 +// points4D: 4XN array or matrix of reconstructed points +// +// Description +// Returns 4D location of the matched feature points from the two projected matrices. The 4D location of the feature points is reconstructed using triangulation. +// +// Examples +// [projMat1] = [12 21 21 19; 34 12 0 2; 112 431 890 32.1] +// [projMat2] = [16 17 32 1; 64 90 12 11; 123 43.5 895 9.8] +// [points1] = [1 2 3 4;5 6 7 8] +// [points2] = [32 1 3 5; 9 8 3 4] +// [points4D] = triangulatePoints(projMat1, projMat2, points1, points2) +// +// Authors +// Deepshikha + + + points4D = raw_triangulatePoints(projMat1, projMat2, points1, points2) + +endfunction + diff --git a/macros/whitepoint.bin b/macros/whitepoint.bin new file mode 100644 index 0000000000000000000000000000000000000000..9f1f0a9045c53b75ba6937873158453ae84ca789 GIT binary patch literal 9072 zcmeI&%WfQ15C-50*NFomF&D=;4sAO~iDMZQ5Lwvoz$36=!L#uqYEb$E|LA;>gx4XsOhvPu;8jQ{CgFySu)9d-LA<#`dE#*SoXX>_*Yf?%tXGJm9Tw zY(Ch2cz=6qedA8{-G7+RX73gMlcMj69u+-5IXSsq_wAwwMO#H1MfZ#F*ZMpD-6DMQ z2;cp~{{B&ar%xWAFEZ~G*}GT72A*8-#I#;SFZVmOCKJE$htD4pFQ3s7D|yfSu*b$u z(QeUR|12i5vB7ro70WP2_Ut3FsX?13Tja#8PKkp|a#4fCC3o_X%f2|iDB??;uB_RW z&tKKE#2>${pI`c(eq6F@BxZd6tz!>=tUgcs{jTnOCQiDWMPjv={2$j^+;UNy@Z`N; z^rR?0Yk9i9Rcro#?en24ui%Ki)SLa-`2NiodQ(0RN|xQ9%dYs@@JwIqYKE-4qBdS~ zVn~lYi=(xZ8t{+k%Z1JOdKrwxK0EBSF{oj1&UR`Z8PBjZjFT-n*v~m*8wS!NdGJlP z#otlCm-^?7IX_}xFSuiq+;I`T;Xd1~oyhT>I=kCXtZ&u2T0A@K_u&2aqCbkr#3#Mv zA6uyfzhXhDpFQ%?6Bm1bmfiULvfulv?k;EXW|4SYZxltwti>N*WBhpug`U-#9^aY2 z>Y=uJ<1R;c@ru(kdCz*4e%X_=oXoh?znw#5x}x+Vb0qVK&-kU!R(h6tMi!rM^6W+q zM%o-=L+xXmJYDC|IyJB5qOSISt6r$hQPJl`V>k&fxdso(Pu;|GTts$RxiMezPwx+F zEynA>V|)fnLp-V-EWTD0nTzmPq6^&3dp$nrOyMzoo5EsOy828`z13zJECw6o*@h9g zW=9X>55L7)D;t@d;jY*9yejxk4=beE>qYWeHGJ#Eb>aH&I@`f2Jhyl?W9LO`7MYe` z+oxCfHp~jOrH9y5vJkC95oAI(cDubGbDat94=v=O<1HC`N-J|w$0p&rfXP(}$VNuXd)>A!CnBS7eXQs^H&jN>9xzaR&d^M@6eJrGNU<&X@EN2J!R|*{83M?1d+1 z*vWShnb`1~j~}+k?AJ4S`tXHd4d(3e15fV!kj2k?98RK7#@aVO`^d96rt)GZ-_+hS zWLx>2dKQOx#4(m@>c!XaY{G+cb>6uQuf)!LXTgv2{j7-XW%%5KIm=gk^IEu-LJ;^en{TVuXyK0sfl{ncad}Hjd#(QUT}5P%jky~ zllyV4!;`O?$uSsnS6kSN?6PuWzSK%T)y~V`%ZiY zheIsm59h>1ST2*v}D=oic)Ve&=;5Z)PcVJ$3;JuPyXEZ>;9xD ze&B??)K*xspZ8i@*Rl9g|I{|Ux>34qeDT@FFP4L%#L%wk?-!;1Q+|B2zltCF ztsnVL)q9zE+gOG*NvxmsKHA!{ot#_TiS07+=v{P&7+ot~Fmzr{t&OReBh$uw*&3!7 z=haY+@TcO5jW!+_YHJARW`c9k6{*1(KGm@Z|@4f zlg^7_N^Uq$B6q8|$KNvNK6)j78q>VD;WxN<47{c;{K_GE?&9~&kr|9{@2A=mhj~Na zn!cJ^#||5612a?qPvxJoRqTb#)>`+l8~ML5|CS6K_zu)>_B@N<{oA6c|07eZMNVQN G=l&lXv+#5P literal 0 HcmV?d00001 diff --git a/macros/whitepoint.sci b/macros/whitepoint.sci new file mode 100644 index 0000000..d6d4515 --- /dev/null +++ b/macros/whitepoint.sci @@ -0,0 +1,46 @@ +// Copyright (C) 2015 - IIT Bombay - FOSSEE +// +// This file must be used under the terms of the CeCILL. +// This source file is licensed as described in the file COPYING, which +// you should have received as part of this distribution. The terms +// are also available at +// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt +// Author: Tess Zacharias +// Organization: FOSSEE, IIT Bombay +// Email: toolbox@scilab.in + +function xyz = whitepoint(input_string) +// Returns a three element vector defining the illumination xyz values for different lighting conditions. +// +// Calling Sequence +// xyz = whitepoint(string); +// +// Parameters +// string: The following are the possible values for this argument and their descriptions d65- CIE standard illuminant D65, [0.9504, 1.0000, 1.0888]. Reperesents noon daylight with correlated color temperature of 6504 K.d50- CIE standard illuminant D50, [0.9642, 1.0000, 0.8251]. Represents warm daylight at sunrise or sunset with correlated color temperature of 5003 K.a- CIE standard illuminant A, [1.0985, 1.0000, 0.3558]. Reperesents typical, domestic, tungsten-filament lighting with correlated color temperature of 2856 K. c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Simulates average or north sky daylight with correlated color temperature of 6774 K. icc- Profile Connection Space (PCS) illuminant used in ICC profiles. Approximation of [0.962, 1.000, 0.8249] using fixed-point, signed, 32-bit numbers with 16 fractional bits. Actual value: [31595,32768, 27030]/32768. c- CIE standard illuminant C, [0.9807, 1.0000, 1.1822]. Represents average or north sky daylight with correlated color temperature of 6774 K.d55- CIE standard illuminant D55, [0.9568, 1.0000, 0.9214]. Represents mid-morning or mid-afternoon daylight with correlated color temperature of 5500 K. +// +// +// Description +// This function is used to get a vector of xyz color space representation for different lighting +// conditions which can be used to get images with different lighting properties. +// +// Examples +// xyz = whitepoint("a"); +// img = imread("images/lena.jpeg"); +// image = applycform(img, "srgb2xyz"); +// temp1 = image(:, :, 1) +// temp3 = image(:, :, 3) +// image(:, :, 1) = temp3 * xyz(1); +// image(:, :, 2) = image(:, :, 2) * xyz(2); +// image(:, :, 3) = temp1 * xyz(3); +// imshow(image); +// +// See also +// imshow +// imread +// applycform +// +// Authors +// Tess Zacharias + + xyz = raw_whitepoint(input_string) +endfunction diff --git a/sci_gateway/cpp/opencv_decorrstretch.cpp b/sci_gateway/cpp/opencv_decorrstretch.cpp new file mode 100644 index 0000000..377a3cd --- /dev/null +++ b/sci_gateway/cpp/opencv_decorrstretch.cpp @@ -0,0 +1,145 @@ +/*************************************************** +Author : Dhruti Shah +***************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + Mat dstretch(Mat& input) + { + CV_Assert(input.channels() > 1); + + Mat dataMu, dataSigma, eigDataSigma, scale, stretch; + Mat targetMean = Mat(); + + Mat data = input.reshape(1, input.rows*input.cols); + + meanStdDev(input, dataMu, dataSigma); + + PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW); + + sqrt(pca.eigenvalues, eigDataSigma); + scale = Mat::diag(1/eigDataSigma); + stretch = Mat::diag(dataSigma); + + stretch.convertTo(stretch, CV_32F); + + Mat zmudata; + Mat repMu = repeat(dataMu.t(), data.rows, 1); + subtract(data, repMu, zmudata, Mat(), CV_32F); + + Mat transformed = zmudata*(pca.eigenvectors.t()*scale*pca.eigenvectors*stretch); + add(transformed, repMu, transformed, Mat(), CV_32F); + + Mat dstr32f = transformed.reshape(input.channels(), input.rows); + return dstr32f; + } + + int opencv_decorrstretch(char *fname, unsigned long fname_len) + { + SciErr sciErr; + int intErr = 0; + int iRows=0,iCols=0; + int *piLen = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + int *piAddr5 = NULL; + char **type = NULL; + int i,j,k; + + //checking input argument + CheckInputArgument(pvApiCtx, 1, 1); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + Mat image; + retrieveImage(image,1); + + Mat lab; + try + { + cvtColor(image, lab, CV_BGR2Lab); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + Mat dstrlab32f = dstretch(lab); + Mat dstrlab8u; + try + { + dstrlab32f.convertTo(dstrlab8u, CV_8UC3); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + Mat dstrlab2bgr; + try + { + cvtColor(dstrlab8u, dstrlab2bgr, CV_Lab2BGR); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + Mat dstrbgr32f; + try + { + dstrbgr32f = dstretch(image); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + Mat dstrbgr8u; + try + { + dstrbgr32f.convertTo(dstrbgr8u, CV_8UC3); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + string tempstring = type2str(dstrbgr8u.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,dstrbgr8u,1); + free(checker); + + // Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + + // Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + } +/* ==================================================================== */ +} + diff --git a/sci_gateway/cpp/opencv_detectAndComputeORB.cpp b/sci_gateway/cpp/opencv_detectAndComputeORB.cpp new file mode 100644 index 0000000..82ad94f --- /dev/null +++ b/sci_gateway/cpp/opencv_detectAndComputeORB.cpp @@ -0,0 +1,660 @@ +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/features2d/features2d.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_detectAndComputeORB(char *fname, unsigned long fname_len) + { + + // Error management variable + SciErr sciErr; + + //Variables + int i, j; + int intErr; + int iRows1 = 0; + int iCols1 = 0; + + int iRows = 0; + int iCols = 0; + int *piLen = NULL; + int *piAddr = NULL; + char **pstData = NULL; + char *currentArg = NULL; + bool *providedArgs = NULL; + + double edgeThreshold = 20; + double fastThreshold = 31; + double firstLevel = 0; + double maxFeatures = 80; + double nLevels = 8; + double patchSize = 30; + double scaleFactor = 1.5f; + double scoreType = ORB::HARRIS_SCORE; + int WTA_K = 2; + + double *ROImat = NULL; + int iRet; + + // checking input argument + // 1 : image + // 2 : edgeThreshold + // 3 : fastThreshold + // 4 : firstLevel + // 5 : ROI + // 6 : maxFeatures + // 7 : nLevels + // 8 : patchSize + // 9 : scaleFactor + // 10 : scoreType + CheckInputArgument(pvApiCtx, 1, 19); + CheckOutputArgument(pvApiCtx, 1, 1); + + // retrieve image + Mat image; + retrieveImage(image, 1); + + // For the optional arguments + int nbInputArguments = *getNbInputArgument(pvApiCtx); + //sciprint("%d\n",nbInputArguments); + + if((nbInputArguments%2) == 0) + { + Scierror(999, "%d: The number of arguments must be odd\n"); + return 0; + } + + providedArgs = (bool*) malloc(sizeof(bool) * 9); + memset(providedArgs, 0, 9); + + for(int iter = 2; iter <= nbInputArguments; iter += 2) + { + sciErr = getVarAddressFromPosition(pvApiCtx, iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + /// Three calls to getMatrixOfString + //First Call + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Second call to get length of string + piLen = (int*) malloc(sizeof(int) * iRows1 * iCols1); + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows1, &iCols1, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // third call + pstData = (char**) malloc(sizeof(char*) * iRows1 * iCols1); + for(int k = 0; k < iRows1 * iCols1; ++k) + { + pstData[k] = (char*) malloc(sizeof(char) * piLen[k] + 1); + } + + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows1, &iCols1, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + currentArg = pstData[0]; + + // getting edgeThreshold + if(strcmp(currentArg, "edgeThreshold") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[0]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + edgeThreshold = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""edgeThreshold"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""edgeThreshold"" is not of type Integer.\n"); + return 0; + } + providedArgs[0] = 1; + } + else if(providedArgs[0]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "fastThreshold") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[1]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + fastThreshold = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""fastThreshold"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""fastThreshold"" is not of type Integer.\n"); + return 0; + } + providedArgs[1] = 1; + } + else if(providedArgs[1]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "firstLevel") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[2]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + firstLevel = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""firstLevel"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""firstLevel"" is not of type Integer.\n"); + return 0; + } + providedArgs[2] = 1; + } + else if(providedArgs[2]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + else if(strcmp(currentArg,"ROI")==0) + { + // val_position=i+1; + + if(providedArgs[3] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, i + 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddr) || isVarComplex(pvApiCtx, piAddr)) + { + Scierror(999,"Enter a List of 4 arguments\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &ROImat); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows*iCols!=4) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + if(ROImat[0]<0 || ROImat[1]<0 || ROImat[2]<0 || ROImat[3]<0) + { + Scierror(999,"Arguments cannot be negative\n"); + return 0; + } + + if(ROImat[0]>image.cols || ROImat[1]>image.rows || ROImat[0]+ROImat[2]>image.cols + || ROImat[1]+ROImat[3]>image.rows) + { + Scierror(999,"Please make sure the arguments are within the image range\n"); + return 0; + } + + providedArgs[3] = 1; + } + + if(strcmp(currentArg, "maxFeatures") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[4]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + maxFeatures = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""maxFeatures"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""maxFeatures"" is not of type Integer.\n"); + return 0; + } + providedArgs[4] = 1; + } + else if(providedArgs[4]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "nLevels") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[5]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + nLevels = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""nLevels"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""nLevels"" is not of type Integer.\n"); + return 0; + } + providedArgs[5] = 1; + } + else if(providedArgs[5]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "patchSize") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[6]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + patchSize = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""patchSize"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""patchSize"" is not of type Integer.\n"); + return 0; + } + providedArgs[6] = 1; + } + else if(providedArgs[6]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "scaleFactor") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[7]) + { + // if(isDoubleType(pvApiCtx, piAddr)) + // { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + scaleFactor = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""scaleFactor"" is not of scalar type.\n"); + return 0; + } + // } + // else + // { + // Scierror(999, "Error: The input argument ""scaleFactor"" is not of type Integer.\n"); + // return 0; + // } + providedArgs[7] = 1; + } + else if(providedArgs[7]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "scoreType") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[8]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + if(dData == 0 || dData == 1 || dData == 32) + { + Scierror(999, "Error: The input argument ""scoreType"" should be 0, 1 or 32.\n"); + return 0; + } + scoreType = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""scoreType"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""scoreType"" is not of type Integer.\n"); + return 0; + } + providedArgs[8] = 1; + } + else if(providedArgs[8]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + } + /// End of error check and input get; + + /// Creating model and setting its params; + Ptr orb = ORB::create(maxFeatures, scaleFactor, nLevels, + edgeThreshold, firstLevel, WTA_K, + scoreType, patchSize, fastThreshold); + + sciprint("\nET:%d\n", orb->getEdgeThreshold()); + /// to store the keypoints of orb detected + vector keyPoints; + + // if(providedArgs[0]) + // { + // orb->setEdgeThreshold(edgeThreshold); + // } + // if(providedArgs[1]) + // { + // orb->setFastThreshold(fastThreshold); + // } + // if(providedArgs[2]) + // { + // orb->setFirstLevel(firstLevel); + // } + + // if(providedArgs[4]) + // { + // orb->setMaxFeatures(maxFeatures); + // } + // if(providedArgs[5]) + // { + // orb->setNLevels(nLevels); + // } + // if(providedArgs[6]) + // { + // orb->setPatchSize(patchSize); + // } + // if(providedArgs[7]) + // { + // orb->setScaleFactor(scaleFactor); + // } + // if(providedArgs[8]) + // { + // orb->setScoreType(scoreType); + // } + + // Handling ROI argument + if(providedArgs[3]==0) + { + ROImat=(double *)malloc(sizeof(double)*1*4); + ROImat[0]=0; + ROImat[1]=0; + ROImat[2]=image.cols; + ROImat[3]=image.rows; + } + + Rect masker(ROImat[0], ROImat[1], ROImat[2], ROImat[3]); + Mat mask(image.size(), CV_8UC1, Scalar::all(0)); + + // Creating ROI + try + { + mask(masker).setTo(Scalar::all(255)); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + } + + Mat descriptor; + + try + { + image.convertTo(image, CV_8U); + // mask.rows -= 500; + // mask.cols -= 500; + // sciprint("M:%d %d I:%d %d", mask.rows, mask.cols, image.rows, image.cols); + orb->detectAndCompute(image, mask, keyPoints, descriptor); + + // orb->detect(image, keyPoints); + // orb->compute(image, keyPoints, descriptor); + // int dcols = descriptor.cols; + // for(int i = 0; i < dcols; i++) + // { + // sciprint("%d ", descriptor.at(i)); + // } + // sciprint("%d %d", keyPoints[104].pt.x, keyPoints[104].pt.y); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + int total_keypoints = (int)keyPoints.size(); + + double *key_value = (double*)malloc(sizeof(double) * (int)keyPoints.size() * 2); + + vector< KeyPoint >::iterator it; + i = 0; + for(it = keyPoints.begin(); it != keyPoints.end(); ++it) + { + KeyPoint temp = keyPoints[i]; + + // x coordinate + key_value[i + 0 * total_keypoints] = it->pt.x; + + // y coordinate + key_value[i + 1 * total_keypoints] = it->pt.y; + i++; + } + + // Converting descriptor from Mat to double* + int dcols = descriptor.cols; + int drows = descriptor.rows; + // for(int i = 0; i < dcols; i++) + // { + // sciprint("%f ", descriptor.at(i)); + // } + double *_descriptors = (double*) malloc(sizeof(double) * dcols * drows); + + for(int i = 0; i < drows * dcols; i++) + { + _descriptors[i] = int(descriptor.at(i)); + } + + // Creating output arguments + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 2, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, total_keypoints, 2, key_value); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 2, drows, dcols, _descriptors); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_detectBRISKFeatures.cpp b/sci_gateway/cpp/opencv_detectBRISKFeatures.cpp new file mode 100644 index 0000000..2813190 --- /dev/null +++ b/sci_gateway/cpp/opencv_detectBRISKFeatures.cpp @@ -0,0 +1,449 @@ +/*************************************************** +Author : Shashank Shekhar +***************************************************/ +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_detectBRISKFeatures(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int *piAddr = NULL; + int *piAddrVal = NULL; + int argPresence[4]; + + for(int i=0;i<4;i++) + argPresence[i]=0; + + int val_position; + int iRows = 0; + int iCols = 0; + int *piLen = NULL; + char ** pstData = NULL; + char *currentArg = NULL; + + +// DECLARING INPUT ARGUMENTS + + double *ROImat = NULL; + double NumOctaves = 0; + double MinContrast = 0; + double MinQuality = 0; + + +// DECLARING OUTPUT ARGUMENTS + + vector myPoints; + vector validKeyPoints; + int *LocationList = NULL; + double *LocationData = NULL; + double *OrientationData = NULL; + double *ScaleData = NULL; + double *MetricData = NULL; + int size; + +// ARGUMENT CHECK + + CheckInputArgument(pvApiCtx, 1,9); + CheckOutputArgument(pvApiCtx,1,5); + +// RETRIEVING IMAGE + + Mat image; + retrieveImage(image,1); + +// GRAYSCALE VALIDATION + + if(image.channels()!=1) + { + Scierror(999," Feature is not meant for RGB images\n"); + return 0; + } + +// OBTAINING NUMBER OF ARGUMENTS + + int noOfarguments = *getNbInputArgument(pvApiCtx); + +// ARGUMENT COUNT CHECK + + if(noOfarguments%2==0) + { + Scierror(999," Invalid Number Of Arguments\n"); + return 0; + } + +// MULTIPLE ARGUMENT HANDLING + + for(int i=2;i1) + { + Scierror(999,"Invalid Value for MinContrast. Please enter a value between 0 and 1\n"); + return 0; + } + + argPresence[0]=1; + } + else if(strcmp(currentArg,"NumOctaves")==0) + { + val_position=i+1; + + if(argPresence[1]==1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx,val_position,&piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for NumOctaves. Recommended values are between 1 and 4\n"); + return 0; + } + + getScalarDouble(pvApiCtx, piAddrVal, &NumOctaves); + if(NumOctaves<1) + { + Scierror(999," Invalid Value for NumOctaves. Recommended values are between 1 and 4\n"); + return 0; + } + argPresence[1]=1; + } + else if(strcmp(currentArg,"MinQuality")==0) + { + val_position=i+1; + + + if(argPresence[2]==1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx,val_position,&piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for MinQuality. Recommended values are between 0 and 1\n"); + return 0; + } + + getScalarDouble(pvApiCtx, piAddrVal, &MinQuality); + + if(MinQuality<0 || MinQuality>1) + { + Scierror(999," Invalid Value for MinQuality. Please enter a value between 0 and 1 \n"); + return 0; + } + + argPresence[2]=1; + } + else if(strcmp(currentArg,"ROI")==0) + { + val_position=i+1; + + if(argPresence[3]==1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx,val_position,&piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddrVal) || isVarComplex(pvApiCtx, piAddrVal)) + { + Scierror(999,"Enter a List of 4 arguments\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddrVal, &iRows, &iCols, &ROImat); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows*iCols!=4) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + if(ROImat[0]<0 || ROImat[1]<0 || ROImat[2]<0 || ROImat[3]<0) + { + Scierror(999,"Arguments cannot be negative\n"); + return 0; + } + + if(ROImat[0]>image.cols || ROImat[1]>image.rows || ROImat[0]+ROImat[2]>image.cols + || ROImat[1]+ROImat[3]>image.rows) + { + Scierror(999,"Please make sure the arguments are within the image range\n"); + return 0; + } + + argPresence[3]=1; + } + else + { + Scierror(999, "Error: \"%s\" Invalid input argument.\n", currentArg); + return 0; + } + + } + + +// DEFAULT ARGUMENTS + + if(argPresence[0]==0) + MinContrast=0.2; + if(argPresence[1]==0) + NumOctaves=4; + if(argPresence[2]==0) + MinQuality=0.1; + if(argPresence[3]==0) + { + ROImat=(double *)malloc(sizeof(double)*1*4); + ROImat[0]=0; + ROImat[1]=0; + ROImat[2]=image.cols; + ROImat[3]=image.rows; + } + +// CREATING REGION OF INTEREST + + Rect masker(ROImat[0], ROImat[1], ROImat[2], ROImat[3]); + + Mat mask(image.size(), CV_8UC1, Scalar::all(0)); + mask(masker).setTo(Scalar::all(255)); + +// PROCESSING BRISK + + + // Setting Threshold -------------------------------------------------> + + double Threshold = MinContrast * 255; + + // Limiting NumOctaves -----------------------------------------------> + + int g = image.rows>image.cols?image.rows:image.cols; + int maxNumOctaves = int(floor(log2(g))); + if(NumOctaves>maxNumOctaves) + NumOctaves=maxNumOctaves; + + //----------------------------------------------------------------------- + + // BRISK myobject(Threshold, NumOctaves); + // myobject.operator()(image, mask, myPoints, noArray()); + + Ptr myobject = BRISK::create(); + try + { + image.convertTo(image, CV_8U); + myobject->detect(image, myPoints, mask); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + + // Selecting Points according to MinQuality ---------------------------> + + size = myPoints.size(); + + double maxMetric = 0; + double minMetric = 0; + + for(int i=0;imaxMetric) + maxMetric=myPoints[i].response; + } + minMetric = maxMetric*MinQuality; + + int finalSize = 0; + for(int i=0;i=minMetric) + finalSize++; + } + + //------------------------------------------------------------------------ + +// LOCATION ----> + + MetricData = (double *)malloc(sizeof(double)*finalSize); + OrientationData = (double *)malloc(sizeof(double)*finalSize); + ScaleData = (double *)malloc(sizeof(double)*finalSize); + int k=0; + // Appending 1x2 Matrices containing the coordinates of the keypoints, as well as assiging other attributes + for(int i=0;i=minMetric) + { + validKeyPoints.push_back(myPoints[i]); + OrientationData[i] = 0; + MetricData[i] = myPoints[i].response; + ScaleData[i] = myPoints[i].size; + } + } + + int validKeyPointsSize = validKeyPoints.size(); + LocationData = (double *)malloc(sizeof(double) * validKeyPointsSize * 2); + + for(int i = 0; i < validKeyPointsSize; i++) + { + LocationData[i] = myPoints[i].pt.x; + LocationData[i + validKeyPointsSize] = myPoints[i].pt.y; + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, finalSize, 2, LocationData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 2, finalSize, 1, OrientationData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 3, finalSize,1, MetricData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 4,finalSize,1, ScaleData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + createScalarInteger32(pvApiCtx,nbInputArgument(pvApiCtx) + 5, finalSize); + +// ASSIGNING ----> + + for(int i=1;i<=5;i++) + { + AssignOutputVariable(pvApiCtx, i) = nbInputArgument(pvApiCtx) + i; + } + + ReturnArguments(pvApiCtx); + } + +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_detectFASTFeatures.cpp b/sci_gateway/cpp/opencv_detectFASTFeatures.cpp new file mode 100644 index 0000000..b15739e --- /dev/null +++ b/sci_gateway/cpp/opencv_detectFASTFeatures.cpp @@ -0,0 +1,594 @@ +/************************************************************************************************************************************************************************************************* +* Author: Umang Agrawal * +* Code: detectFASTFeatures.cpp * +* Function Format: detectFASTFeatures( Image, Optional Arguments... ) * +* Requirements: Image should be a grayscale image * +* Optional Arguments: 1. 'MinContrast' Value: Range 0 < x < 1 * +* 2. 'MinQuality' Value: Range 0 < x < 1 * +* 3. 'ROI' Value: [ x_cordinate, y_cordinate, width, height ] * +*************************************************************************************************************************************************************************************************/ + + +#include +#include +#include +#include +#include "opencv2/core/core.hpp" +#include "opencv2/features2d/features2d.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + //#include "../common.h" + + // Function using OpenCV to detect FAST Features + int opencv_detectFASTFeatures(char *fname, unsigned long fname_len) + { + int *piAddr = NULL; + + //Variable Declarations + SciErr sciErr; //Error Variable + int sca_read; //Error Variable + + int *imgAddr = NULL; //Address of the Image List Argument + int *piAddrChild = NULL; //Address of the Child of the Image Matrix List + int no_item_list; //Number of items in the list + + int iPrec = 0; //Precesision of the image in the lsit + int iRows=0, iCols=0; //Rows & Columns in the image + + int inp_params; //Number of Input Arguments + int *piAddr1 = NULL; //Address of Argument Head + int *piAddr2 = NULL; //Address of Value_1 of Argument + //int *piAddr3 = NULL; //Address of Value_2 of Argument + //int *piAddr4 = NULL; //Address of Value_3 of Argument + //int *piAddr5 = NULL; //Address of Value_4 of Argument + int Rows,Cols; //Rows & Columns of String Matrix + int *len = NULL; //Length of each String Element + char **arg; //String Argument + double *roi_arg = NULL; //ROI Argument Matrix Address + int rows,cols; //Rows and Columns of ROI value matrix + + //int *point = NULL; //Points returned by the FAST Algorithm + + double arg_val; //Variables for Contrast/Quality Argument + double x = 0, y = 0, width, height; //Variables for ROI Argument + + double thresh; //Effective Threshold + double thresh_c = 0; //Threshold due to arguments + double thresh_q = 0; //Threshold due to arguments + + int count_q = 0; //Count of Argument Quality Call + int count_c = 0; //Count of Argument Contrast Call + int count_r = 0; //Count of Argument ROI call + + vector keypoints; //Keypoint Vector to store the points returned by FAST Algorithm + + int i,j; //Iterators + + double count = 0; //Count of number of Features Detected + double *metric = NULL; + + Mat image; //Image Container + Mat cropped; //Image Container + + //Checks on Input and Output Arguments + CheckInputArgument(pvApiCtx, 1, 7); + CheckOutputArgument(pvApiCtx, 1, 3); + + + //Image Retrieval + //Get Address of the Image List + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &imgAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Get Number of items in the list + sciErr = getListItemNumber(pvApiCtx, imgAddr, &no_item_list); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Check if it is a Grayscal image by checking whether 1 item is present in the list + if( no_item_list == 1) + { + //Address of the Grayscale Matrix + sciErr = getListItemAddress(pvApiCtx, imgAddr, 1, &piAddrChild); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Check whether it is an integer Matrix or not + if(isIntegerType(pvApiCtx, piAddrChild)) + { + //If integer matrix getting precision + sciErr = getMatrixOfIntegerPrecision(pvApiCtx, piAddrChild, &iPrec); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Based on precision Read the matrix + switch(iPrec) + { + case SCI_UINT8: //for unsigned integer 8 + { + unsigned char *pstDatagray = NULL; + sciErr = getMatrixOfUnsignedInteger8InList(pvApiCtx, imgAddr, 1, &iRows, &iCols, &pstDatagray); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + image = Mat(iRows,iCols,CV_8UC1); + for(i=0;i(i,j)=pstDatagray[i+iRows*j]; + break; + } + case SCI_UINT16: //for unsigned integer 16 + { + short unsigned int *pstDatagray = NULL; + sciErr = getMatrixOfUnsignedInteger16InList(pvApiCtx, imgAddr, 1, &iRows, &iCols, &pstDatagray); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + image = Mat(iRows,iCols,CV_16UC1); + for(i=0;i(i,j)=pstDatagray[i+iRows*j]; + break; + } + case SCI_INT32: //for unsigned integer 32 + { + int *pstDatagray = NULL; + sciErr = getMatrixOfInteger32InList(pvApiCtx, imgAddr, 1, &iRows, &iCols, &pstDatagray); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + image = Mat(iRows,iCols,CV_32SC1); + for(i=0;i(i,j)=pstDatagray[i+iRows*j]; + break; + } + } + } + else + { + //If not Integer then must be double + double *pstDatagray = NULL; + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &imgAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDoubleInList(pvApiCtx, imgAddr, 1, &iRows, &iCols, &pstDatagray); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + image = Mat(iRows,iCols,CV_64FC1); + for(i=0;i(i,j)=pstDatagray[i+iRows*j]; + } + } + //If not single element in list than it is not a grayscale image and hence error + else + { + Scierror(999,"Expecting a single Matrix in grayscale format\n"); + return 0; + } + + //Get the Number of Arguments + inp_params = *getNbInputArgument(pvApiCtx); + + //Based on Number of Arguments Evaluate each Argument + for(i=2; i=1) + { + Scierror(999,"Not a valid range.Should be between 0 and 1.\n"); + return 0; + } + //Threshold Calculation + else thresh_c = 256*arg_val; + i++; //Incrementing iterator to count for the value argument read + count_c += 1; //Indicating MinContrast has been called once + } + else + { + Scierror(999,"Specified MinContrast twice. Check Arguments\n"); + return 0; + } + } + //MinQuality Argument + else if(strcmp(arg[0],"MinQuality") == 0) + { + if(count_q == 0) + { + sciErr = getVarAddressFromPosition(pvApiCtx, i+1, &piAddr2); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Checking the type of Value + if( !isDoubleType(pvApiCtx, piAddr2)) + { + Scierror(999,"Not a valid type of value.\n"); + return 0; + } + //Reading the Value of argument + sca_read = getScalarDouble(pvApiCtx, piAddr2, &arg_val); + if(sca_read) + { + Scierror(999,"Not a valid type of value.\n"); + return 0; + } + //Cheack for valid range + if(arg_val<0 && arg_val>=1) + { + Scierror(999,"Not a valid range.Should be between 0 and 1.\n"); + return 0; + } + //Threshold Calculation + else thresh_q = 240*arg_val; + i++; //Incrementing iterator to count for the value argument read + count_q += 1; //Indicating MinQuality has been called once + } + else + { + Scierror(999,"Specified MinQuality twice. Check Arguments\n"); + return 0; + } + } + //ROI Argument + else if(strcmp(arg[0],"ROI") == 0) + { + if(count_r == 0) + { + sciErr = getVarAddressFromPosition(pvApiCtx, i+1, &piAddr2); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Checking the type of argument + if( !isDoubleType(pvApiCtx, piAddr2)) + { + Scierror(999,"Not a valid type of value.\n"); + return 0; + } + //Reading the Value of the argument + sciErr = getMatrixOfDouble(pvApiCtx, piAddr2, &rows, &cols, &roi_arg); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Assigning the elements of the list to their proper function + x = roi_arg[0]; + y = roi_arg[1]; + width = roi_arg[2]; + height = roi_arg[3]; + + + //Code for reading the value associated with ROI individually rather than in a list form + + /*sca_read = getScalarDouble(pvApiCtx, piAddr2, &x); + if(sca_read) + { + Scierror(999,"Not a valid type of value.\n"); + return 0; + } + sciErr = getVarAddressFromPosition(pvApiCtx, i+2, &piAddr3); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sca_read = getScalarDouble(pvApiCtx, piAddr3, &y); + if(sca_read) + { + Scierror(999,"Not a valid type of value.\n"); + return 0; + } + sciErr = getVarAddressFromPosition(pvApiCtx, i+3, &piAddr4); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sca_read = getScalarDouble(pvApiCtx, piAddr4, &width); + if(sca_read) + { + Scierror(999,"Not a valid type of value.\n"); + return 0; + } + sciErr = getVarAddressFromPosition(pvApiCtx, i+4, &piAddr5); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sca_read = getScalarDouble(pvApiCtx, piAddr5, &height); + if(sca_read) + { + Scierror(999,"Not a valid type of value.\n"); + return 0; + }*/ + + //Checking for valid crop area + if(x>=image.cols || y>=image.rows || x<0 || y<0) + { + sciprint("Invalid x or y value\n"); + return 0; + } + if(width<=0 || height<=0 || x+width > image.cols || y+height > image.rows) + { + sciprint("Invalid width or height value\n"); + return 0; + } + //Croppint the image + Rect myROI(x, y, width, height); + Mat croppedRef(image, myROI); + croppedRef.copyTo(cropped); + i++; //Incrementing iterator to count for the value argument read + count_r += 1; //Indicating ROI has been called once + } + else + { + Scierror(999,"Specified ROC twice. Check Arguments\n"); + return 0; + } + } + else + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + } + + //Calculating the effective threshold by selecting the maximum threshold + if(thresh_c > 0 && thresh_c >= thresh_q) + thresh = thresh_c; + else if(thresh_q > 0 && thresh_q > thresh_c) + thresh = thresh_q; + else thresh = 256 * 0.2; + + //Implementing FAST Algorithm + int t = int(thresh); + Ptr fd = FastFeatureDetector::create(t, true); + image.convertTo(image, CV_8U); + if(count_r != 0) + { + try + { + fd -> detect(cropped, keypoints); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + } + else + { + try + { + int t = int(thresh); + fd -> detect(image, keypoints); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + } + + count = keypoints.size(); + + metric = (double*)malloc(sizeof(double)*keypoints.size()*1); + for( i=0; i +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + /* Calling syntax: detectHarrisFeatures(I) or detectHarrisFeatures(I, Name, Value) + which uses additional options specified by one or more Name, Value pair arguments. + Arguments Allowed : MinQuality, FilterSize, ROI, SensitivityFactor + MinQuality : The minimum accepted quality of corners represents a fraction of the + maximum corner metric value in the image. Larger values can be used + to remove erroneous corners. + FilterSize : Gaussian filter dimension + ROI : Rectangular region for corner detection + SensitivityFactor : A scalar value, K, where 0 < K < 0.25, specifying the sensitivity + factor used in the Harris detection algorithm. */ + + int opencv_detectHarrisFeatures(char *fname, unsigned long fname_len) + { + // Error management variables + SciErr sciErr; + int intErr; + + //------Local variables------// + double *location = NULL; + double *metric = NULL; + int *piAddr = NULL; + int *piLen = NULL; + int nbInputArguments; + char **pstData = NULL; + char *currentArg = NULL; + bool *providedArgs = NULL; + double *matrixOfRoi; // ROI[xStart, yStart, width, height] + int iRows, iCols; + Mat sourceImage, dst, dstThresholded, ucharDstThresholded, extended; + vector > contours; + double filterSize = 5, minQuality = 1, sensitivityFactor = 0.04, blockSize = 2, maxDst, localMax; + double sensitivityFactor1 = 0.05; + int blockSize1 = 2, filterSize1 = 3; + bool *included = NULL; + int pointCount = 0, localMaxPos; + double tempForSwapping; + int coordinateMin, coordinatePos; + + //------Check number of parameters------// + CheckInputArgument(pvApiCtx, 1, 9); + CheckOutputArgument(pvApiCtx, 1, 3); + + //------Get input arguments------// + retrieveImage(sourceImage, 1); + if(sourceImage.channels() != 1) + { + Scierror(999, "The input image is not a grayscale image."); + return 0; + } + matrixOfRoi = (double*) malloc(sizeof(double) * 4); + providedArgs = (bool*) malloc(sizeof(bool) * 4); + memset(providedArgs, 0, 4); + matrixOfRoi[0] = 0; + matrixOfRoi[1] = 0; + matrixOfRoi[2] = sourceImage.cols; + matrixOfRoi[3] = sourceImage.rows; + + nbInputArguments = *getNbInputArgument(pvApiCtx); + // The following loop is for checking if optional arguments have been provided + for(int iter = 2; iter <= nbInputArguments; iter++) + { + // Getting address of next argument + sciErr = getVarAddressFromPosition(pvApiCtx, iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Extracting name of next argument takes three calls to getMatrixOfString + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + currentArg = pstData[0]; + // providedArgs[] makes sure that no optional argument is provided more than once + if(strcmp(currentArg, "MinQuality")==0) + { + if(iter+1<=nbInputArguments && !providedArgs[0]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr, &minQuality); + if(intErr) + { + return intErr; + } + // Checking if values are in proper range. Same for all optional arguments + if(minQuality < 0 || minQuality > 1) + { + Scierror(999, "Error: Please provide proper value for \"%s\". Permissible range is [0, 1].\n", currentArg); + return 0; + } + providedArgs[0] = 1; + } + else if(providedArgs[0]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + else if(strcmp(currentArg, "FilterSize")==0) + { + if(iter+1 <= nbInputArguments && !providedArgs[1]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr, &filterSize); + if(intErr) + { + return intErr; + } + providedArgs[1] = 1; + if(filterSize!=1 && filterSize!=3 && filterSize!=5 && filterSize!=7) + { + Scierror(999, "Error: Please provide proper value for \"%s\". Permissible values are {1, 3, 5, 7}.\n", currentArg); + return 0; + } + } + else if(providedArgs[1]) + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + else if(strcmp(currentArg, "ROI")==0) + { + if(iter+1 <= nbInputArguments && !providedArgs[2]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isDoubleType(pvApiCtx, piAddr) || isVarComplex(pvApiCtx, piAddr)) + { + Scierror(999, "%s: Wrong type for input argument #%d: A real matrix expected.\n", fname, iter); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &matrixOfRoi); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(iRows!=1 || iCols!=4) + { + Scierror(999, "Incorrect dimension of matrix for argument ROI.\n"); + return 0; + } + providedArgs[2] = 1; + if(matrixOfRoi[0] < 0 || matrixOfRoi[0] > sourceImage.cols || matrixOfRoi[1] < 0 || + matrixOfRoi[1] > sourceImage.rows || matrixOfRoi[2] < 0 || matrixOfRoi[0] + matrixOfRoi[2] > sourceImage.cols + || matrixOfRoi[3] < 0 || matrixOfRoi[1] + matrixOfRoi[3] > sourceImage.rows) + { + Scierror(999, "Error: Please provide proper values for \"%s\".\n", currentArg); + return 0; + } + } + else if(providedArgs[2]) + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + else if(strcmp(currentArg, "SensitivityFactor")==0) + { + if(iter+1 <= nbInputArguments && !providedArgs[3]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr, &sensitivityFactor); + if(intErr) + { + return intErr; + } + providedArgs[3] = 1; + if(sensitivityFactor < 0 || sensitivityFactor > 0.25) + { + Scierror(999, "Error: Please provide proper value for \"%s\". Permissible values are [0, 0.25].\n", currentArg); + return 0; + } + } + else if(providedArgs[3]) + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: \"%s\" name for input argument is not valid.\n", currentArg); + return 0; + } + } + + //------Actual processing------// + dst = Mat::zeros( sourceImage.size(), CV_32FC1 ); + try + { + sourceImage.convertTo(sourceImage, CV_8U); + //(Rect(matrixOfRoi[0], matrixOfRoi[1], matrixOfRoi[2], matrixOfRoi[3]) + cornerHarris(sourceImage, dst, blockSize1, filterSize1, sensitivityFactor1, BORDER_DEFAULT); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + pointCount = dst.rows * dst.cols; + + Mat dst_norm, dst_norm_scaled; + vector loc; + normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() ); + convertScaleAbs( dst_norm, dst_norm_scaled ); + + for( int j = 0; j < dst_norm.rows; j++ ) + { + for( int i = 0; i < dst_norm.cols; i++ ) + { + if( (int) dst_norm.at(j,i) > 200 ) + { + loc.push_back(i); + loc.push_back(j); + } + } + } + + int size1 = loc.size() / 2; + location = (double*) malloc(sizeof(double) * size1 * 2); + metric = (double*) malloc(sizeof(double) * size1); + for(int i = 0; i < size1; i++) + { + location[i] = loc[i]; + location[i + size1] = loc[i + 1]; + metric[i] = dst_norm.at(loc[i + 1],loc[i]); + } + //------Create output arguments------// + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx)+1, size1, 2, location); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx)+2, size1, 1, metric); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfInteger32(pvApiCtx, nbInputArgument(pvApiCtx)+3, 1, 1, &pointCount); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //------Return Arguments------// + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + AssignOutputVariable(pvApiCtx, 2) = nbInputArgument(pvApiCtx)+2; + AssignOutputVariable(pvApiCtx, 3) = nbInputArgument(pvApiCtx)+3; + ReturnArguments(pvApiCtx); + return 0; + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_detectORB.cpp b/sci_gateway/cpp/opencv_detectORB.cpp new file mode 100644 index 0000000..aa9f0bf --- /dev/null +++ b/sci_gateway/cpp/opencv_detectORB.cpp @@ -0,0 +1,636 @@ +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/features2d/features2d.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_detectORB(char *fname, unsigned long fname_len) + { + + // Error management variable + SciErr sciErr; + + //Variables + int i, j; + int intErr; + int iRows1 = 0; + int iCols1 = 0; + + int iRows = 0; + int iCols = 0; + int *piLen = NULL; + int *piAddr = NULL; + char **pstData = NULL; + char *currentArg = NULL; + bool *providedArgs = NULL; + + double edgeThreshold = 0; + double fastThreshold = 0; + double firstLevel = 0; + double maxFeatures = 0; + double nLevels = 0; + double patchSize = 0; + double scaleFactor = 0; + double scoreType = 0; + + int iRet; + + // checking input argument + // 1 : image + // 2 : edgeThreshold + // 3 : fastThreshold + // 4 : firstLevel + // 5 : ROI + // 6 : setMaxFeatures + // 7 : nLevels + // 8 : patchSize + // 9 : scaleFactor + // 10 : scoreType + CheckInputArgument(pvApiCtx, 1, 19); + CheckOutputArgument(pvApiCtx, 1, 1); + + // retrieve image + Mat image; + retrieveImage(image, 1); + + // For the optional arguments + int nbInputArguments = *getNbInputArgument(pvApiCtx); + //sciprint("%d\n",nbInputArguments); + + if((nbInputArguments%2) == 0) + { + Scierror(999, "%d: The number of arguments must be odd\n"); + return 0; + } + + providedArgs = (bool*) malloc(sizeof(bool) * 9); + memset(providedArgs, 0, 9); + + for(int iter = 2; iter <= nbInputArguments; ++iter) + { + sciErr = getVarAddressFromPosition(pvApiCtx, iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + /// Three calls to getMatrixOfString + //First Call + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Second call to get length of string + piLen = (int*) malloc(sizeof(int) * iRows1 * iCols1); + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows1, &iCols1, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // third call + pstData = (char**) malloc(sizeof(char*) * iRows1 * iCols1); + for(int k = 0; k < iRows1 * iCols1; ++k) + { + pstData[k] = (char*) malloc(sizeof(char) * piLen[k] + 1); + } + + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows1, &iCols1, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + currentArg = pstData[0]; + + // getting edgeThreshold + if(strcmp(currentArg, "edgeThreshold") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[0]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + edgeThreshold = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""edgeThreshold"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""edgeThreshold"" is not of type Integer.\n"); + return 0; + } + providedArgs[0] = 1; + } + else if(providedArgs[0]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "fastThreshold") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[1]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + fastThreshold = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""fastThreshold"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""fastThreshold"" is not of type Integer.\n"); + return 0; + } + providedArgs[1] = 1; + } + else if(providedArgs[1]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "firstLevel") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[2]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + firstLevel = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""firstLevel"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""firstLevel"" is not of type Integer.\n"); + return 0; + } + providedArgs[2] = 1; + } + else if(providedArgs[2]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + else if(strcmp(currentArg,"ROI")==0) + { + // val_position=i+1; + + if(providedArgs[3] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, i + 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddr) || isVarComplex(pvApiCtx, piAddr)) + { + Scierror(999,"Enter a List of 4 arguments\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &ROImat); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows*iCols!=4) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + if(ROImat[0]<0 || ROImat[1]<0 || ROImat[2]<0 || ROImat[3]<0) + { + Scierror(999,"Arguments cannot be negative\n"); + return 0; + } + + if(ROImat[0]>image.cols || ROImat[1]>image.rows || ROImat[0]+ROImat[2]>image.cols + || ROImat[1]+ROImat[3]>image.rows) + { + Scierror(999,"Please make sure the arguments are within the image range\n"); + return 0; + } + + providedArgs[3] = 1; + } + + if(strcmp(currentArg, "maxFeatures") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[4]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + maxFeatures = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""maxFeatures"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""maxFeatures"" is not of type Integer.\n"); + return 0; + } + providedArgs[4] = 1; + } + else if(providedArgs[4]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "nLevels") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[5]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + nLevels = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""nLevels"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""nLevels"" is not of type Integer.\n"); + return 0; + } + providedArgs[5] = 1; + } + else if(providedArgs[5]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "patchSize") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[6]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + patchSize = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""patchSize"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""patchSize"" is not of type Integer.\n"); + return 0; + } + providedArgs[6] = 1; + } + else if(providedArgs[6]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "scaleFactor") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[7]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + scaleFactor = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""scaleFactor"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""scaleFactor"" is not of type Integer.\n"); + return 0; + } + providedArgs[7] = 1; + } + else if(providedArgs[7]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + if(strcmp(currentArg, "scoreType") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[8]) + { + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + if(dData == 0 || dData == 1 || dData == 32) + { + Scierror(999, "Error: The input argument ""scoreType"" should be 0, 1 or 32.\n"); + return 0; + } + scoreType = dData; + } + } + else + { + Scierror(999, "Error: The input argument ""scoreType"" is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument ""scoreType"" is not of type Integer.\n"); + return 0; + } + providedArgs[8] = 1; + } + else if(providedArgs[8]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + } + /// End of error check and input get; + + /// Creating model and setting its params; + Ptr orb = ORB::create(); + + /// to store the keypoints of orb detected + vector keyPoints; + + if(providedArgs[0]) + { + orb->setEdgeThreshold(edgeThreshold); + } + if(providedArgs[1]) + { + orb->setFastThreshold(fastThreshold); + } + if(providedArgs[2]) + { + orb->setFirstLevel(firstLevel); + } + + if(providedArgs[4]) + { + orb->setMaxFeatures(maxFeatures); + } + if(providedArgs[5]) + { + orb->setNLevels(nLevels); + } + if(providedArgs[6]) + { + orb->setPatchSize(patchSize); + } + if(providedArgs[7]) + { + orb->setScaleFactor(scaleFactor); + } + if(providedArgs[8]) + { + orb->setScoreType(scoreType); + } + + // Handling ROI argument + if(providedArgs[3]==0) + { + ROImat=(double *)malloc(sizeof(double)*1*4); + ROImat[0]=0; + ROImat[1]=0; + ROImat[2]=image.cols; + ROImat[3]=image.rows; + } + + Rect masker(ROImat[0], ROImat[1], ROImat[2], ROImat[3]); + Mat mask(image.size(), CV_8UC1, Scalar::all(0)); + + // Creating ROI + try + { + mask(masker).setTo(Scalar::all(255)); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + } + + Mat descriptor; + + try + { + image.convertTo(image, CV_8U); + orb->detectAndCompute(image, keyPoints, mask, descriptor); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + int total_keypoints = (int)keyPoints.size(); + + double *key_value = (double*)malloc(sizeof(double) * (int)keyPoints.size() * 2); + + vector< KeyPoint >::iterator it; + for(it = keyPoints.begin(); it != keyPoints.end(); ++it) + { + KeyPoint temp = keyPoints[i]; + + // x coordinate + key_value[i + 0 * total_keypoints] = it->pt.x; + + // y coordinate + key_value[i + 1 * total_keypoints] = it->pt.y; + } + + // Converting descriptor from Mat to double* + int dcols = descriptor.cols; + double *_descriptors = (double*) malloc(sizeof(double) * dcols); + + for(int i = 0; i < dcols; i++) + { + _descriptors[i] = descriptor.at(i); + } + + // Creating output arguments + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 2, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, total_keypoints, 2, key_value); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 2, 1, dcols, _descriptors); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_detectSURFFeatures.cpp b/sci_gateway/cpp/opencv_detectSURFFeatures.cpp new file mode 100644 index 0000000..aca5c07 --- /dev/null +++ b/sci_gateway/cpp/opencv_detectSURFFeatures.cpp @@ -0,0 +1,446 @@ +/*************************************************** +Author : Shashank Shekhar +***************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/features2d/features2d.hpp" +#include +//#include "opencv2/nonfree/features2d.hpp" +#include "opencv2/highgui/highgui.hpp" +//#include "opencv2/nonfree/nonfree.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; +using namespace cv::xfeatures2d; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + //#include "../common.cpp" + +int opencv_detectSURFFeatures(char *fname, unsigned long fname_len) +{ + + SciErr sciErr; + + int *piAddr = NULL; + int *piAddrVal = NULL; + int val_position; + int *piLen = NULL; + int iRows, iCols = 0; + char ** pstData = NULL; + char *currentArg = NULL; + int valOfCA; + int argPresence[4]; + for(int i=0;i<4;i++) + argPresence[i]=0; + + vector myPoints; + + int *LocationList = NULL; + int *OrientationList = NULL; + int *MetricList = NULL; + int *LaplacianList = NULL; + int *ScaleList = NULL; + + double *LocationData = NULL; + double *OrientationData = NULL; + double *MetricData = NULL; + double *LaplacianData = NULL; + double *ScaleData = NULL; + + int noOfarguments = *getNbInputArgument(pvApiCtx); + + CheckInputArgument(pvApiCtx, 1,9); + CheckOutputArgument(pvApiCtx,1,6); + + Mat image; + retrieveImage(image,1); + + if(image.channels()!=1) + { + Scierror(999," Feature is not meant for RGB images\n"); + return 0; + } + +//********************************************* Valid Argument Count Check ***************************************** + + if(noOfarguments%2==0) + { + Scierror(999," Invalid No of Arguments \n"); + return 0; + } + +//********************************************* Optional Input Arguments ***************************************** + + double MetricThreshold = 0; + double NumOctaves = 0; + double NumScaleLevels = 0; + double *ROImat = NULL; + +//********************************************* Retrieval of Name, Value Argument Pair **************************** + + + for(int i=2;i<=noOfarguments;i=i+2) + { + sciErr = getVarAddressFromPosition(pvApiCtx,i,&piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isStringType(pvApiCtx, piAddr)) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + //first call to get rows and columns + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + //second call to retrieve length of each string + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + for(int j = 0 ; j < iRows * iCols ; j++) + { + pstData[j] = (char*)malloc(sizeof(char) * (piLen[j] + 1));//+ 1 for null termination + } + + //third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + currentArg = pstData[0]; + free(pstData); + iRows=0; + iCols=0; + free(piLen); + + if(strcmp(currentArg,"MetricThreshold")==0) + { + + val_position=i+1; + + if(argPresence[0]==1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx,val_position,&piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddrVal) || isVarComplex(pvApiCtx,piAddrVal) || !isScalar(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for MetricThreshold. Please enter a non negative Double value\\n"); + return 0; + } + + getScalarDouble(pvApiCtx, piAddrVal, &MetricThreshold); + + if(MetricThreshold<0) + { + Scierror(999," Invalid Value for MetricThreshold. Please enter a non negative Double value\\n"); + return 0; + } + argPresence[0]=1; + } + else if(strcmp(currentArg,"NumOctaves")==0) + { + val_position=i+1; + + if(argPresence[1]==1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + + sciErr = getVarAddressFromPosition(pvApiCtx,val_position,&piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddrVal) || isVarComplex(pvApiCtx,piAddrVal) || !isScalar(pvApiCtx, piAddrVal)) + { + + Scierror(999," Invalid Value for NumOctaves. Recommended Values are between 1 and 4\n"); + return 0; + } + + getScalarDouble(pvApiCtx, piAddrVal, &NumOctaves); + + if(NumOctaves<1) + { + Scierror(999," Invalid Value for NumOctaves. Recommended Values are between 1 and 4\n"); + return 0; + } + + argPresence[1]=1; + } + else if(strcmp(currentArg,"NumScaleLevels")==0) + { + val_position=i+1; + + if(argPresence[2]==1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx,val_position,&piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddrVal) || isVarComplex(pvApiCtx,piAddrVal) || !isScalar(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for NumScaleLevels. Recommended values are between 3 and 6\n"); + return 0; + } + + getScalarDouble(pvApiCtx, piAddrVal, &NumScaleLevels); + + if(NumScaleLevels<3) + { + Scierror(999," Invalid Value for NumScaleLevels. Please enter an integer value greater than or equal to 3\n"); + return 0; + } + + argPresence[2]=1; + } + else if(strcmp(currentArg,"ROI")==0) + { + val_position=i+1; + + if(argPresence[3]==1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx,val_position,&piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddrVal) || isVarComplex(pvApiCtx, piAddrVal)) + { + Scierror(999,"Enter a List of 4 double arguments\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddrVal, &iRows, &iCols, &ROImat); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows*iCols!=4) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + + if(ROImat[0]<0 || ROImat[1]<0 || ROImat[2]<0 || ROImat[3]<0) + { + sciprint("Arguments cannot be negative\n"); + return 0; + } + + if(ROImat[0]>image.cols || ROImat[1]>image.rows || ROImat[0]+ROImat[2]>image.cols + || ROImat[1]+ROImat[3]>image.rows) + { + Scierror(999,"Please make sure the arguments are within the image range\n"); + return 0; + } + + argPresence[3]=1; + } + else + { + Scierror(999, "Error: \"%s\" name for input argument is not valid.\n", currentArg); + return 0; + } + + } +//********************************************* End of OIA ******************************************************** + + int nOctaveLayers; + + if(argPresence[2]==1) + nOctaveLayers = NumScaleLevels-2; + + if(argPresence[0]==0) + MetricThreshold=100; + if(argPresence[1]==0) + NumOctaves=4; + if(argPresence[2]==0) + nOctaveLayers = 3; + if(argPresence[3]==0) + { + ROImat=(double *)malloc(sizeof(double)*4); + ROImat[0]=0; + ROImat[1]=0; + ROImat[2]=image.cols; + ROImat[3]=image.rows; + } + + Rect masker(ROImat[0], ROImat[1], ROImat[2], ROImat[3]); + + Mat mask(image.size(), CV_8UC1, Scalar::all(0)); + mask(masker).setTo(Scalar::all(255)); + + // SURF my_object(MetricThreshold, NumOctaves, nOctaveLayers); + Ptr detector = SURF::create(MetricThreshold, NumOctaves, nOctaveLayers, 1, false); + + // my_object.operator()(image, mask, myPoints, noArray()); + try + { + image.convertTo(image, CV_8UC1); + detector->detect(image, myPoints); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + int size = myPoints.size(); + +//*************************************************************** Location *************************************************************** + + ScaleData = (double *)malloc(sizeof(double)*size); + OrientationData = (double *)malloc(sizeof(double)*size); + MetricData = (double *)malloc(sizeof(double)*size); + LaplacianData = (double*)malloc(sizeof(double)*size); + + iRows=size; + iCols=2; + int k=0; + + LocationData = (double *)malloc(sizeof(double)*iRows*iCols); + + for(int i=0;i +#include +#include +#include +#include +#include +#include +#include + + +using namespace cv; +using namespace std; +using namespace cv::ximgproc; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_disparity(char *fname, unsigned long fname_len) + { + SciErr sciErr; + + /*----- Local Variables -----*/ + int *piAddr = NULL; + int *piAddrVal = NULL; + int val_position = 0; + int *piLen = NULL; + int iRows = 0, iCols = 0; + char ** pstData = NULL; + char *currentArg = NULL; + int valOfCA = 0; + int argPresence[6]; + for(int i = 0; i < 6; i++) + argPresence[i] = 0; + + /*----- Variables used in procesing -----*/ + Mat left_for_matcher, right_for_matcher; + Mat left_disp,right_disp; + Mat filtered_disp; + //conf_map = Scalar(255); + Rect ROI; + Ptr wls_filter; + int vis_mult = 1.0; + //char *dst_path = "./disparity.jpg" + + /*----- Optional Input Arguments -----*/ + char **method = NULL; + int numDisparities = 160; + int SADWindowSize = 7; + int uniquenessRatio = 0; + int textureThreshold = 507; + int disp12MaxDiff = 1; + + int noOfarguments = *getNbInputArgument(pvApiCtx); + + /*----- Check for input and output arguments -----*/ + CheckInputArgument(pvApiCtx, 2, 14); + CheckOutputArgument(pvApiCtx, 2, 2); + + /*----- Retrieving two images -----*/ + Mat image_1; + retrieveImage(image_1, 1); + image_1.convertTo(image_1, CV_8UC1); + + Mat image_2; + retrieveImage(image_2, 2); + image_2.convertTo(image_2, CV_8UC1); + + if(image_1.channels() != 1) + { + Scierror(999, "Image 1 not a RGB image.\n"); + return 0; + } + + if(image_2.channels() != 1) + { + Scierror(999, "Image 2 not a RGB image.\n"); + return 0; + } + + if(noOfarguments % 2 != 0) + { + Scierror(999," Invalid No of Arguments \n"); + return 0; + } + + /*----- Retrieving Optional Input Arguments -----*/ + for(int i = 3; i <= noOfarguments; i = i + 2) + { + sciErr = getVarAddressFromPosition(pvApiCtx,i,&piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isStringType(pvApiCtx, piAddr)) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + // First call to get rows and columns + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + // Second call to retrieve length of each string + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + for(int j = 0 ; j < iRows * iCols ; j++) + { + pstData[j] = (char*)malloc(sizeof(char) * (piLen[j] + 1));//+ 1 for null termination + } + + // Third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + currentArg = pstData[0]; + free(pstData); + iRows = 0; + iCols = 0; + free(piLen); + + if(strcmp(currentArg, "numDisparities") == 0) + { + val_position = i + 1; + + if(argPresence[0] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, val_position, &piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isIntegerType(pvApiCtx, piAddrVal) || + isVarComplex(pvApiCtx,piAddrVal) || + !isScalar(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for numDisparities. Please enter a non negative Integer value.\n"); + return 0; + } + + getScalarInteger32(pvApiCtx, piAddrVal, &numDisparities); + + if(numDisparities < 0 && numDisparities % 16 != 0) + { + Scierror(999, "Invalid Value for numDisparities. Please enter a non negative Integer value which is divisible by 16.\n"); + return 0; + } + argPresence[0] = 1; + } + + if(strcmp(currentArg, "SADWindowSize") == 0) + { + val_position = i + 1; + + if(argPresence[1] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, val_position, &piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isIntegerType(pvApiCtx, piAddrVal) || + isVarComplex(pvApiCtx,piAddrVal) || + !isScalar(pvApiCtx, piAddrVal)) + { + Scierror(999, "Invalid Value for SADWindowSize. Please enter a non negative Integer value.\n"); + return 0; + } + + getScalarInteger32(pvApiCtx, piAddrVal, &SADWindowSize); + + if(SADWindowSize < 1 && SADWindowSize % 2 == 0) + { + Scierror(999, "Invalid Value for SADWindowSize. Please enter a non negative Integer value, which is odd and greater than 1.\n"); + return 0; + } + argPresence[1] = 1; + } + + if(strcmp(currentArg, "Method") == 0) + { + if(argPresence[2] != 0) + { + Scierror(999,"Method Argument has been called twice\n"); + return 0; + } + + val_position = i + 1; + + sciErr = getVarAddressFromPosition(pvApiCtx, val_position, &piAddrVal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + // Check for Argument type + if(!isStringType(pvApiCtx, piAddrVal)) + { + Scierror(999, "%s: Wrong type of 2nd argument #%d. A string is expected.\n", fname, 1); + return 0; + } + + // Matrix of Stings + sciErr = getMatrixOfString(pvApiCtx, piAddrVal, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + // Second call to retrieve the length of the string + sciErr = getMatrixOfString(pvApiCtx, piAddrVal, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(piLen); + return 0; + } + method = (char**)malloc(sizeof(char*) * iRows * iCols); + for(int j = 0; j < iRows * iCols; j++) + { + method[j] = (char*)malloc(sizeof(char) * (piLen[j] + 1)); + } + + // Third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddrVal, &iRows, &iCols, piLen, method); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(piLen); + free(method); + return 0; + } + argPresence[2] = 1; + } + + if(strcmp(currentArg, "uniquenessRatio") == 0) + { + val_position = i + 1; + + if(argPresence[3] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, val_position, &piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isIntegerType(pvApiCtx, piAddrVal) || + isVarComplex(pvApiCtx,piAddrVal) || + !isScalar(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for uniquenessRatio. Please enter a non negative Integer value.\n"); + return 0; + } + + getScalarInteger32(pvApiCtx, piAddrVal, &uniquenessRatio); + + if(uniquenessRatio < 0) + { + Scierror(999," Invalid Value for uniquenessRatio. Please enter a non negative Integer value.\n"); + return 0; + } + argPresence[3] = 1; + } + + if(strcmp(currentArg, "textureThreshold") == 0) + { + val_position = i + 1; + + if(argPresence[4] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, val_position, &piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isIntegerType(pvApiCtx, piAddrVal) || + isVarComplex(pvApiCtx,piAddrVal) || + !isScalar(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for textureThreshold. Please enter a non negative Integer value.\n"); + return 0; + } + + getScalarInteger32(pvApiCtx, piAddrVal, &textureThreshold); + + if(textureThreshold < 0) + { + Scierror(999," Invalid Value for textureThreshold. Please enter a non negative Integer value.\n"); + return 0; + } + argPresence[4] = 1; + } + + if(strcmp(currentArg, "disp12MaxDiff") == 0) + { + val_position = i + 1; + + if(argPresence[5] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, val_position, &piAddrVal); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isIntegerType(pvApiCtx, piAddrVal) || + isVarComplex(pvApiCtx,piAddrVal) || + !isScalar(pvApiCtx, piAddrVal)) + { + Scierror(999," Invalid Value for disp12MaxDiff. Please enter a non negative Integer value.\n"); + return 0; + } + + getScalarInteger32(pvApiCtx, piAddrVal, &disp12MaxDiff); + + if(disp12MaxDiff < 0) + { + Scierror(999," Invalid Value for disp12MaxDiff. Please enter a non negative Integer value.\n"); + return 0; + } + argPresence[5] = 1; + } + } + + if(argPresence[2] == 0) + { + method = (char**)malloc(sizeof(char*) * 1 * 1); + method[0] = (char*)malloc(sizeof(char) * 13); + strcpy(method[0],"blockMatching"); + } + + /*----- Matching -----*/ + if(strcmp(method[0], "blockMatching") == 0) + { + Ptr left_matcher = StereoBM::create(numDisparities, SADWindowSize); + left_matcher -> setTextureThreshold(textureThreshold); + left_matcher -> setUniquenessRatio(uniquenessRatio); + left_matcher -> setDisp12MaxDiff(disp12MaxDiff); + wls_filter = createDisparityWLSFilter(left_matcher); + Ptr right_matcher = createRightMatcher(left_matcher); + try + { + sciprint("\n%d %d\n", image_1.rows, image_1.cols); + left_matcher -> compute(image_1, image_2,left_disp); + right_matcher -> compute(image_2, image_1, right_disp); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + } + + else if(strcmp(method[0], "semi-blockMatching") == 0) + { + Ptr left_matcher = StereoSGBM::create(0, numDisparities, SADWindowSize); + left_matcher -> setP1(24 * SADWindowSize * SADWindowSize); + left_matcher -> setP2(96 * SADWindowSize * SADWindowSize); + left_matcher -> setPreFilterCap(63); + left_matcher -> setMode(StereoSGBM::MODE_SGBM_3WAY); + left_matcher -> setDisp12MaxDiff(disp12MaxDiff); + left_matcher -> setUniquenessRatio(uniquenessRatio); + wls_filter = createDisparityWLSFilter(left_matcher); + Ptr right_matcher = createRightMatcher(left_matcher); + try + { + left_matcher -> compute(image_1, image_2, left_disp); + right_matcher -> compute(image_2, image_1, right_disp); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + } + + /*----- Filtering -----*/ + int lambda = 8000; + int sigma = 1.5; + wls_filter->setLambda(lambda); + wls_filter->setSigmaColor(sigma); + try + { + wls_filter->filter(left_disp, image_1, filtered_disp, right_disp); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + //Mat conf_map = Mat(left.rows, left.cols, CV_8U); + //conf_map = wls_filter->getConfidenceMap(); + + Mat filtered_disp_vis; + try + { + getDisparityVis(filtered_disp, filtered_disp_vis, vis_mult); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + try + { + left_disp.convertTo(left_disp, CV_8U, 255 / (numDisparities * 16.)); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + // imwrite(dst_path, filtered_disp_vis); + + /*----- Creating output images -----*/ + string tempstring = type2str(filtered_disp_vis.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker, filtered_disp_vis, 1); + free(checker); + + tempstring = type2str(left_disp.type()); + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker, left_disp, 2); + free(checker); + + /*----- Returning output -----*/ + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + AssignOutputVariable(pvApiCtx, 2) = nbInputArgument(pvApiCtx) + 2; + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_filter2D.cpp b/sci_gateway/cpp/opencv_filter2D.cpp new file mode 100644 index 0000000..72725fd --- /dev/null +++ b/sci_gateway/cpp/opencv_filter2D.cpp @@ -0,0 +1,193 @@ +/*************************************************** +Author : Sukul Bagai +**************************************************** +Usage : return_image = filter2D(input_image,"",kernel_matrix,anchor_x,anchor_y,delta); +***************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +using namespace cv; +using namespace std; +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_filter2D(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr=0; + int iRows=0,iCols=0; + int *piLen = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + int *piAddr5 = NULL; + int *piAddr6 = NULL; + char **ddepth = NULL; + int i,j,k; + double *kernel, anchorX, anchorY, delta; + + //checking input argument + CheckInputArgument(pvApiCtx, 6, 6); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + Mat image; + retrieveImage(image,1); + + //for ddepth + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Now, we will retrieve the string from the input parameter. For this, we will require 3 calls + //first call to retrieve dimensions + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + //second call to retrieve length of each string + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + ddepth = (char**)malloc(sizeof(char*) * iRows * iCols); + for(i = 0 ; i < iRows * iCols ; i++) + ddepth[i] = (char*)malloc(sizeof(char) * (piLen[i] + 1));//+ 1 for null termination + //third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, piLen, ddepth); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //for kernel matrix + sciErr = getVarAddressFromPosition(pvApiCtx,3,&piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr3, &iRows, &iCols ,&kernel); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + int n=iRows; + double kernelArray[n][n]; + //assigning values to actual kernelMatrix + for(i=0;i= n || anchorY >=n) + { + sciprint("Invalid anchor point given. Centre point (-1,-1) was used instead"); + anchorY = -1; + anchorX = -1; + } + Mat new_image(image.rows,image.cols,image.type()); + Point pt(anchorX,anchorY); + + int actualddepth; + + if(strcmp(ddepth[0],"CV_8U")==0) + actualddepth=CV_8U; + else if(strcmp(ddepth[0],"CV_16U")==0) + actualddepth=CV_16U; + else if(strcmp(ddepth[0],"CV_16S")==0) + actualddepth=CV_16S; + else if(strcmp(ddepth[0],"CV_32F")==0) + actualddepth=CV_32F; + else if(strcmp(ddepth[0],"CV_64F")==0) + actualddepth=CV_64F; + else + { + sciprint("Invalid type %s used. CV_8U was used instead by default",ddepth[0]); + actualddepth = CV_8U; + } + + //applying function + try + { + image.convertTo(image, CV_8U); + filter2D(image,new_image,actualddepth,kernelMatrix,pt,delta); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + //returning image + string tempstring = type2str(new_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,new_image,1); + free(checker); + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_ftrans2.cpp b/sci_gateway/cpp/opencv_ftrans2.cpp new file mode 100644 index 0000000..3d45ffc --- /dev/null +++ b/sci_gateway/cpp/opencv_ftrans2.cpp @@ -0,0 +1,208 @@ +/******************************************************** +Author: Vinay + +Function: h = ftrans2(b, t) +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +#include +using namespace cv; +using namespace std; + +void rotate180(Mat &m) { + double temp; + for (int i=0; i<(m.rows+1)/2; i++) { + int k = m.cols; + if ((i+1)>=((m.rows+1)/2) && m.rows%2!=0) { + k = (m.cols+1)/2; + } + for (int j=0; j(i, j); + m.at(i, j) = m.at(m.rows-i-1, m.cols-j-1); + m.at(m.rows-i-1, m.cols-j-1) = temp; + } + } + +} + +Mat fftshift(Mat m) { + int a = m.rows/2; + int b = m.cols/2; + Mat r = Mat::zeros(m.size(), m.type()); + for (int i=0; i((i+a)%m.rows, (j+b)%m.cols) = m.at(i, j); + } + } + return r; +} + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_ftrans2(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr = 0; + int iRows=0,iCols=0; + int cRows=0,cCols=0; + int *piAddr = NULL; + int *piAddrNew = NULL; + + //checking input argument + CheckInputArgument(pvApiCtx, 1, 2); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + Mat b, bcpy, t; + Mat P0, P1, P2, h, hh; + + retrieveImage(bcpy, 1); + bcpy.convertTo(b, CV_64F); + + if (b.cols == 1) { + transpose(b, b); + } + else if (b.rows == 1) { + ; + } + else { + sciprint("b at argument 1 expected to be vector"); + return 0; + } + + if (b.cols%2 == 0) { + sciprint("b at argument 1 must be of odd length"); + return 0; + } + + Mat c = b.clone(); + rotate180(c); + + int zeroCount = 0; + double eps = 1.5e-5; + + for (int i=0; i(0, i) - c.at(0, i)) > eps) { + zeroCount = b.cols; + break; + } + if (b.at(0, i) == 0) { + zeroCount++; + } + } + if (zeroCount == b.cols) { + sciprint("b at argument 1 must be nonzero and symmetric"); + return 0; + } + + + if (nbInputArgument(pvApiCtx) == 2) { + Mat tcpy; + retrieveImage(tcpy, 2); + tcpy.convertTo(t, CV_64F); + + } + else { + Mat tcpy; + double data[3][3] = {{1.0/8, 2.0/8, 1.0/8},{2.0/8, -4.0/8, 2.0/8},{1.0/8, 2.0/8, 1.0/8}}; + tcpy = Mat(3, 3, CV_64F, &data); + t = tcpy.clone(); + } + + rotate180(b); + + fftshift(b).copyTo(b); + + rotate180(b); + + int inset1 = (t.rows-1)/2; + int inset2 = (t.cols-1)/2; + int n = (b.cols-1)/2; + + Mat a = Mat::zeros(1, n+1, CV_64F); + a.at(0, 0) = b.at(0,0); + for (int i=1; i<=n; i++) { + a.at(0, i) = 2*b.at(0, i); + } + + P0 = Mat::ones(1, 1, CV_64F); + t.copyTo(P1); + h = (P1*a.at(0, 1)); + + h.at(inset1,inset2) = h.at(inset1,inset2) + a.at(0, 0); + + for (int i=2; i<=n; i++) { + Mat src = t.clone(); + + int additionalRows = P1.rows-1, additionalCols = P1.cols-1; + + copyMakeBorder(src, src, (additionalRows+1)/2, additionalRows/2, (additionalCols+1)/2, additionalCols/2, BORDER_CONSTANT, Scalar(0)); + + Point anchor(P1.cols - P1.cols/2 - 1, P1.rows - P1.rows/2 - 1); + int borderMode = BORDER_CONSTANT; + Mat P11; + try + { + flip(P1, P11,-1); + filter2D(src, P2, src.depth(), P11, anchor, 0, borderMode); + } + catch(Exception &e) + { + sciprint("%s", e.what()); + return 0; + } + + P2 = P2 * 2; + + for (int x=0; x(x + 2*inset1, y+ 2*inset2) = P2.at(x + 2*inset1, y+ 2*inset2) - P0.at(x, y); + } + } + h.copyTo(hh); + h = (P2*a.at(0, i)); + for (int x=0; x(x + inset1, y + inset2) = h.at(x + inset1, y + inset2) + hh.at(x, y); + } + } + + P1.copyTo(P0); + P2.copyTo(P1); + + } + + rotate180(h); + + + Mat hcopy; + h.copyTo(hcopy); + + string tempstring = type2str(hcopy.type()); + char *imtype; + imtype = (char *)malloc(tempstring.size() + 1); + memcpy(imtype, tempstring.c_str(), tempstring.size() + 1); + returnImage(imtype,hcopy,1); + free(imtype); + + + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} + diff --git a/sci_gateway/cpp/opencv_getParamsEM.cpp b/sci_gateway/cpp/opencv_getParamsEM.cpp new file mode 100644 index 0000000..67da458 --- /dev/null +++ b/sci_gateway/cpp/opencv_getParamsEM.cpp @@ -0,0 +1,214 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/features2d.hpp" +#include "opencv2/xfeatures2d.hpp" +#include "opencv2/ml.hpp" +#include "opencv2/opencv.hpp" + + +using namespace cv; +using namespace cv::xfeatures2d; +using namespace std; +using namespace cv::ml; + + +inline bool file_exists_check(const std::string& name) +{ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + int opencv_getParamsEM(char *fname, unsigned long fname_len) + { + SciErr sciErr; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + char **classifierDescription = NULL; + int classifierDescriptionCount; + + double nClusters = 0; + Mat means; + Mat weights; + double *_means; + double *_weights; + + /*------ Check number of parameters ------*/ + CheckInputArgument(pvApiCtx, 1, 1); + CheckOutputArgument(pvApiCtx, 1, 1); + + /*------ Get input arguments ------*/ + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + /*----- Extracting object type and checking if type is classifier -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"EMClassifier"))) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + /*----- Extracting classifier location from classifier object -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for classifier argument."); + return 0; + } + string classifierLocation = string(pstData[0]); + + if(!file_exists_check(classifierLocation)) + { + Scierror(999, "Error: Input "".yml"" File not found in the pwd.\n"); + return 0; + } + + Ptr em = Algorithm::load(classifierLocation); + + try + { + if(!em->isTrained()) + { + Scierror(999,"\nEM Model not trained\n"); + return 0; + } + nClusters = em->getClustersNumber(); + + means = em->getMeans(); + // Converting from type matrix to double + _means = (double*) malloc(means.cols * sizeof(double)); + for(int i = 0; i < means.cols; i++) + { + _means[i] = means.at(i); + } + + weights = em->getWeights(); + // Converting from type matrix to double + _weights = (double*) malloc(weights.cols * sizeof(double)); + for(int i = 0; i < weights.cols; i++) + { + _weights[i] = weights.at(i); + } + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + /*----- Creating output arguments -----*/ + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 6, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, 1, 1, &nClusters); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 2, 1, means.cols, _means); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 3, 1, weights.cols, _weights); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + /*------ Return Arguments ------*/ + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_getParamsKNN.cpp b/sci_gateway/cpp/opencv_getParamsKNN.cpp new file mode 100644 index 0000000..d5457f7 --- /dev/null +++ b/sci_gateway/cpp/opencv_getParamsKNN.cpp @@ -0,0 +1,207 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/features2d.hpp" +#include "opencv2/xfeatures2d.hpp" +#include "opencv2/ml.hpp" +#include "opencv2/opencv.hpp" + + +using namespace cv; +using namespace cv::xfeatures2d; +using namespace std; +using namespace cv::ml; + + +inline bool file_exists_check(const std::string& name) +{ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + int opencv_getParamsKNN(char *fname, unsigned long fname_len) + { + SciErr sciErr; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + char **classifierDescription = NULL; + int classifierDescriptionCount; + + char *algoType = NULL; + double k = 0; + double emax = 0; + + /*------ Check number of parameters ------*/ + CheckInputArgument(pvApiCtx, 1, 1); + CheckOutputArgument(pvApiCtx, 1, 1); + + /*------ Get input arguments ------*/ + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + /*----- Extracting object type and checking if type is classifier -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1)); //+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"KNNClassifier"))) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + /*----- Extracting classifier loacation from classifier object -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for classifier argument."); + return 0; + } + string classifierLocation = string(pstData[0]); + + if(!file_exists_check(classifierLocation)) + { + Scierror(999, "Error: Input "".yml"" File not found in the pwd.\n"); + return 0; + } + + /*----- Getting all the parameters -----*/ + try + { + Ptr knearest = Algorithm::load(classifierLocation); + if(!knearest->isTrained()) + { + Scierror(999,"\nKNN Model not trained\n"); + return 0; + } + int a = knearest->getAlgorithmType(); + if(a == 1) + { + algoType = "BRUTE_FORCE"; + } + else + { + algoType = "KDTREE"; + } + k = knearest->getDefaultK(); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + /*------ Create output arguments ------*/ + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 3, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, + 1, 1, 1, &algoType); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, + 2, 1, 1, &k); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 3, 1, 1, &emax); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + /*------ Return Arguments ------*/ + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_getParamsLR.cpp b/sci_gateway/cpp/opencv_getParamsLR.cpp new file mode 100644 index 0000000..6fd3335 --- /dev/null +++ b/sci_gateway/cpp/opencv_getParamsLR.cpp @@ -0,0 +1,254 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/features2d.hpp" +#include "opencv2/xfeatures2d.hpp" +#include "opencv2/ml.hpp" +#include "opencv2/opencv.hpp" + + +using namespace cv; +using namespace cv::xfeatures2d; +using namespace std; +using namespace cv::ml; + + +inline bool file_exists_check(const std::string& name) +{ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + int opencv_getParamsLR(char *fname, unsigned long fname_len) + { + SciErr sciErr; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + char **classifierDescription = NULL; + int classifierDescriptionCount; + + double iterations = 0; + double learningRate = 0; + double miniBatchSize = 0; + char *regularization = NULL; + char *trainMethod = NULL; + Mat glm; + double *_glm; + + /*------ Check number of parameters ------*/ + CheckInputArgument(pvApiCtx, 1, 1); + CheckOutputArgument(pvApiCtx, 1, 1); + + /* ------Get input arguments------ */ + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + /*----- Extracting object type and checking if type is classifier -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"LRClassifier"))) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + /*----- Extracting classifier location from classifier object -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for classifier argument."); + return 0; + } + string classifierLocation = string(pstData[0]); + + /*----- Check if .yml file is in pwd -----*/ + if(!file_exists_check(classifierLocation)) + { + Scierror(999, "Error: Input "".yml"" File not found in the pwd.\n"); + return 0; + } + + /*------ Processing steps -----*/ + try + { + Ptr lr = Algorithm::load(classifierLocation); + if(!lr->isTrained()) + { + Scierror(999,"\nLR Model not trained\n"); + return 0; + } + iterations = lr->getIterations(); + learningRate = lr->getLearningRate(); + + int reg = lr->getRegularization(); + if(reg == -1) + { + regularization = "REG_DISABLED"; + } + else if(reg == 0) + { + regularization = "REG_L1"; + } + else + { + regularization = "REG_L2"; + } + miniBatchSize = lr->getMiniBatchSize(); + + int tm = lr->getTrainMethod(); + if(tm == 0) + { + trainMethod = "BATCH"; + } + else + { + trainMethod = "MINI_BATCH"; + } + + glm = lr->get_learnt_thetas(); + + // Converting learnt thetas matrix from type matrix to double. + _glm = (double*) malloc(glm.cols * sizeof(double)); + for(int i = 0; i < glm.cols; i++) + { + _glm[i] = glm.at(i); + } + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + /*----- Creating Output Arguments ------*/ + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 6, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, 1, 1, &iterations); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 2, 1, 1, &learningRate); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 3, 1, 1, &miniBatchSize); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 4, 1, 1, ®ularization); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 5, 1, 1, &trainMethod); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 6, 1, glm.cols, _glm); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + /*------ Return Arguments ------*/ + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_graydiffweight.cpp b/sci_gateway/cpp/opencv_graydiffweight.cpp new file mode 100644 index 0000000..6bfd752 --- /dev/null +++ b/sci_gateway/cpp/opencv_graydiffweight.cpp @@ -0,0 +1,97 @@ +/******************************************************** +Authors: Dhruti Shah +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + int opencv_graydiffweight(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr = 0; + int iRows=0,iCols=0; + int *piAddr = NULL; + int *piAddrNew = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + int *piAddr5 = NULL; + int i,j,k; + double refGrayVal; + + //checking input argument + CheckInputArgument(pvApiCtx, 2, 2); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + + Mat image; + retrieveImage(image, 1); + //cvtColor( image, image, CV_BGR2GRAY ); + + //for value of refGrayVal + sciErr = getVarAddressFromPosition(pvApiCtx,2,&piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr2, &refGrayVal); + if(intErr) + { + return intErr; + } + + try + { + image.convertTo(image, CV_8U); + } + catch(Exception &e) + { + sciprint("%s", e.what()); + return 0; + } + + double value1, value2; + Mat new_image = Mat::zeros(image.size(),image.type()); + for(int i=0; i(i, j); + value2 = abs(value1 - refGrayVal); + new_image.at(i, j) = value2; + } + } + + string tempstring = type2str(new_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,new_image,1); + free(checker); + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} + diff --git a/sci_gateway/cpp/opencv_imabsdiff.cpp b/sci_gateway/cpp/opencv_imabsdiff.cpp new file mode 100644 index 0000000..1327fe1 --- /dev/null +++ b/sci_gateway/cpp/opencv_imabsdiff.cpp @@ -0,0 +1,59 @@ +/******************************************************** +Function :imabsdiff +Syntax :C=imabsdiff(A,B) +Author : Tess Zacharias +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +#include "string.h" +using namespace cv; +using namespace std; +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + int opencv_imabsdiff(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + Mat A,B,C; + CheckInputArgument(pvApiCtx, 2, 2); + CheckOutputArgument(pvApiCtx, 1, 1) ; + retrieveImage(A,1); + retrieveImage(B,2); + Size s1=A.size(); + Size s2=B.size(); + if(s1!=s2) + { + sciprint("\nBoth input should be same size"); + return 0; + } + try + { + absdiff(A,B,C); + } + catch(Exception &e) + { + sciprint("%s", e.what()); + return 0; + } + int temp = nbInputArgument(pvApiCtx) + 1; + string tempstring = type2str(C.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,C,1); + free(checker); + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + ReturnArguments(pvApiCtx); + return 0; + } +} diff --git a/sci_gateway/cpp/opencv_imboxfilt3.cpp b/sci_gateway/cpp/opencv_imboxfilt3.cpp new file mode 100644 index 0000000..deb8862 --- /dev/null +++ b/sci_gateway/cpp/opencv_imboxfilt3.cpp @@ -0,0 +1,140 @@ +/*************************************************** +Author : Yash S. Bhalgat +**************************************************** +Usage : + 1) box_filtered_image = imboxfilt3(input_img); + In this usage, the default filter size of 3x3 is used. + + 2) box_filtered_image = imboxfilt3(input_img, filter_height, filter_width); + +Example : + img = imread("lena.jpg"); + imshow(img); + box_filtered_img = imboxfilt3(img, 9, 9); + imshow(box_filtered_img); +***************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_imboxfilt3(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr = 0; + int iRows=0,iCols=0; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int i,j,k; + + //Default filter size + double filter_height = 3; + double filter_width = 3; + + //checking input argument + CheckInputArgument(pvApiCtx, 1, 3); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + int inputarg = *getNbInputArgument(pvApiCtx); + + + Mat image; + retrieveImage(image,1); + + + if(inputarg >= 2){ + //for value of filter_height + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr2, &filter_height); + if(intErr) + return intErr; + + //for value of filter_width + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr3, &filter_width); + if(intErr) + return intErr; + } + + + //taking the cases which can lead to an error + Mat filtered_image(image.rows,image.cols,image.type()); + + if(filter_height < 0) + { + sciprint("Positive Value Required for Height. 3 value was used instead"); + filter_height = 3; + } + if(filter_width < 0) + { + sciprint("Positive Value Required for Width. 3 value was used instead"); + filter_width = 3; + } + if((int)filter_height % 2 == 0) + { + filter_height += 1; + sciprint("Odd Value Required for Height. %f value was used instead",&filter_height); + } + if((int)filter_width % 2 == 0) + { + filter_width += 1; + sciprint("Odd Value Required for Width. %f value was used instead",&filter_width); + } + + //temporary size variable, to use in function + Size sz(filter_height, filter_width); + + //opencv function called + //if both filter_size is not given, default value of 3x3 is used + try + { + boxFilter(image, filtered_image, -1, sz); + } + catch(Exception &e) + { + sciprint("%s", e.what()); + return 0; + } + + //returning image + string tempstring = type2str(filtered_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,filtered_image,1); + free(checker); + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_imcontrast.cpp b/sci_gateway/cpp/opencv_imcontrast.cpp new file mode 100644 index 0000000..52113da --- /dev/null +++ b/sci_gateway/cpp/opencv_imcontrast.cpp @@ -0,0 +1,99 @@ +/******************************************************** +Author: Sukul Bagai +********************************************************/ +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +using namespace cv; +using namespace std; +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "../common.h" + + int opencv_imcontrast(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr; + int iRows=0,iCols=0; + int *piAddr = NULL; + int *piAddrNew = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int i,j,k; + double alpha, beta; + + //checking input argument + CheckInputArgument(pvApiCtx, 3, 3); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + + Mat image; + retrieveImage(image, 1); + + //for value of alpha + sciErr = getVarAddressFromPosition(pvApiCtx,2,&piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr2, &alpha); + if(intErr) + { + return intErr; + } + + //for value of beta + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr3, &beta); + if(intErr) + { + return intErr; + } + + + //we copy the original image into the new_image, and change values of each pixel using value of alpha and beta given by the user + Mat new_image = Mat::zeros(image.size(), image.type()); + + //changes the attributes of each individual pixel + 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(y,x)[c] = + saturate_cast(alpha * (image.at(y, x)[c]) + beta); + } + } + } + + + string tempstring = type2str(new_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,new_image,1); + free(checker); + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + +} +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_imcrop.cpp b/sci_gateway/cpp/opencv_imcrop.cpp new file mode 100644 index 0000000..c577f97 --- /dev/null +++ b/sci_gateway/cpp/opencv_imcrop.cpp @@ -0,0 +1,138 @@ +/******************************************************** +Author: Sukul Bagai +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +using namespace cv; +using namespace std; +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_imcrop(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr = 0; + int iRows=0,iCols=0; + int *piAddr = NULL; + int *piAddrNew = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + int *piAddr5 = NULL; + int i,j,k; + double x, y, width, height; + + //checking input argument + CheckInputArgument(pvApiCtx, 5, 5); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + Mat image; + retrieveImage(image, 1); + + //for value of top-left x-coordinate + sciErr = getVarAddressFromPosition(pvApiCtx,2,&piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr2, &x); + if(intErr) + { + return intErr; + } + + //for value top-left y-coordinate + sciErr = getVarAddressFromPosition(pvApiCtx,3,&piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr3, &y); + if(intErr) + { + return intErr; + } + + //for value of width + sciErr = getVarAddressFromPosition(pvApiCtx,4,&piAddr4); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr4, &width); + if(intErr) + { + return intErr; + } + + //for value of height + sciErr = getVarAddressFromPosition(pvApiCtx,5,&piAddr5); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr5, &height); + if(intErr) + { + return intErr; + } + + if(x>=image.cols || y>=image.rows || x<0 || y<0) + { + sciprint("Invalid x or y value\n"); + return 0; + } + if(width<=0 || height<=0 || x+width > image.cols || y+height > image.rows) + { + sciprint("Invalid width or height value\n"); + return 0; + } + //defining a temporary rectangle, that denotes the area that has to be cropped into the new image + Rect myROI(x, y, width, height); + + // Crop the full image to that image contained by the rectangle myROI + // Note that this doesn't copy the data + Mat croppedRef(image, myROI); + + Mat cropped; + // Copy the data into new matrix + try + { + croppedRef.copyTo(cropped); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + string tempstring = type2str(cropped.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,cropped,1); + free(checker); + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_imextendedmax.cpp b/sci_gateway/cpp/opencv_imextendedmax.cpp new file mode 100644 index 0000000..92a7809 --- /dev/null +++ b/sci_gateway/cpp/opencv_imextendedmax.cpp @@ -0,0 +1,119 @@ +/******************************************************** +Author: Vinay Bhat +******************************************************** +Usage: return_image = imextendedmax(input_image, h) +Example: + im = imextendedmax(image, 80) +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +using namespace cv; +using namespace std; +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + void imextendedmax_imreconstruct(Mat, Mat, Mat&); + + int opencv_imextendedmax(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr = 0; + int *piAddr = NULL; + double h; + + //checking input argument + CheckInputArgument(pvApiCtx, 2, 2); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + // Get the input image from the Scilab environment + Mat image; + retrieveImage(image, 1); + + // Get the address of 2nd argument, the H-Maxima transform scalar + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Get the H-Maxima transform scalar + intErr = getScalarDouble(pvApiCtx, piAddr, &h); + if(intErr) + { + return intErr; + } + + if (h < 0) + { + sciprint("Please enter a nonnegative scalar for H-maxima transform.\n"); + return 0; + } + + Mat gray_image, dst, fin_image, m, m2; + // cvtColor(image, gray_image, CV_BGR2GRAY); + try + { + image.convertTo(image, CV_8U); + max((image - h), 0, m); + imextendedmax_imreconstruct(image, m, dst); + subtract(dst, 1, m2); + imextendedmax_imreconstruct(dst, m2, m); + subtract(dst, m, m2); + } + catch(Exception &e) + { + sciprint("%s", e.what()); + return 0; + } + + fin_image = m2 * 255; + + string tempstring = type2str(fin_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker, fin_image, 1); + free(checker); + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + } + + void imextendedmax_imreconstruct(Mat g, Mat f, Mat &dest) + { + Mat m0, m1, m; + m1 = f; + do + { + m0 = m1.clone(); + try + { + dilate(m0, m, Mat()); + min(g, m, m1); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return; + } + + } while(countNonZero(m1 != m0) != 0); + dest = m1.clone(); + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_imfindcircles.cpp b/sci_gateway/cpp/opencv_imfindcircles.cpp new file mode 100644 index 0000000..99b7655 --- /dev/null +++ b/sci_gateway/cpp/opencv_imfindcircles.cpp @@ -0,0 +1,155 @@ +/******************************************************** +Function: imfindcircles +Syntax: B = imfindcircles(A) +Author: Tess Zacharias +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_imfindcircles(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int intErr = 0; + int *piAddrNew = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + Mat src_gray, image; + double Rmin, Rmax; + + //checking input argument + CheckInputArgument(pvApiCtx, 3, 3); + CheckOutputArgument(pvApiCtx, 1, 2) ; + retrieveImage(image, 1); + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr2, &Rmin); + if(intErr) + { + return intErr; + } + if(Rmin != round(Rmin) || Rmin <= 0) + { + sciprint("The value of minium Radius must be an integer\n"); + return 0; + } + if(Rmin < 5) + { + sciprint("The value of minium Radius too small\n"); + return 0; + } + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr3, &Rmax); + if(intErr) + { + return intErr; + } + if(Rmax != round(Rmax) || Rmax <= 0) + { + sciprint("The value of maximum Radius must be an integer\n"); + return 0; + } + + try + { + GaussianBlur(image, image, Size(9, 9), 2, 2); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + vector circles; + try + { + image.convertTo(image, CV_8U); + HoughCircles(image, circles, CV_HOUGH_GRADIENT, 2, 10, 200, 100, Rmin, Rmax); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + if(circles.size() == 0) + { + Scierror(999, "\nNo circles of the given range of radii found in image.\n"); + return 0; + } + + int k = circles.size(); + double *radius = NULL; + radius = ( double *)malloc(sizeof(double) * k); + double *c1 = NULL; + c1 = (double *)malloc(sizeof(double) * k); + double *c2 = NULL; + c2 = ( double *)malloc(sizeof(double) * k); + + for(size_t i= 0; i < circles.size(); i++ ) + { + c1[i] = cvRound(circles[i][0]); + c2[i] = cvRound(circles[i][1]); + radius[i] = cvRound(circles[i][2]); + } + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 2, &piAddrNew); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddrNew, 1, 1, k, c1); + free(c1); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddrNew, 2, 1, k, c2); + free(c2); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + if(Lhs == 2) + { + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) +2, 1, k, radius); + free(radius); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + AssignOutputVariable(pvApiCtx, 2) = nbInputArgument(pvApiCtx) + 2; + } + ReturnArguments(pvApiCtx); + return 0; + } +} + diff --git a/sci_gateway/cpp/opencv_imwrite.cpp b/sci_gateway/cpp/opencv_imwrite.cpp new file mode 100644 index 0000000..84c4e77 --- /dev/null +++ b/sci_gateway/cpp/opencv_imwrite.cpp @@ -0,0 +1,93 @@ +/******************************************************** +Author: Sukul Bagai +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_imwrite(char *fname, unsigned long fname_len) + { + + SciErr sciErr; + int iRows = 0,iCols = 0; + int *piAddr = NULL; + int *piAddr1 = NULL; + int *piLen = NULL; + char **pstData = NULL; + int i, j, k; + + //checking input argument + CheckInputArgument(pvApiCtx, 2, 2); + //CheckOutputArgument(pvApiCtx, 0, 0) ; + Mat image; + retrieveImage(image, 1); + + //Now, retriving path + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr1); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //first call to retrieve dimensions + sciErr = getMatrixOfString(pvApiCtx, piAddr1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + //second call to retrieve length of each string + sciErr = getMatrixOfString(pvApiCtx, piAddr1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + for(int i = 0 ; i < iRows * iCols ; i++) + { + pstData[i] = (char*)malloc(sizeof(char) * (piLen[i] + 1));//+ 1 for null termination + } + //third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //image path will contain the path where the image has to be written + string image_path = pstData[0]; + + //writes to the path + try + { + imwrite(image_path, image); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + return 0; + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_integralFilter.cpp b/sci_gateway/cpp/opencv_integralFilter.cpp new file mode 100644 index 0000000..eaaa7a8 --- /dev/null +++ b/sci_gateway/cpp/opencv_integralFilter.cpp @@ -0,0 +1,252 @@ +/*************************************************** +Author : Tanmay Chaudhari + ***************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + // #include "../common.h" + // #include "../common.cpp" + + int opencv_integralFilter(char *fname, unsigned long fname_len) + { + //Error management variable + SciErr sciErr; + + //Variable declaration + int i, j, k; + int iType = 0; + int iComplex = 0; + int rowsOfintImage = 0; + int colsOfintImage = 0; + int rowsOfBbox = 0; + int rowsOfWeights = 0; + int colsOfBbox = 0; + int colsOfWeights = 0; + int rowsOfFilter = 0; + int colsOfFilter = 0; + int sR = 0; + int sC = 0; + int eR = 0; + int eC = 0; + int *piAddr = NULL; + int *outSize = NULL; + double bboxSum = 0; + double *integralFilter = NULL; + double *intImage = NULL; + double *bbox = NULL; + double *weights = NULL; + double *filterSize = NULL; + + //Check input output argument + checkInputArgument(pvApiCtx, 4, 4); + checkOutputArgument(pvApiCtx, 1, 1); + + //Get variable address of the first input arguent + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Check type + sciErr = getVarType(pvApiCtx, piAddr, &iType); + if(sciErr.iErr || iType != sci_matrix) + { + printError(&sciErr, 0); + return 0; + } + + //Get complexity + iComplex = isVarComplex(pvApiCtx, piAddr); + + //Check complexity + if(iComplex) + { + Scierror(999, "%s: Wrong type for input argument: A complex number is not expected.\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &rowsOfintImage, &colsOfintImage, &intImage); + if(sciErr.iErr || rowsOfintImage == 0 || colsOfintImage == 0) + { + printError(&sciErr, 0); + return 0; + } + + //Get variable address of the second input arguent + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Check type + sciErr = getVarType(pvApiCtx, piAddr, &iType); + if(sciErr.iErr || iType != sci_matrix) + { + printError(&sciErr, 0); + return 0; + } + + //Get complexity + iComplex = isVarComplex(pvApiCtx, piAddr); + + //Check complexity + if(iComplex) + { + Scierror(999, "%s: Wrong type for input argument: A complex number is not expected.\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &rowsOfBbox, &colsOfBbox, &bbox); + if(sciErr.iErr || colsOfBbox != 4 || rowsOfBbox == 0) + { + printError(&sciErr, 0); + return 0; + } + + //Get variable address of the third input arguent + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Check type + sciErr = getVarType(pvApiCtx, piAddr, &iType); + if(sciErr.iErr || iType != sci_matrix) + { + printError(&sciErr, 0); + return 0; + } + + //Get complexity + iComplex = isVarComplex(pvApiCtx, piAddr); + + //Check complexity + if(iComplex) + { + Scierror(999, "%s: Wrong type for input argument: A complex number is not expected.\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &rowsOfWeights, &colsOfWeights, &weights); + if(sciErr.iErr || colsOfWeights == 0 || rowsOfWeights != 1 || colsOfWeights != rowsOfBbox) + { + printError(&sciErr, 0); + return 0; + } + + //Get variable address of the fourth input arguent + sciErr = getVarAddressFromPosition(pvApiCtx, 4, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Check type + sciErr = getVarType(pvApiCtx, piAddr, &iType); + if(sciErr.iErr || iType != sci_matrix) + { + printError(&sciErr, 0); + return 0; + } + + //Get complexity + iComplex = isVarComplex(pvApiCtx, piAddr); + + //Check complexity + if(iComplex) + { + Scierror(999, "%s: Wrong type for input argument: A complex number is not expected.\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &rowsOfFilter, &colsOfFilter, &filterSize); + if(sciErr.iErr || colsOfFilter != 2 || rowsOfFilter != 1) + { + printError(&sciErr, 0); + return 0; + } + + outSize = (int*)malloc(sizeof(int) * 2); + if(filterSize[0] != 0 && filterSize[1] != 0) + { + outSize[0] = rowsOfintImage - filterSize[0]; + outSize[1] = colsOfintImage - filterSize[1]; + } + else + { + outSize[0] = rowsOfintImage - 1; + outSize[1] = colsOfintImage - 1; + } + + if(outSize[0] <= 0 || outSize[1] <= 0) + outSize[0] = outSize[1] = 0; + + integralFilter = (double*)malloc(sizeof(double) * outSize[0] * outSize[1]); + + for( i = 0; i < outSize[0] * outSize[1]; i++) + integralFilter[i] = 0; + + for( i = 1; i <= outSize[1]; i++) + { + for( j = 1; j <= outSize[0]; j++) + { + for( k = 0; k < rowsOfBbox; k++) + { + sR = j + bbox[1 * rowsOfBbox + k] - 1; + sC = i + bbox[0 * rowsOfBbox + k] - 1; + eR = sR + bbox[3 * rowsOfBbox + k]; + eC = sC + bbox[2 * rowsOfBbox + k]; + + bboxSum = intImage[(eC - 1) * rowsOfintImage + (eR - 1)] - intImage[(sC - 1) * rowsOfintImage + (eR - 1)]; + bboxSum -= intImage[(eC - 1) * rowsOfintImage + (sR - 1)]; + bboxSum += intImage[(sC - 1) * rowsOfintImage + (sR - 1)]; + + integralFilter[(j - 1) * outSize[1] + (i - 1)] = integralFilter[(j - 1) * outSize[1] + (i - 1)] + weights[k] * bboxSum; + } + } + } + + //Creating list to store integral filter in it + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 1, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, outSize[0], outSize[1], integralFilter); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Return output arguments + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + ReturnArguments(pvApiCtx); + + return 0; + } + /* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_isFilter.cpp b/sci_gateway/cpp/opencv_isFilter.cpp new file mode 100644 index 0000000..55cf7c4 --- /dev/null +++ b/sci_gateway/cpp/opencv_isFilter.cpp @@ -0,0 +1,294 @@ +/********************************************************************************* +*Author : Kevin George +* +*-> To execute, isfilter("Data",..,"Size",..) +* +* +*********************************************************************************/ +#include +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/features2d/features2d.hpp" +#include +#include +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_isFilter(char *fname, unsigned long fname_len) + { + //-> Error Management variables + SciErr sciErr; + int intErr=0; + + //-> Address of Various Arguments + int *piAddr = NULL; + + //-> Local variables + double size; + double *data = NULL; + + Mat s; + Mat u; + Mat v; + + int num_InputArgs; //-> gives total number of arguments + int iRows, iCols; + int *piLen = NULL; + char **pstData = NULL; //-> why double pointer?? and what is it + char *currentArg = NULL; //-> Stores current string representing 'name' of name,value pair arguments + bool *providedArgs = NULL; //-> Used to check that optional argument is not entered more than once + + //-> Checks the number of arguments + //-> pvApiCtx is a Scilab environment pointer + //-> Checks number of input and output arguments + CheckInputArgument(pvApiCtx, 4, 4); + CheckOutputArgument(pvApiCtx, 1, 1); + + //-> Count number of input arguments + num_InputArgs = *getNbInputArgument(pvApiCtx); + + providedArgs = (bool*) malloc(sizeof(bool) * 2); + +//***************************************************** Getting Input Arguments ************************************************************* + for(int iter = 1; iter <= num_InputArgs; iter++) + { + //-> Getting address of next argument + sciErr = getVarAddressFromPosition(pvApiCtx, iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //-> Extracting name of next argument takes three calls to getMatrixOfString + //-> First call to get rows and columns + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + //-> Second call to retrieve length of each string + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + //-> Third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + currentArg = pstData[0]; + free(pstData); + iRows=0; + iCols=0; + free(piLen); + + + +//****************************************************** Name,Value - Data ***************************************************************** + + if(strcmp(currentArg, "Data")==0) + { + if(iter+1<= num_InputArgs && !providedArgs[0]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &data); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + /*if(iRows*iCols!=) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } */ + + providedArgs[0] = 1; + } + + else if(providedArgs[0]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + + } + +//****************************************************** Name,Value - Size ***************************************************************** + else if(strcmp(currentArg, "Size")==0) + { + if(iter+1<= num_InputArgs && !providedArgs[1]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + intErr = getScalarDouble(pvApiCtx, piAddr, &size); + if(intErr) + { + return intErr; + } + + //-> Checking if values are in proper range. Same for all optional arguments + if( size < 0) + { + Scierror(999," Invalid Value for NumPyramidLevels. Please enter a non negative Double value\\n"); + return 0; + } + providedArgs[1] = 1; + } + + else if(providedArgs[1]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + + } + + } +//***************************************************** Actual Processing ************************************************************* + + int size2 = int(size); + float *kdata = new float[size2*size2]; + + for(int i = 0;i(i, j); + if(s.at(i, j) != 0) + count++; + } + } + + double *_u = (double *) malloc(u.rows * u.cols * sizeof(double)); + for(int i = 0; i < u.rows; i++) + { + for(int j = 0; j < u.cols; j++) + { + _u[(i * u.rows) + j] = u.at(i, j); + } + } + + double ans = -1; + if (count == 1) + { + sciprint("\nFilter is seperable\n"); + ans = 1; + } + + else + { + sciprint("\nFilter is not seperable\n"); + ans = 0; + } + + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 3, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, 1, 1, &ans); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(_s != NULL) + { + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 2, s.rows, s.cols, _s); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + } + + if(_u != NULL) + { + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 3, u.rows, u.cols, _u); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + } + + //------Return Arguments------// + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_matchFeatures.cpp b/sci_gateway/cpp/opencv_matchFeatures.cpp new file mode 100644 index 0000000..c867f07 --- /dev/null +++ b/sci_gateway/cpp/opencv_matchFeatures.cpp @@ -0,0 +1,592 @@ +/******************************************************************************************************************************************************************************************************** +* Author: Umang Agrawal & Siddhant Narang * +* Code: matchFeatures.cpp * +* Function Format: [ index_Pairs_of_Matched_fetaures Metric ] = matchFeatures( feature_Vector_1, feature_Vector_2, Optional Arguments ) * +* Optional Arguments: Name Value * +* 'Method' [ 'Exhaustive' : 'Brute Force Matching', 'Approximate' : FANN Based Matching' ] * +* 'Metric' [ 'SSD', 'SAD', 'Hamming', 'Hamming_2' ] * +* 'Unique' [ Boolean True or False ] * +* 'MatchThreshold' [ Percentage: 0 - 100 ] * +********************************************************************************************************************************************************************************************************/ +#include +#include +#include +#include +#include "opencv2/core/core.hpp" +#include "opencv2/features2d/features2d.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_matchFeatures(char *fname, unsigned long fname_len) + { + // Error Handling + SciErr sciErr; + + // Address of Various Scilab API + int *piAddr1 = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + + // Number of input and output Arguments + int inputArguments = 0; + + int Rows_1,Cols_1; + int Rows_2,Cols_2; + + // Input arguments + double *feature_1 = NULL; + double *feature_2 = NULL; + + int iRows, iCols; + int *pilen = NULL; + char **arg = NULL; + char **method = NULL; + char **metric = NULL; + double unique = 0; + double thresh = 10; + + int count_method = 0,count_metric = 0, count_unique = 0, count_thresh = 0; + + double max_dist = 0, min_dist; + double *indexPairs = NULL; + double *matchMetric = NULL; + + vector < vector > matches1; + vector matches; + vector valid_m; + + // Checks on Number of Input and Output Arguments + CheckInputArgument(pvApiCtx, 2, 10); + CheckOutputArgument(pvApiCtx, 1, 2); + + inputArguments = *getNbInputArgument(pvApiCtx); + + if( inputArguments%2 == 0 ) + { + // Feature Matrix 1 + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr1); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if( !isVarMatrixType(pvApiCtx, piAddr1)) + { + Scierror(999,"Expecting a Matrix of MxN order containing the Binary Feature Set of Image 1 (Query Image)\n"); + return 0; + } + if( !isDoubleType(pvApiCtx, piAddr1)) + { + Scierror(999,"Feature Matrix should be of Double Type\n"); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr1, &Rows_1, &Cols_1, &feature_1); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Feature Matrix 2 + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if( !isVarMatrixType(pvApiCtx, piAddr2)) + { + Scierror(999,"Expecting a Matrix of MxN order containing the Binary Feature Set of Image 1 (Query Image)\n"); + return 0; + } + if( !isDoubleType(pvApiCtx, piAddr2)) + { + Scierror(999,"Feature Matrix should be of Double Type\n"); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr2, &Rows_2, &Cols_2, &feature_2); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + } + else + { + Scierror(999,"Required Arguments are Missing\n"); + return 0; + } + + for( int i=3; i<=inputArguments; i++) + { + sciErr = getVarAddressFromPosition(pvApiCtx, i, &piAddr3); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + // Check for Argument type + if( !isStringType(pvApiCtx, piAddr3)) + { + Scierror(999, "%s: Wrong type of argument #%d. A string is expected.\n", fname, 1); + return 0; + } + // Matrix of Stings + sciErr = getMatrixOfString(pvApiCtx, piAddr3, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + pilen = (int*)malloc(sizeof(int) * iRows * iCols); + + // second call to retrieve the length of the string + sciErr = getMatrixOfString(pvApiCtx, piAddr3, &iRows, &iCols, pilen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(pilen); + return 0; + } + arg = (char**)malloc(sizeof(char*) * iRows * iCols); + for(int j=0;j< iRows * iCols; j++) + { + arg[j] = (char*)malloc(sizeof(char) * (pilen[j] + 1)); + } + + // third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr3, &iRows, &iCols, pilen, arg); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(pilen); + free(arg); + return 0; + } + + if(strcmp(arg[0],"Method") == 0) + { + if(count_method != 0) + { + Scierror(999,"Method argument has been called twice.\n"); + return 0; + } + free(arg); + free(pilen); + sciErr = getVarAddressFromPosition(pvApiCtx, i+1, &piAddr4); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Check for Argument type + if( !isStringType(pvApiCtx, piAddr4)) + { + Scierror(999, "%s: Wrong type of value for Method Argument. A string is expected.\n"); + return 0; + } + + // Matrix of Stings + sciErr = getMatrixOfString(pvApiCtx, piAddr4, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + pilen = (int*)malloc(sizeof(int) * iRows * iCols); + + // second call to retrieve the length of the string + sciErr = getMatrixOfString(pvApiCtx, piAddr4, &iRows, &iCols, pilen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(pilen); + return 0; + } + method = (char**)malloc(sizeof(char*) * iRows * iCols); + for(int j=0;j< iRows * iCols; j++) + { + method[j] = (char*)malloc(sizeof(char) * (pilen[j] + 1)); + } + + // third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr4, &iRows, &iCols, pilen, method); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(pilen); + free(method); + return 0; + } + i++; + count_method += 1; + } + + else if(strcmp(arg[0],"Metric") == 0) + { + if(count_metric != 0) + { + Scierror(999,"Metric argument has been called twice.\n"); + return 0; + } + free(arg); + free(pilen); + + sciErr = getVarAddressFromPosition(pvApiCtx, i+1, &piAddr4); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Check for Argument type + if( !isStringType(pvApiCtx, piAddr4)) + { + Scierror(999, "%s: Wrong type of Value for Metric Argument. A string is expected.\n"); + return 0; + } + + //Matrix of Stings + sciErr = getMatrixOfString(pvApiCtx, piAddr4, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + pilen = (int*)malloc(sizeof(int) * iRows * iCols); + + //second call to retrieve the length of the string + sciErr = getMatrixOfString(pvApiCtx, piAddr4, &iRows, &iCols, pilen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(pilen); + return 0; + } + metric = (char**)malloc(sizeof(char*) * iRows * iCols); + for(int j=0;j< iRows * iCols; j++) + { + metric[j] = (char*)malloc(sizeof(char) * (pilen[j] + 1)); + } + + //third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr4, &iRows, &iCols, pilen, metric); + if(sciErr.iErr) + { + printError(&sciErr, 0); + free(pilen); + free(metric); + return 0; + } + i++; + count_metric += 1; + } + + else if(strcmp(arg[0],"Unique") == 0) + { + if(count_unique != 0) + { + Scierror(999,"Unique argument has been called twice.\n"); + return 0; + } + free(arg); + free(pilen); + + sciErr = getVarAddressFromPosition(pvApiCtx, i+1, &piAddr4); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Check for Argument type + if( !(isDoubleType(pvApiCtx, piAddr4)) ) + { + Scierror(999,"Unique Value must be a logic scalar\n"); + return 0; + } + if(getScalarDouble(pvApiCtx, piAddr4, &unique)) + { + Scierror(999,"Cannot Read Upright Value\n"); + return 0; + } + if( !(int(unique)==0 || int(unique)==1) ) + { + Scierror(999,"Unique Value must be a logic scalar\n"); + return 0; + } + i++; + count_unique += 1; + } + + else if(strcmp(arg[0],"MatchThreshold") == 0) + { + if(count_thresh != 0) + { + Scierror(999,"Match Threshold argument has been called twice.\n"); + return 0; + } + free(arg); + free(pilen); + + sciErr = getVarAddressFromPosition(pvApiCtx, i+1, &piAddr4); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //Check for Argument type + if( !(isDoubleType(pvApiCtx, piAddr4)) ) + { + Scierror(999,"Match Threshold Value must be a scalar Double\n"); + return 0; + } + if(getScalarDouble(pvApiCtx, piAddr4, &thresh)) + { + Scierror(999,"Cannot Read Threshold Value\n"); + return 0; + } + if( !(thresh>0 && thresh<=100) ) + { + Scierror(999,"Threshold Value must be in the range of 1 to 100\n"); + return 0; + } + i++; + count_thresh += 1; + } + + else + { + Scierror(999, "Invalid Argument Name. Provide Valid Arguments\n"); + return 0; + } + } + + if( count_metric == 0 ) + { + metric = (char**)malloc(sizeof(char*) * 1 * 1); + metric[0] = (char*)malloc(sizeof(char) * 4); + strcpy(metric[0], "SSD"); + } + + if( count_method == 0) + { + method = (char**)malloc(sizeof(char*) * 1 * 1); + method[0] = (char*)malloc(sizeof(char) * 11); + strcpy(method[0], "Exhaustive"); + } + + Mat descriptor_2(Rows_2, Cols_2, CV_32FC1); + if( strcmp(method[0],"Exhaustive") == 0) + { + Mat descriptor_1(Rows_1, Cols_1, CV_8UC1); + Mat descriptor_2(Rows_2, Cols_2, CV_8UC1); + + // Converting feature_1 vector from double matrix to cv::mat. + for(int i = 0; i < Rows_1; i++) + { + for(int j = 0; j < Cols_1; j++) + { + descriptor_1.at(i,j) = int(feature_1[j*Rows_1 + i]); + } + } + + // Converting feature_2 vector from double matrix to cv::mat. + for(int i = 0; i < Rows_2; i++) + { + for(int j = 0; j < Cols_2; j++) + { + descriptor_2.at(i,j) = int(feature_2[j*Rows_2 + i]); + } + } + + if( strcmp(metric[0],"SSD") == 0) + { + Ptr matcher = DescriptorMatcher::create("BruteForce"); + try + { + matcher->match(descriptor_1, descriptor_2, matches); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + // BFMatcher matcher(NORM_L2, int(unique)); + // matcher.match(descriptor_1, descriptor_2, matches); + } + else if( strcmp(metric[0],"SAD") == 0) + { + Ptr matcher = DescriptorMatcher::create("BruteForce-L1"); + try + { + matcher->match(descriptor_1, descriptor_2, matches); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + // BFMatcher matcher(NORM_L1, int(unique)); + // matcher.match(descriptor_1, descriptor_2, matches); + } + else if( strcmp(metric[0],"Hamming") == 0) + { + Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming"); + try + { + matcher->knnMatch(descriptor_1, descriptor_2, matches1, 2); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + // BFMatcher matcher(NORM_HAMMING, int(unique)); + // matcher.match(descriptor_1, descriptor_2, matches); + } + else if( strcmp(metric[0],"Hamming_2") == 0) + { + sciprint("\nInside\n"); + Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming(2)"); + try + { + matcher->match(descriptor_1, descriptor_2, matches); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + // BFMatcher matcher(NORM_HAMMING2, int(unique)); + // matcher.match(descriptor_1, descriptor_2, matches); + } + else + { + Scierror(999,"Enter a Valid value for Metric Argument\n"); + return 0; + } + } + + else if( strcmp(method[0],"Approximate") == 0) + { + Mat descriptor_1(Rows_1, Cols_1, CV_32FC1); + //descriptor_2(Rows_2, Cols_2, CV_32FC1); + + // Converting feature_1 vector from double matrix to cv::mat. + for(int i=0; i(i,j) = float(feature_1[j*Rows_1 + i]); + } + } + + // Converting feature_1 vector from double matrix to cv::mat + for(int i=0; i(i,j) = float(feature_2[j*Rows_2 + i]); + } + } + FlannBasedMatcher matcher; + // Ptr matcher = DescriptorMatcher::create("FlannBased"); + try + { + matcher.knnMatch(descriptor_1, descriptor_2, matches1, 2); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + } + else + { + Scierror(999,"Enter a Valid value for Method Argument\n"); + return 0; + } + + if(matches1.size() != 0) + { + for(int i = 0; i < (int)matches1.size(); i++) + { + if((matches1[i][0].distance < 0.7 * (matches1[i][1].distance)) && + ((int)matches1[i].size() <= 2 && (int)matches1[i].size() > 0)) + { + valid_m.push_back(matches1[i][0]); + } + } + } + + if(matches.size() != 0) + { + int size = (int) matches.size(); + for(int i = 0; i < (int)matches.size(); i++) + { + if((matches[i].distance < 0.7 * (matches[i + 1].distance))) + { + valid_m.push_back(matches[i]); + } + } + } + + // Extracting Index Pairs from the match struct. + indexPairs = (double*)malloc(sizeof(double) * valid_m.size() * 2); + for( int i=0; i +#include +#include +#include +#include +#include +#include +#include + + +inline bool file_exists_check(const std::string& name) +{ + /*----- Checks is the input file is in the given wd. -----*/ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +using namespace cv::ml; + + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + int opencv_predictEM(char *fname, unsigned long fname_len) + { + // Error management variables + SciErr sciErr; + + //------Local variables------// + int upright = 1; + Ptr matcher = DescriptorMatcher::create("FlannBased"); + Ptr detector = SURF::create(400, 4, 2, 1, upright); + Ptr extractor = detector; + Ptr bowDE = makePtr(extractor, matcher); + + char *classifierLocation = NULL; + Mat dictionary, features; + Vec response; + Mat prob; + vector keyPoints; + int iPrec = 0; + int dictionarySize; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + char **classifierDescription = NULL; + int classifierDescriptionCount; + char *bagOfFeaturesLocation = NULL; + int descriptionCount; + Mat input; + + //------Check number of parameters------// + CheckInputArgument(pvApiCtx, 2, 2); + CheckOutputArgument(pvApiCtx, 1, 1); + + //------Get input arguments------// + retrieveImage(input,2); + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + // Extracting object type and checking if type is classifier + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0; iter < iRows * iCols; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"EMClassifier"))) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for classifier argument."); + return 0; + } + classifierLocation = pstData[0]; + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows != 1 || iCols != 1) + { + Scierror(999, "1x1 Matrix expected for bagOfFeatures argument."); + return 0; + } + + bagOfFeaturesLocation = pstData[0]; + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + classifierDescription = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + classifierDescription[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, piLen, classifierDescription); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Handling missing yml file + if(!file_exists_check(classifierLocation)) + { + Scierror(999, "Error: Input "".yml"" File not found in the pwd.\n"); + return 0; + } + + //------Actual processing------// + FileStorage fs(bagOfFeaturesLocation, FileStorage::READ); + fs["dictionary"] >> dictionary; + fs.release(); + dictionarySize = dictionary.rows; + try + { + bowDE->setVocabulary(dictionary); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + // Convert input image to and detect keypoints. + try + { + input.convertTo(input, CV_8U); + detector->detect(input, keyPoints); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + // Compute features. + try + { + bowDE->compute(input, keyPoints, features); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + // Load the trained classifier + Ptr em = Algorithm::load(classifierLocation); + try + { + if(!em->isTrained()) + { + Scierror(999, "Error: the model is not trained!.\n"); + return 0; + } + features.convertTo(features, CV_32F); + response = em->predict2(features, prob); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + double *resp = (double*) malloc(sizeof(double) * 2); + int i = 0; + for(i = 0; i < 2; i++) + { + resp[i] = response[i]; + } + + double *prob1 = (double*) malloc(sizeof(double) * 2); + // int i = 0; + int nClusters = em->getClustersNumber(); + for(i = 0; i < nClusters; i++) + { + prob1[i] = prob.at(i); + } + + //------Create output arguments------// + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 2, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, 1, (int)nClusters, prob1); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 2, 1, 2, resp); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //------Return Arguments------// + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + ReturnArguments(pvApiCtx); + return 0; + } + /* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_predictKNN.cpp b/sci_gateway/cpp/opencv_predictKNN.cpp new file mode 100644 index 0000000..e9db31b --- /dev/null +++ b/sci_gateway/cpp/opencv_predictKNN.cpp @@ -0,0 +1,336 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +using namespace cv::ml; + + +inline bool file_exists_check(const std::string& name) +{ + /*----- Checks if the input file is in the mentioned wd -----*/ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + int opencv_predictKNN(char *fname, unsigned long fname_len) + { + // Error management variables + SciErr sciErr; + + //------Local variables------// + int upright = 1; + Ptr matcher = DescriptorMatcher::create("FlannBased"); + Ptr detector = SURF::create(400, 4, 2, 1, upright); + Ptr extractor = detector; + Ptr bowDE = makePtr(extractor, matcher); + //String *classifierLocation = NULL; + Mat dictionary,features; + Mat response; + std::vector keyPoints; + int k = 4; + int iRet; + int dictionarySize; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + char **classifierDescription = NULL; + int classifierDescriptionCount; + char *bagOfFeaturesLocation = NULL; + int descriptionCount; + Mat input; + + //------Check number of parameters------// + CheckInputArgument(pvApiCtx, 3, 3); + CheckOutputArgument(pvApiCtx, 1, 1); + + //------Get input arguments------// + retrieveImage(input, 2); + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + // Extracting object type and checking if type is classifier + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"KNNClassifier"))) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for classifier argument."); + return 0; + } + //*classifierLocation = (String*) malloc(100 * sizeof(String)); + String classifierLocation = String(pstData[0]); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for bagOfFeatures argument."); + return 0; + } + bagOfFeaturesLocation = pstData[0]; + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + classifierDescription = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + classifierDescription[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, piLen, classifierDescription); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + // Handling the argument 3. + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isIntegerType(pvApiCtx, piAddr)||isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + k = (int)dData; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not of type Integer.\n"); + return 0; + } + + // Handling missing yml file + if(!file_exists_check(classifierLocation)) + { + Scierror(999, "Error: Input "".yml"" File not found in the pwd.\n"); + return 0; + } + + // sciprint("arguments done"); + //------Actual processing------// + sciprint("\n%s\n", bagOfFeaturesLocation); + FileStorage fs(bagOfFeaturesLocation, FileStorage::READ); + fs["dictionary"] >> dictionary; + fs.release(); + dictionarySize = dictionary.rows; + try + { + bowDE->setVocabulary(dictionary); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + // sciprint("\n%d %d\n", input.rows, input.cols); + // Convert input image to and detect keypoints. + try + { + input.convertTo(input, CV_8U); + detector->detect(input, keyPoints); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + // Compute features. + try + { + bowDE->compute(input, keyPoints, features); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + // Load and train classifier. + try + { + Ptr knearest = Algorithm::load(classifierLocation); + if(!knearest->isTrained()) + { + Scierror(999, "Error: the model is not trained!.\n"); + return 0; + } + features.convertTo(features, CV_32F); + knearest->setIsClassifier(1); + knearest->findNearest(features, k, response); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + //------Create output arguments------// + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 1, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, 1, 1, &classifierDescription[(int)response.at(0, 0)]); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //------Return Arguments------// + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + ReturnArguments(pvApiCtx); + return 0; + } + /* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_predictLR.cpp b/sci_gateway/cpp/opencv_predictLR.cpp new file mode 100644 index 0000000..c4cafc5 --- /dev/null +++ b/sci_gateway/cpp/opencv_predictLR.cpp @@ -0,0 +1,295 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +inline bool file_exists_check(const std::string& name) +{ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +using namespace cv::ml; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + int opencv_predictLR(char *fname, unsigned long fname_len) + { + // Error management variables + SciErr sciErr; + + //------Local variables------// + int upright = 1; + Ptr matcher = DescriptorMatcher::create("FlannBased"); + Ptr detector = SURF::create(400, 4, 2, 1, upright); + Ptr extractor = detector; + Ptr bowDE = makePtr(extractor, matcher); + char *classifierLocation = NULL; + Mat dictionary, features; + Mat response; + vector keyPoints; + int iPrec = 0; + int dictionarySize; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + char **classifierDescription = NULL; + int classifierDescriptionCount; + char *bagOfFeaturesLocation = NULL; + int descriptionCount; + Mat input; + + //------Check number of parameters------// + CheckInputArgument(pvApiCtx, 2, 2); + CheckOutputArgument(pvApiCtx, 1, 1); + + //------Get input arguments------// + retrieveImage(input,2); + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + + // Extracting object type and checking if type is classifier + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"LRClassifier"))) + { + Scierror(999, "Error: The input argument #1 is not of type classifier.\n"); + return 0; + } + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for classifier argument."); + return 0; + } + classifierLocation = pstData[0]; + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 3, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for bagOfFeatures argument."); + return 0; + } + bagOfFeaturesLocation = pstData[0]; + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + classifierDescription = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + classifierDescription[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 4, &iRows, &iCols, piLen, classifierDescription); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Handling missing yml file + if(!file_exists_check(classifierLocation)) + { + Scierror(999, "Error: Input "".yml"" File not found in the pwd.\n"); + return 0; + } + + //------Actual processing------// + FileStorage fs(bagOfFeaturesLocation, FileStorage::READ); + fs["dictionary"] >> dictionary; + fs.release(); + dictionarySize = dictionary.rows; + try + { + bowDE->setVocabulary(dictionary); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + // Convert input image to and detect keypoints. + try + { + input.convertTo(input, CV_8U); + detector->detect(input, keyPoints); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + // Compute features. + try + { + bowDE->compute(input, keyPoints, features); + } + catch(Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + // Load classifier + Ptr lr = Algorithm::load(classifierLocation); + + try + { + if(!lr->isTrained()) + { + Scierror(999, "Error: the model is not trained!.\n"); + return 0; + } + features.convertTo(features, CV_32F); + lr->predict(features, response); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + //------Create output arguments------// + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 1, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, 1, 1, &classifierDescription[response.at(0)]); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //------Return Arguments------// + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + ReturnArguments(pvApiCtx); + return 0; + } + /* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_reconstructScene.cpp b/sci_gateway/cpp/opencv_reconstructScene.cpp new file mode 100644 index 0000000..a6060e7 --- /dev/null +++ b/sci_gateway/cpp/opencv_reconstructScene.cpp @@ -0,0 +1,126 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace cv; +using namespace std; +using namespace cv::ximgproc; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_reconstructScene(char *fname, unsigned long fname_len) + { + SciErr sciErr; + + /*----- Local Variables -----*/ + int *piAddr = NULL; + int *piLen = NULL; + int iRows = 0, iCols = 0; + int iType = 0; + + /*----- Check for input and output arguments -----*/ + CheckInputArgument(pvApiCtx, 3, 3); + CheckOutputArgument(pvApiCtx, 1, 1); + + /*----- Taking input arguments -----*/ + double *Q = NULL; + int handleMissigValues = 0; + + + // Input Arguments one + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //check type + sciErr = getVarType(pvApiCtx, piAddr, &iType); + if(sciErr.iErr || iType != sci_matrix) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &Q); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + double temp[iCols][iRows]; + int k = 0, j = 0; + for(int i = 0; i < iRows; i++) + { + for(int i = 0; i < iRows; i++) + { + temp[i][j] = Q[(j * 4) + i]; + } + } + Mat _Q(iRows, iCols, CV_8UC1, &temp); + + // Input Arguments two + Mat _disparity; + retrieveImage(_disparity, 2); + + // Input Arguments three + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + getScalarInteger32(pvApiCtx, piAddr, &handleMissigValues); + sciprint("%d", handleMissigValues); + + if(handleMissigValues < 0 && handleMissigValues > 1) + { + Scierror(999, "Invalid Value for handleMissigValues. Please enter a non negative Integer value which is divisible by 16.\n"); + return 0; + } + + Mat image3DOCV; + try + { + reprojectImageTo3D(_disparity, image3DOCV, _Q, true, CV_64F); + sciprint("%d", image3DOCV.rows); + } + catch(Exception &e) + { + Scierror(999, "%s", e.what()); + return 0; + } + + /*----- Creating output images -----*/ + string tempstring = type2str(image3DOCV.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker, image3DOCV, 1); + free(checker); + + /*----- Returning output -----*/ + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + ReturnArguments(pvApiCtx); + return 0; + } +} \ No newline at end of file diff --git a/sci_gateway/cpp/opencv_scharr.cpp b/sci_gateway/cpp/opencv_scharr.cpp new file mode 100644 index 0000000..2c2c08b --- /dev/null +++ b/sci_gateway/cpp/opencv_scharr.cpp @@ -0,0 +1,165 @@ +/**************************************************************** +Author: Sukul Bagai +***************************************************************** +return_image = scharr(input_image, ddepth, dx, dy, scale, delta); +*****************************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_scharr(char *fname, unsigned long fname_len) + { + SciErr sciErr; + int intErr = 0; + int iRows = 0,iCols = 0; + int *piLen = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + int *piAddr5 = NULL; + int *piAddr6 = NULL; + int *piAddr7 = NULL; + char **ddepth = NULL; + int i,j,k; + double dx,dy,scale,delta; + + + //checking input argument + CheckInputArgument(pvApiCtx, 6, 6); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + Mat image; + retrieveImage(image,1); + + //for ddepth + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Now, we will retrieve the string from the input parameter. For this, we will require 3 calls + //first call to retrieve dimensions + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + //second call to retrieve length of each string + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + ddepth = (char**)malloc(sizeof(char*) * iRows * iCols); + for(i = 0 ; i < iRows * iCols ; i++) + ddepth[i] = (char*)malloc(sizeof(char) * (piLen[i] + 1));//+ 1 for null termination + //third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, piLen, ddepth); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //for value of dx + sciErr = getVarAddressFromPosition(pvApiCtx,3,&piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr3, &dx); + if(intErr) + return intErr; + + //for value of dy + sciErr = getVarAddressFromPosition(pvApiCtx,4,&piAddr4); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr4, &dy); + if(intErr) + return intErr; + + //for value of scale + sciErr = getVarAddressFromPosition(pvApiCtx,5,&piAddr5); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr5, &scale); + if(intErr) + return intErr; + + //for value of delta + sciErr = getVarAddressFromPosition(pvApiCtx,6,&piAddr6); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + intErr = getScalarDouble(pvApiCtx, piAddr6, &delta); + if(intErr) + return intErr; + + Mat new_image(image.rows,image.cols,image.type()); + + try + { + if(strcmp(ddepth[0], "CV_8U") == 0) + Scharr(image, new_image, CV_8U, dx, dy, scale, delta); + else if(strcmp(ddepth[0], "CV_16U") == 0) + Scharr(image, new_image, CV_16U, dx, dy, scale, delta); + else if(strcmp(ddepth[0],"CV_16S") == 0) + Scharr(image, new_image, CV_16S, dx, dy, scale, delta); + else if(strcmp(ddepth[0], "CV_32F") == 0) + Scharr(image, new_image, CV_32F, dx, dy, scale, delta); + else if(strcmp(ddepth[0], "CV_64F") == 0) + Scharr(image, new_image, CV_64F, dx, dy, scale, delta); + } + catch(Exception &err) + { + sciprint("%s", err.what()); + return 0; + } + + + string tempstring = type2str(new_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,new_image,1); + free(checker); + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_sepFilter2D.cpp b/sci_gateway/cpp/opencv_sepFilter2D.cpp new file mode 100644 index 0000000..3994ada --- /dev/null +++ b/sci_gateway/cpp/opencv_sepFilter2D.cpp @@ -0,0 +1,271 @@ +/*************************************************** +Author : Sukul Bagai +**************************************************** +Usage : return_image = sepFilter2D(input_image,"",kernel_x,kernel_y,anchor_x,anchor_y,delta,""); +***************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_sepFilter2D(char *fname, unsigned long fname_len) + { + SciErr sciErr; + int intErr=0; + int iRows=0,iCols=0; + int *piLen = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + int *piAddr5 = NULL; + int *piAddr6 = NULL; + int *piAddr7 = NULL; + int *piAddr8 = NULL; + char **ddepth = NULL; + char **borderType = NULL; + int i,j,k; + double *kernelX,*kernelY,anchorX,anchorY,delta,border,actualddepth; + + //checking input argument + CheckInputArgument(pvApiCtx, 8, 8); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + Mat image; + retrieveImage(image,1); + cout<<"here1"; + //for ddepth + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + //Now, we will retrieve the string from the input parameter. For this, we will require 3 calls + //first call to retrieve dimensions + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + //second call to retrieve length of each string + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + ddepth = (char**)malloc(sizeof(char*) * iRows * iCols); + for(i = 0 ; i < iRows * iCols ; i++) + ddepth[i] = (char*)malloc(sizeof(char) * (piLen[i] + 1));//+ 1 for null termination + //third call to retrieve data + sciErr = getMatrixOfString(pvApiCtx, piAddr2, &iRows, &iCols, piLen, ddepth); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //for kernel_x matrix + sciErr = getVarAddressFromPosition(pvApiCtx,3,&piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr3, &iRows, &iCols ,&kernelX); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + int n; + + if(iRows == 1) + n=iCols; + else + n=iRows; + double kernelArray_x[n]; + //assigning values to actual kernelMatrix + for(i=0;i= n || anchorY >=n) + { + sciprint("Invalid anchor point given. Centre point (-1,-1) was used instead"); + anchorY = -1; + anchorX = -1; + } + Mat new_image(image.rows,image.cols,image.type()); + Point pt(anchorX,anchorY); + + if(strcmp(ddepth[0],"CV_8U")==0) + actualddepth=CV_8U; + else if(strcmp(ddepth[0],"CV_16U")==0) + actualddepth=CV_16U; + else if(strcmp(ddepth[0],"CV_16S")==0) + actualddepth=CV_16S; + else if(strcmp(ddepth[0],"CV_32F")==0) + actualddepth=CV_32F; + else if(strcmp(ddepth[0],"CV_64F")==0) + actualddepth=CV_64F; + else + { + sciprint("Invalid type %s used. CV_8U was used instead by default",ddepth[0]); + actualddepth = CV_8U; + } + if(strcmp(borderType[0], "BORDER_CONSTANT") == 0) + border = BORDER_CONSTANT; + else if(strcmp(borderType[0], "BORDER_REPLICATE") == 0) + border = BORDER_REPLICATE; + else if(strcmp(borderType[0], "BORDER_REFLECT") == 0) + border = BORDER_REFLECT; + else if(strcmp(borderType[0], "BORDER_REFLECT_101") == 0) + border = BORDER_REFLECT_101; + else if(strcmp(borderType[0], "BORDER_WRAP") == 0) + border = BORDER_WRAP; + else + border = BORDER_DEFAULT; + + //applying function + try + { + sepFilter2D(image,new_image,actualddepth,kernelMatrix_x,kernelMatrix_y,pt,delta,border); + } + catch(Exception &e) + { + sciprint("%s", e.what()); + return 0; + } + + + //returning image + string tempstring = type2str(new_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,new_image,1); + free(checker); + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_stereoCalibrateAndRect.cpp b/sci_gateway/cpp/opencv_stereoCalibrateAndRect.cpp new file mode 100644 index 0000000..8d76d36 --- /dev/null +++ b/sci_gateway/cpp/opencv_stereoCalibrateAndRect.cpp @@ -0,0 +1,609 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ + +#include +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/core/types_c.h" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + double* readDoubleArrayFromScilab(int cnt) + { + SciErr sciErr; + int *piAddr = NULL; + double val = 0; + int intErr = 0; + int iRows = 0, iCols = 0; + double *pdblReal; + + sciErr = getVarAddressFromPosition(pvApiCtx, cnt, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(isDoubleType(pvApiCtx, piAddr)) + { + return pdblReal; + } + else + { + sciprint("Error: the %d argument is not of the type double!", cnt); + return 0; + } + } + + + int opencv_stereoCalibrateAndRect(char *fname, unsigned long fname_len) + { + /*----- Local variables -----*/ + int i = 0, j = 0, k = 0, n = 0, m = 0; + int iRows = 0, iCols = 0; + int *piAddr = NULL; + double *pdblReal = NULL; + double x, y, rms; + SciErr sciErr; + + /*----- Processing Variables -----*/ + vector >imagePoints1(1), imagePoints2(1); + vector >objectPoints(1); + Mat cameraMatrix1; + Mat cameraMatrix2; + Mat distCoeffsActual1; + Mat distCoeffsActual2; + Mat rotationMatrix; + Mat translationVector; + Mat fundamentalMatrix; + int num; + double width = 0, height = 0; + + /*----- Check for input and output arguments -----*/ + CheckInputArgument(pvApiCtx, 4, 8); + CheckOutputArgument(pvApiCtx, 9, 9); + + /*----- Parsing input -----*/ + n = *getNbInputArgument(pvApiCtx); + + // First + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Stores + for(i = 0; i < iRows; ++i) + { + objectPoints[0].push_back(Point3f(float(pdblReal[(0 * iRows) + i]), + float(pdblReal[(1 * iRows) + i]), + 0.0)); + } + int pointCount = iRows; + + // Second Input + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999,"The imagePoints1 Argument must be a list of points.\n"); + return 0; + } + sciErr = getListItemNumber(pvApiCtx, piAddr, &num); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Get items from list + for(int i = 1; i <= num; i++) + { + sciErr = getMatrixOfDoubleInList(pvApiCtx, piAddr, i, &iRows, &iCols, &pdblReal); + + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + for(j = 0; j < iRows; ++j) + { + imagePoints1[i-1].push_back(Point2f(float(pdblReal[(0 * iRows) + j]), + float(pdblReal[(1 * iRows) + j]))); + } + } + + // Third input + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999,"\nthe imagePoints2 Argument must be a list of points \n"); + return 0; + } + sciErr = getListItemNumber(pvApiCtx, piAddr, &num); + if(sciErr.iErr) + { + printError(&sciErr, 0); + + return 0; + } + + // Get items from list + for(int i = 1; i <= num; i++) + { + sciErr = getMatrixOfDoubleInList(pvApiCtx, piAddr,i,&iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + for(j = 0; j < iRows; ++j) + { + imagePoints2[i - 1].push_back(Point2f(float(pdblReal[(0 * iRows) + j]), + float(pdblReal[(1 * iRows) + j]))); + } + } + + // Fourth + sciErr = getVarAddressFromPosition(pvApiCtx, 4, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(iCols > 2 && iRows > 1) + { + Scierror(999, "The image size should be of a grayscale image.\n"); + return 0; + } + + sciprint("\nImage size obtained\n"); + width = pdblReal[0]; + height = pdblReal[1]; + + /*----- Getting optional arguments -----*/ + int p; + switch(n) + { + case 5: + pdblReal = readDoubleArrayFromScilab(4); + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + cameraMatrix1.at(i, j) = pdblReal[(j * 3) + i]; + } + } + break; + + case 6: + pdblReal = readDoubleArrayFromScilab(4); + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + cameraMatrix1.at(i, j) = pdblReal[(j * 3) + i]; + } + } + + sciErr = getVarAddressFromPosition(pvApiCtx,5,&piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows== 1) + { + p = iCols; + } + else if (iCols == 1) + { + p = iRows; + } + else + { + Scierror(1,"Distortion Points matrix (arg 5) must be a 1 X N or N X 1 matrix"); + return 0; + } + if(p == 4 or p == 5 or p == 8); + else + { + Scierror(1," N must be 4 or 5 or 8"); + return 0; + } + break; + + case 7: + pdblReal = readDoubleArrayFromScilab(4); + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + cameraMatrix1.at(i, j) = pdblReal[(j * 3) + i]; + } + } + + sciErr = getVarAddressFromPosition(pvApiCtx,5,&piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows == 1) + { + p = iCols; + } + else if (iCols == 1) + { + p = iRows; + } + else + { + Scierror(1,"Distortion Points matrix (arg 5) must be a 1 X N or N X 1 matrix"); + return 0; + } + if(p == 4 or p == 5 or p == 8); + else + { + Scierror(1," N must be 4 or 5 or 8"); + return 0; + } + for(i = 0; i < p; i++){ + distCoeffsActual1.at(0, i) = pdblReal[i]; + } + pdblReal=readDoubleArrayFromScilab(6); + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + cameraMatrix2.at(i,j) = pdblReal[(j * 3) + i]; + } + } + break; + + case 8: + pdblReal = readDoubleArrayFromScilab(4); + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + cameraMatrix1.at(i, j) = pdblReal[(j * 3) + i]; + } + } + + sciErr = getVarAddressFromPosition(pvApiCtx,5,&piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows == 1) + { + p = iCols; + } + else if (iCols == 1) + { + p = iRows; + } + else + { + Scierror(1,"Distortion Points matrix (arg 5) must be a 1 X N or N X 1 matrix"); + return 0; + } + if(p == 4 or p == 5 or p == 8); + else{ + Scierror(1," N must be 4 or 5 or 8"); + return 0; + } + for(i = 0; i < p; i++) + { + distCoeffsActual1.at(0, i) = pdblReal[i]; + } + + pdblReal = readDoubleArrayFromScilab(6); + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + cameraMatrix2.at(i,j) = pdblReal[(j * 3) + i]; + } + } + sciErr = getVarAddressFromPosition(pvApiCtx,7,&piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows == 1) + p = iCols; + else if (iCols == 1) + p = iRows; + else + { + Scierror(1,"Distortion Points matrix (arg 5) must be a 1 X N or N X 1 matrix"); + return 0; + } + if(p == 4 or p == 5 or p == 8); + else + { + Scierror(1," N must be 4 or 5 or 8"); + return 0; + } + for(i = 0; i < p; i++) + { + distCoeffsActual2.at(0, i) = pdblReal[i]; + } + break; + } + + Size imageSize (width, height); + Mat E; + try + { + rms = stereoCalibrate(objectPoints, imagePoints1, imagePoints2, + cameraMatrix1, distCoeffsActual1, + cameraMatrix2, distCoeffsActual2, + imageSize, rotationMatrix, + translationVector, E, fundamentalMatrix, + CV_CALIB_SAME_FOCAL_LENGTH | CV_CALIB_ZERO_TANGENT_DIST, + cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 100, 1e-5) + ); + } + catch(cv::Exception& e) + { + sciprint("%s", e.what()); + return 0; + } + + Mat R1, R2, P1, P2, Q; + try + { + stereoRectify(cameraMatrix1, distCoeffsActual1, + cameraMatrix2, distCoeffsActual2, + imageSize, rotationMatrix, + translationVector, R1, R2, P1, P2, Q, + CALIB_ZERO_DISPARITY); + } + catch(cv::Exception& e) + { + sciprint("%s", e.what()); + return 0; + } + + sciprint("Calibration done with RMS error=%f\n", rms); + + /*----- Return Arguments to Scilab -----*/ + double *pstdata1 = NULL; + double *pstdata2 = NULL; + double *pstdata3 = NULL; + double *pstdata4 = NULL; + double *pstdata5 = NULL; + double *pstdata6 = NULL; + double *pstdata7 = NULL; + double *pstdata8 = NULL; + double *pstdata9 = NULL; + + pstdata1 = (double*)malloc(sizeof(double) * 3 * 3); + + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + pstdata1[(j * 3) + i] = cameraMatrix1.at(i, j); + } + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 3, 3, pstdata1); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstdata2 = (double*)malloc(sizeof(double) * 4 * 1); + for(i = 0; i < 4; i++) + { + pstdata2[i] = distCoeffsActual1.at(0, i); + } + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 2, 1, 4, pstdata2); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstdata3 = (double*)malloc(sizeof(double) * 3 * 3); + + for(i = 0; i < 3; i++) + { + for(j = 0; j < 3; j++) + { + pstdata3[(j * 3) + i] = cameraMatrix2.at(i,j); + } + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 3, 3, 3, pstdata3); + if(sciErr.iErr){ + printError(&sciErr, 0); + return 0; + } + + pstdata4 = (double*)malloc(sizeof(double) * 4 * 1); + for(i = 0; i < 4; i++) + { + pstdata4[i] = distCoeffsActual2.at(0, i); + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 4, 1, 4, pstdata4); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstdata5 = (double*)malloc(sizeof(double) *rotationMatrix.rows*rotationMatrix.cols); + for(i = 0; i < rotationMatrix.rows; i++) + { + for(j = 0; j < rotationMatrix.cols; j++) + { + pstdata5[(j * rotationMatrix.rows) + i] = rotationMatrix.at(i, j); + } + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 5, rotationMatrix.rows, rotationMatrix.cols, pstdata5); + if(sciErr.iErr){ + printError(&sciErr, 0); + return 0; + } + + pstdata6 = (double*)malloc(sizeof(double) * translationVector.rows * translationVector.cols); + + for(i = 0; i < translationVector.rows; i++) + { + for(j = 0; j < translationVector.cols; j++) + { + pstdata6[(j * translationVector.rows) + i] = translationVector.at(i, j); + } + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 6, translationVector.rows, translationVector.cols, pstdata6); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstdata7 = (double*)malloc(sizeof(double) * Q.rows * Q.cols); + for(i = 0; i < Q.rows; i++) + { + for(j = 0; j < Q.cols; j++) + { + pstdata7[(j * Q.rows) + i] = Q.at(i, j); + } + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 7, Q.rows, Q.cols, pstdata7); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstdata8 = (double*)malloc(sizeof(double) * P1.rows * P1.cols); + for(i = 0; i < P1.rows; i++) + { + for(j = 0; j < P1.cols; j++) + { + pstdata8[(j * P1.rows) + i] = P1.at(i, j); + } + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 8, P1.rows, P1.cols, pstdata8); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstdata9 = (double*)malloc(sizeof(double) * P2.rows * P2.cols); + for(i = 0; i < P2.rows; i++) + { + for(j = 0; j < P2.cols; j++) + { + pstdata9[(j * P2.rows) + i] = P2.at(i, j); + } + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 9, P2.rows, P2.cols, pstdata9); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + for(int i = 1; i <= 9; i++) + { + AssignOutputVariable(pvApiCtx, i) = nbInputArgument(pvApiCtx) + i; + } + + /*----- Returning the Output Variables as arguments to the Scilab environment -----*/ + ReturnArguments(pvApiCtx); + return 0; + } +} diff --git a/sci_gateway/cpp/opencv_trainEMClassifier.cpp b/sci_gateway/cpp/opencv_trainEMClassifier.cpp new file mode 100644 index 0000000..e491ae0 --- /dev/null +++ b/sci_gateway/cpp/opencv_trainEMClassifier.cpp @@ -0,0 +1,519 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include +#include +#include +#include + + +inline bool file_exists_check(const std::string& name) +{ + /*----- This function checks if the input file exists in the mentioned wd -----*/ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +using namespace cv::ml; + + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + + + int opencv_trainEMClassifier(char *fname, unsigned long fname_len) + { + // Error management variables + SciErr sciErr; + + //------Local variables------// + int upright = 1; + Ptr matcher = DescriptorMatcher::create("FlannBased"); + Ptr detector = SURF::create(400, 4, 2, 1, upright); + Ptr extractor = detector; + Ptr bowDE = makePtr(extractor, matcher); + char *fileName = NULL; + Mat dictionary,inp,features; + vector keyPoints; + + int iRet = 0; + int iPrec = 0; + int iBool = 0; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + int *count = NULL; + char **description = NULL; + char ***location = NULL; + char *bagOfFeaturesLocation = NULL; + int descriptionCount; + + int nClusters = 10; + int iType = 0; + char *classifierName = NULL; + + char *classifierLocation = NULL; + char *objectType = "EMClassifier"; + + //------Check number of parameters------// + CheckInputArgument(pvApiCtx, 3, 4); + CheckOutputArgument(pvApiCtx, 1, 1); + + //------Get input arguments------// + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type imageSet.\n"); + return 0; + } + + // Extracting object type and checking if type is imageSet + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1)); // + 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"imageSet")==0)) + { + Scierror(999, "Error: The input argument #1 is not of type imageSet.\n"); + return 0; + } + + // Extracting Description attribute of input argument + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + description = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + description[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, description); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + descriptionCount = iRows; + + // Extracting Count attribute of input argument + sciErr = getMatrixOfInteger32InList(pvApiCtx, piAddr, 3, &iRows, &iCols, &count); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + location = (char***) malloc(sizeof(char**) * descriptionCount); + + // Extracting Location of images from input argument. + sciErr = getListItemAddress(pvApiCtx, piAddr, 4, &piChild); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + for(int iter = 1; iter <= descriptionCount; iter++) + { + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + location[iter-1] = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int colIter = 0 ; colIter < iRows * iCols ; colIter++) + { + location[iter-1][colIter] = (char*)malloc(sizeof(char) * (piLen[colIter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, piLen, location[iter-1]); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + } + + // Check is imageSet is in pwd. + if(!file_exists_check(location[0][1])) + { + Scierror(999, "Error: Image set not found in the pwd.\n"); + return 0; + } + + // Second argument + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #2 is not of type bagOfFeatures.\n"); + return 0; + } + + // Extracting object type and checking if type is bagOfFeatures + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1)); //+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"bagOfFeatures") == 0)) + { + Scierror(999, "Error: The input argument #2 is not of type bagOfFeatures.\n"); + return 0; + } + + // Extracting name of next argument takes three calls to getMatrixOfString + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows != 1 || iCols != 1) + { + Scierror(999, "1x1 Matrix expected for bagOfFeatures argument."); + return 0; + } + bagOfFeaturesLocation = pstData[0]; + + // Check is bagOfFeatures.yml is in pwd. + if(!file_exists_check(bagOfFeaturesLocation)) + { + Scierror(999, "Error: Bag of Features "".yml"" file not found in the pwd.\n"); + return 0; + } + + // Handling 3rd argument. + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isStringType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + char* stringData = NULL; + + iRet = getAllocatedSingleString(pvApiCtx, piAddr, &stringData); + if(!iRet) + { + classifierName = stringData; + } + else + { + Scierror(999, "Error: Could not assign input arg #3 to local var.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not a string.\n"); + return 0; + } + + // Handling more than 3 arguments. + if(*getNbInputArgument(pvApiCtx) > 3) + { + sciErr = getVarAddressFromPosition(pvApiCtx, 4, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + nClusters = dData; + } + } + else + { + Scierror(999, "Error: The input argument #4 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #4 is not of type Integer.\n"); + return 0; + } + } + + classifierLocation = classifierName; + strcat(classifierLocation, ".yml"); + + //------Actual processing------// + FileStorage fs(bagOfFeaturesLocation, FileStorage::READ); + fs["dictionary"] >> dictionary; + fs.release(); + if(dictionary.rows == 0 || dictionary.cols == 0) + { + sciprint("Error: The provided file for bagOfFeatures may be invalid.\n"); + } + sciprint("Training an EM classifier for %d clusters.\n", nClusters); + sciprint("-------------------------------------------------------\n\n"); + int dictionarySize = dictionary.rows; + sciprint("%d", dictionary.rows); + Mat trainingData(0, dictionarySize, CV_32FC1); + bowDE->setVocabulary(dictionary); + + for(int i = 0; i < descriptionCount; i++) + { + sciprint("# Encoding features for Class %d ...", i + 1); + for(int j = 0; j < count[i]; j++) + { + features.release(); + keyPoints.clear(); + fileName = location[i][j]; + inp = imread(fileName); + try + { + detector->detect(inp, keyPoints); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + try + { + bowDE->compute(inp, keyPoints, features); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + trainingData.push_back(features); + // labels.push_back((float) i); + } + sciprint("done.\n"); + } + sciprint("\n# Training the EM classifier..."); + + Ptr em = EM::create(); + Mat labels; + + try + { + em->setClustersNumber(nClusters); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + const cv::TermCriteria& termCrit=cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, + 100, 0.0000001); + try + { + em->setTermCriteria(termCrit); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + try + { + em->trainEM(trainingData, noArray(), labels, noArray()); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + sciprint("\n# Saving the EM classifier..."); + try + { + em->save(classifierLocation); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + sciprint("done.\n"); + + //------Create output arguments------// + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 4, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 1, 1, 1, &objectType); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 2, 1, 1, &classifierLocation); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 3, 1, 1, &bagOfFeaturesLocation); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 4, descriptionCount, 1, description); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //------Return Arguments------// + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + ReturnArguments(pvApiCtx); + return 0; + } + /* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_trainKNNClassifier.cpp b/sci_gateway/cpp/opencv_trainKNNClassifier.cpp new file mode 100644 index 0000000..a6010e9 --- /dev/null +++ b/sci_gateway/cpp/opencv_trainKNNClassifier.cpp @@ -0,0 +1,517 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + + +inline bool file_exists_check(const std::string& name) +{ + /*----- Checks if the input file is in the mentioned wd ------*/ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +using namespace cv::ml; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + + + int opencv_trainKNNClassifier(char *fname, unsigned long fname_len) + { + // Error management variables + SciErr sciErr; + + /*------ Local variables ------*/ + int upright = 1; + Ptr matcher = DescriptorMatcher::create("FlannBased"); + Ptr detector = SURF::create(400, 4, 2, 1, upright); + Ptr extractor = detector; + Ptr bowDE = makePtr(extractor, matcher); + char *fileName = NULL; + Mat dictionary,inp,features; + vector keyPoints; + + int iRet = 0; + + int iBool = 0; + + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + int *count = NULL; + char **description = NULL; + char ***location = NULL; + char *bagOfFeaturesLocation = NULL; + int descriptionCount; + + int algorithmType = 1; + + char *classifierLocation; + char *classifierName = NULL; + char *objectType = "KNNClassifier"; + + /*------ Check number of parameters ------*/ + CheckInputArgument(pvApiCtx, 3, 4); + CheckOutputArgument(pvApiCtx, 1, 1); + + /*------ Get input arguments ------*/ + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type imageSet.\n"); + return 0; + } + + /*----- Extracting object type and checking if type is imageSet -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1)); // + 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"imageSet")==0)) + { + Scierror(999, "Error: The input argument #1 is not of type imageSet.\n"); + return 0; + } + + /*----- Extracting Description attribute of input argument -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + description = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + description[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, description); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + descriptionCount = iRows; + + /*----- Extracting Count attribute of input argument -----*/ + sciErr = getMatrixOfInteger32InList(pvApiCtx, piAddr, 3, &iRows, &iCols, &count); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + location = (char***) malloc(sizeof(char**) * descriptionCount); + + /*----- Extracting Location of images from input argument. -----*/ + sciErr = getListItemAddress(pvApiCtx, piAddr, 4, &piChild); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + for(int iter = 1; iter<=descriptionCount; iter++) + { + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + location[iter-1] = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int colIter = 0 ; colIter < iRows * iCols ; colIter++) + { + location[iter-1][colIter] = (char*)malloc(sizeof(char) * (piLen[colIter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, piLen, location[iter-1]); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + } + + // Check is imageSet is in its specified location. + if(!file_exists_check(location[0][1])) + { + Scierror(999, "Error: Image set not found in the pwd.\n"); + return 0; + } + + // Second argument + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #2 is not of type bagOfFeatures.\n"); + return 0; + } + + /*----- Extracting object type and checking if type is bagOfFeatures -----*/ + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1)); //+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"bagOfFeatures")==0)) + { + Scierror(999, "Error: The input argument #2 is not of type bagOfFeatures.\n"); + return 0; + } + // Extracting name of next argument takes three calls to getMatrixOfString + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows != 1 || iCols != 1) + { + Scierror(999, "1x1 Matrix expected for bagOfFeatures argument."); + return 0; + } + + bagOfFeaturesLocation = pstData[0]; + + // Check is bagOfFeatures.yml is in its specified location. + if(!file_exists_check(bagOfFeaturesLocation)) + { + Scierror(999, "Error: Bag of Features "".yml"" file not found in the pwd.\n"); + return 0; + } + + // Handling 3rd argument. + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isStringType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + char* stringData = NULL; + + iRet = getAllocatedSingleString(pvApiCtx, piAddr, &stringData); + if(!iRet) + { + classifierName = stringData; + } + else + { + Scierror(999, "Error: Could not assign input arg #3 to local var.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not a string.\n"); + return 0; + } + + // Handling more than 3 arguments. + if(*getNbInputArgument(pvApiCtx) > 3) + { + sciErr = getVarAddressFromPosition(pvApiCtx, 4, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + if(dData < 1 || dData > 2) + { + Scierror(999, "Error: The input argument ""algorithmType"" should be in range [1, 2].\n"); + return 0; + } + algorithmType = dData; + } + } + else + { + Scierror(999, "Error: The input argument #4 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #4 is not of type Integer.\n"); + return 0; + } + } + + classifierLocation = classifierName; + strcat(classifierLocation, ".yml"); + + //------Actual processing------// + FileStorage fs(bagOfFeaturesLocation, FileStorage::READ); + fs["dictionary"] >> dictionary; + fs.release(); + if(dictionary.rows == 0 || dictionary.cols == 0) + { + sciprint("Error: The provided file for bagOfFeatures may be invalid.\n"); + } + sciprint("Training an KNN classifier for %d classes.\n",descriptionCount); + sciprint("-------------------------------------------------------\n\n"); + for(int i = 0; i < descriptionCount; i++) + { + sciprint("# Class %d: %s\n", i + 1, description[i]); + } + sciprint("\n"); + int dictionarySize = dictionary.rows; + Mat labels(0, 1, CV_32FC1); + Mat trainingData(0, dictionarySize, CV_32FC1); + bowDE->setVocabulary(dictionary); + + for(int i =0 ; i < descriptionCount; i++) + { + sciprint("# Encoding features for Class %d ...",i+1); + for(int j=0; jdetect(inp,keyPoints); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + try + { + bowDE->compute(inp, keyPoints,features); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + trainingData.push_back(features); + labels.push_back((float) i); + } + sciprint("done.\n"); + } + sciprint("\n# Training the KNN classifier..."); + + Ptr knearest = KNearest::create(); + + try + { + knearest->setAlgorithmType(algorithmType); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + try + { + knearest->train(trainingData, ml::ROW_SAMPLE, labels); + transpose(trainingData, trainingData); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + try + { + knearest->save(classifierLocation); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + return 0; + } + + /*------ Create output arguments ------*/ + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 4, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 1, 1, 1, &objectType); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 2, 1, 1, &classifierLocation); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 3, 1, 1, &bagOfFeaturesLocation); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 4, descriptionCount, 1, description); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + /*------ Return Arguments ------*/ + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + ReturnArguments(pvApiCtx); + return 0; + } + /* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_trainLRClassifier.cpp b/sci_gateway/cpp/opencv_trainLRClassifier.cpp new file mode 100644 index 0000000..885b132 --- /dev/null +++ b/sci_gateway/cpp/opencv_trainLRClassifier.cpp @@ -0,0 +1,696 @@ +/*************************************************** +Author : Siddhant Narang +***************************************************/ +#include +#include +#include +#include +#include +#include + + +inline bool file_exists_check(const std::string& name) +{ + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0); +} + + +using namespace std; +using namespace cv; +using namespace cv::xfeatures2d; +using namespace cv::ml; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + + + int opencv_trainLRClassifier(char *fname, unsigned long fname_len) + { + // Error management variables + SciErr sciErr; + + //------Local variables------// + int upright = 1; + Ptr matcher = DescriptorMatcher::create("FlannBased"); + Ptr detector = SURF::create(400, 4, 2, 1, upright); + Ptr extractor = detector; + Ptr bowDE = makePtr(extractor, matcher); + char *fileName = NULL; + Mat dictionary,inp,features; + vector keyPoints; + + int iRet = 0; + int iPrec = 0; + int iBool = 0; + int *piAddr = NULL; + int *piChild = NULL; + int iRows, iCols; + char **pstData = NULL; + int *piLen = NULL; + int *count = NULL; + char **description = NULL; + char ***location = NULL; + char *bagOfFeaturesLocation = NULL; + int descriptionCount; + + double learningRate = 1.0; + double iteration = 100; + double regularization = 1; + double trainMethod = 0; + double miniBatchSize = 10; + + char *classifierName = NULL; + char *classifierLocation = NULL; + char *objectType = "LRClassifier"; + //------Check number of parameters------// + CheckInputArgument(pvApiCtx, 2, 8); + CheckOutputArgument(pvApiCtx, 1, 1); + + //------Get input arguments------// + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #1 is not of type imageSet.\n"); + return 0; + } + + // Extracting object type and checking if type is imageSet + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1)); // + 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"imageSet")==0)) + { + Scierror(999, "Error: The input argument #1 is not of type imageSet.\n"); + return 0; + } + + // Extracting Description attribute of input argument + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + description = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + description[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, description); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + descriptionCount = iRows; + + // Extracting Count attribute of input argument + sciErr = getMatrixOfInteger32InList(pvApiCtx, piAddr, 3, &iRows, &iCols, &count); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + location = (char***) malloc(sizeof(char**) * descriptionCount); + + // Extracting Location of images from input argument. + sciErr = getListItemAddress(pvApiCtx, piAddr, 4, &piChild); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + for(int iter = 1; iter<=descriptionCount; iter++) + { + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + location[iter-1] = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int colIter = 0 ; colIter < iRows * iCols ; colIter++) + { + location[iter-1][colIter] = (char*)malloc(sizeof(char) * (piLen[colIter] + 1));//+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piChild, iter, &iRows, &iCols, piLen, location[iter-1]); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + } + + // Check is imageSet is in pwd. + if(!file_exists_check(location[0][1])) + { + Scierror(999, "Error: Image set not found in the pwd.\n"); + return 0; + } + + // Second argument + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(!isListType(pvApiCtx, piAddr)) + { + Scierror(999, "Error: The input argument #2 is not of type bagOfFeatures.\n"); + return 0; + } + + // Extracting object type and checking if type is bagOfFeatures + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, NULL, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*)malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, NULL); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**)malloc(sizeof(char*) * iRows * iCols); + + for(int iter = 0 ; iter < iRows * iCols ; iter++) + { + pstData[iter] = (char*)malloc(sizeof(char) * (piLen[iter] + 1)); //+ 1 for null termination + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 1, &iRows, &iCols, piLen, pstData); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!(strcmp(pstData[0],"bagOfFeatures")==0)) + { + Scierror(999, "Error: The input argument #2 is not of type bagOfFeatures.\n"); + return 0; + } + // Extracting name of next argument takes three calls to getMatrixOfString + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + piLen = (int*) malloc(sizeof(int) * iRows * iCols); + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + pstData = (char**) malloc(sizeof(char*) * iRows * iCols); + for(int iterPstData = 0; iterPstData < iRows * iCols; iterPstData++) + { + pstData[iterPstData] = (char*) malloc(sizeof(char) * piLen[iterPstData] + 1); + } + + sciErr = getMatrixOfStringInList(pvApiCtx, piAddr, 2, &iRows, &iCols, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=1 || iCols!=1) + { + Scierror(999, "1x1 Matrix expected for bagOfFeatures argument."); + return 0; + } + bagOfFeaturesLocation = pstData[0]; + + // Check is bagOfFeatures.yml is in pwd. + if(!file_exists_check(bagOfFeaturesLocation)) + { + Scierror(999, "Error: Bag of Features "".yml"" file not found in the pwd.\n"); + return 0; + } + + // Handling 3rd argument. + sciErr = getVarAddressFromPosition(pvApiCtx, 3, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isStringType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + char* stringData = NULL; + + iRet = getAllocatedSingleString(pvApiCtx, piAddr, &stringData); + if(!iRet) + { + classifierName = stringData; + } + else + { + Scierror(999, "Error: Could not assign input arg #3 to local var.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #3 is not a string.\n"); + return 0; + } + + // Handling more than 3 arguments. + if(*getNbInputArgument(pvApiCtx) > 3) + { + sciErr = getVarAddressFromPosition(pvApiCtx, 4, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isDoubleType(pvApiCtx, piAddr)) + { + + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + learningRate = dData; + } + } + else + { + Scierror(999, "Error: The input argument #4 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #4 is not of type Double.\n"); + return 0; + } + } + + // Handling more than 4 arguments. + if(*getNbInputArgument(pvApiCtx) > 4) + { + sciErr = getVarAddressFromPosition(pvApiCtx, 5, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + iteration = dData; + } + } + else + { + Scierror(999, "Error: The input argument #5 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #5 is not of type Integer.\n"); + return 0; + } + } + + // Handling more than 5 arguments. + if(*getNbInputArgument(pvApiCtx) > 5) + { + sciErr = getVarAddressFromPosition(pvApiCtx, 6, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + if(dData < -1 || dData > 1) + { + Scierror(999, "Error: The input argument ""regularization"" should be in range [-1, 1].\n"); + return 0; + } + + regularization = dData; + } + } + else + { + Scierror(999, "Error: The input argument #6 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #6 is not of type Integer.\n"); + return 0; + } + } + + // Handling more than 6 arguments. + if(*getNbInputArgument(pvApiCtx) > 6) + { + sciErr = getVarAddressFromPosition(pvApiCtx, 7, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + if(!(dData >= 0 && dData <= 1)) + { + Scierror(999, "Error: The input argument ""trainMethod"" should be in range [0, 1].\n"); + return 0; + } + trainMethod = dData; + } + } + else + { + Scierror(999, "Error: The input argument #7 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #7 is not of type Integer.\n"); + return 0; + } + } + + // Handling more than 7 arguments. + if(*getNbInputArgument(pvApiCtx) > 7) + { + sciErr = getVarAddressFromPosition(pvApiCtx, 8, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(isIntegerType(pvApiCtx, piAddr) || isDoubleType(pvApiCtx, piAddr)) + { + + if(isScalar(pvApiCtx, piAddr)) + { + double dData = 0; + iRet = getScalarDouble(pvApiCtx, piAddr, &dData); + if(!iRet) + { + miniBatchSize = dData; + } + } + else + { + Scierror(999, "Error: The input argument #8 is not of scalar type.\n"); + return 0; + } + } + else + { + Scierror(999, "Error: The input argument #8 is not of type Integer.\n"); + return 0; + } + } + + classifierLocation = classifierName; + strcat(classifierLocation, ".yml"); + + //------Actual processing------// + FileStorage fs(bagOfFeaturesLocation, FileStorage::READ); + fs["dictionary"] >> dictionary; + fs.release(); + if(dictionary.rows==0 || dictionary.cols==0) + { + sciprint("Error: The provided file for bagOfFeatures may be invalid.\n"); + } + sciprint("Training an image category classifier for %d classes.\n",descriptionCount); + sciprint("-------------------------------------------------------\n\n"); + for(int i=0;isetVocabulary(dictionary); + for(int i=0; idetect(inp,keyPoints); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + try + { + bowDE->compute(inp, keyPoints,features); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + trainingData.push_back(features); + labels.push_back((float) i); + } + sciprint("done.\n"); + } + sciprint("\n# Training the Logistic Regression classifier..."); + + Ptr p = LogisticRegression::create(); + Ptr tdata = TrainData::create(trainingData, ml::ROW_SAMPLE, labels); + + try + { + p->setLearningRate(learningRate); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + try + { + p->setIterations(iteration); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + try + { + p->setRegularization(regularization); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + try + { + p->setTrainMethod(trainMethod); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + try + { + if(trainMethod == 1) + { + p->setMiniBatchSize(miniBatchSize); + } + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + try + { + p->train(tdata); + trainingData = tdata->getSamples(); + transpose(trainingData, trainingData); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + try + { + p->save(classifierLocation); + } + catch(cv::Exception &e) + { + const char *err = e.what(); + sciprint("%s", err); + } + + sciprint("done.\n"); + //------Create output arguments------// + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 4, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 1, 1, 1, &objectType); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 2, 1, 1, &classifierLocation); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 3, 1, 1, &bagOfFeaturesLocation); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = createMatrixOfStringInList(pvApiCtx, nbInputArgument(pvApiCtx)+1, piAddr, 4, descriptionCount, 1, description); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + //------Return Arguments------// + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx)+1; + ReturnArguments(pvApiCtx); + return 0; + } + /* ==================================================================== */ +} diff --git a/sci_gateway/cpp/opencv_whitepoint.cpp b/sci_gateway/cpp/opencv_whitepoint.cpp new file mode 100644 index 0000000..e43af0e --- /dev/null +++ b/sci_gateway/cpp/opencv_whitepoint.cpp @@ -0,0 +1,121 @@ +/******************************************************** +Function: whitepoint +Syntax : B = whitepoint(string) +String : 'd65', 'd50', 'a', 'icc', 'c', 'd55' +Author : Tess Zacharias +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include +#include "string.h" + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include "sciprint.h" + #include "../common.h" + + int opencv_whitepoint(char *fname, unsigned long fname_len) + { + // Error management variable + SciErr sciErr; + + //variable info + int* piAddr1 = NULL; + int error; + int iRet = 0; + char* pstData = NULL; + + //checking input argument + CheckInputArgument(pvApiCtx, 1, 1); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr1); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(isStringType(pvApiCtx, piAddr1)) + { + if(isScalar(pvApiCtx, piAddr1)) + { + iRet = getAllocatedSingleString(pvApiCtx, piAddr1, &pstData); + } + } + + double *output = NULL; + int k = 0; + output = (double *)malloc(sizeof(double) * 3); + + if(strcmp(pstData, "d65") == 0) + { + output[0] = 0.9504; + output[1] = 1.0000; + output[2] = 1.0889; + } + + else if(strcmp(pstData, "d50") == 0) + { + output[0] = 0.9642; + output[1] = 1.0000; + output[2] = 0.8251; + } + + else if(strcmp(pstData, "icc") == 0) + { + output[0] = 0.9642; + output[1] = 1.0000; + output[2] = 0.8249; + } + + else if(strcmp(pstData, "a") == 0) + { + output[0] = 1.0985; + output[1] = 1.0000; + output[2] = 0.3558; + } + + else if(strcmp(pstData, "d55") == 0) + { + output[0] = 0.9568; + output[1] = 1.0000; + output[2] = 0.9214; + } + + else if(strcmp(pstData, "c") == 0) + { + output[0] = 0.9807; + output[1] = 1.0000; + output[2] = 1.1823; + } + + else + { + sciprint("Expected input number 1: to match one of these strings:'icc', 'd50', 'd55', 'd65', 'c', 'a'"); + return 0; + } + + sciErr = createMatrixOfDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 1, 3, output); + free(output); // Data have been copied into Scilab memory + if (sciErr.iErr) + { + //Make sure everything is cleanup in case of error + printError(&sciErr, 0); + return 0; + } + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + ReturnArguments(pvApiCtx); + return 0; + } +} From ed9ab2c5b4464b74725fd7113160c3eeeae34315 Mon Sep 17 00:00:00 2001 From: Siddhant Narang Date: Wed, 8 Nov 2017 23:15:29 +0530 Subject: [PATCH 2/4] Add files via upload --- sci_gateway/cpp/opencv_blobAnalysis.cpp | 479 ++++++++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100644 sci_gateway/cpp/opencv_blobAnalysis.cpp diff --git a/sci_gateway/cpp/opencv_blobAnalysis.cpp b/sci_gateway/cpp/opencv_blobAnalysis.cpp new file mode 100644 index 0000000..be917d5 --- /dev/null +++ b/sci_gateway/cpp/opencv_blobAnalysis.cpp @@ -0,0 +1,479 @@ +/******************************************************** +Author : Deepshikha +[key_value] : blobAnalysis(source_image) + +// 1 :image +Optional arguments :- +// 2 : filterByArea +// 3 : filterByThreshold +// 4 : filterByCircularity +// 5 : filterByConvexity +********************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/features2d/features2d.hpp" +#include + +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_blobAnalysis(char *fname, unsigned long fname_len) + { + + // Error management variable + SciErr sciErr; + + //Variables + // int i, j; + int i = 0; + int intErr; + int iRows1 = 0; + int iCols1 = 0; + + int iRows = 0; + int iCols = 0; + int *piLen = NULL; + int *piAddr = NULL; + char **pstData = NULL; + char *currentArg = NULL; + bool *providedArgs = NULL; + + double *area = NULL; + double *threshold = NULL; + double *circularity = NULL; + double *convexity = NULL; + double *ROImat = NULL; + double *key_value = NULL; + + // checking input argument + // 1 : image + // 2 : filterByArea + // 3 : filterByThreshold + // 4 : filterByCircularity + // 5 : ROI + // 6 : filterByConvexity + CheckInputArgument(pvApiCtx, 1, 11); + CheckOutputArgument(pvApiCtx, 1, 1); + + // retrieve image + Mat image; + retrieveImage(image, 1); + + // For the optional arguments + int nbInputArguments = *getNbInputArgument(pvApiCtx); + //sciprint("%d\n",nbInputArguments); + + if((nbInputArguments%2) == 0) + { + Scierror(999, "%d: The number of arguments must be odd\n"); + return 0; + } + + providedArgs = (bool*) malloc(sizeof(bool) * 5); + memset(providedArgs, 0, 5); + + for(int iter = 2; iter <= nbInputArguments; ++iter) + { + sciErr = getVarAddressFromPosition(pvApiCtx, iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + /// Three calls to getMatrixOfString + //First Call + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows, &iCols, NULL, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // Second call to get length of string + piLen = (int*) malloc(sizeof(int) * iRows1 * iCols1); + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows1, &iCols1, piLen, NULL); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // third call + pstData = (char**) malloc(sizeof(char*) * iRows1 * iCols1); + for(int k = 0; k < iRows1 * iCols1; ++k) + { + pstData[k] = (char*) malloc(sizeof(char) * piLen[k] + 1); + } + + sciErr = getMatrixOfString(pvApiCtx, piAddr, &iRows1, &iCols1, piLen, pstData); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + currentArg = pstData[0]; + + // getting filterbyArea + if(strcmp(currentArg, "filterByArea") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[0]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows1, &iCols1, &area); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(iRows1 != 1 or iCols1 != 2) + { + Scierror(999, "Incorrect dimension of matrix for argument .\n"); + return 0; + } + providedArgs[0] = 1; + } + else if(providedArgs[0]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + /// filterbyThreshold + else if(strcmp(currentArg, "filterByThreshold") == 0) + { + if(iter+1 <= nbInputArguments && !providedArgs[1]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows1, &iCols1, &threshold); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(iRows1 != 1 or iCols1 != 2) + { + Scierror(999, "Incorrect dimension of matrix for argument .\n"); + return 0; + } + + // Checking if values are in proper range. Same for all optional arguments + providedArgs[1] = 1; + } + else if(providedArgs[1]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + /// filterbycircularity + else if(strcmp(currentArg, "filterByCircularity") == 0) + { + if(iter+1 <= nbInputArguments && !providedArgs[2]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows1, &iCols1, &circularity); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(iRows1 != 1 or iCols1 != 2) + { + Scierror(999, "Incorrect dimension of matrix for argument .\n"); + return 0; + } + + // Checking if values are in proper range. Same for all optional arguments + providedArgs[2] = 1; + } + else if(providedArgs[2]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + else if(strcmp(currentArg,"ROI")==0) + { + // val_position=i+1; + + if(providedArgs[3] == 1) + { + Scierror(999,"Do not enter the same parameter\n"); + return 0; + } + + sciErr = getVarAddressFromPosition(pvApiCtx, i + 1, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(!isDoubleType(pvApiCtx, piAddr) || isVarComplex(pvApiCtx, piAddr)) + { + Scierror(999,"Enter a List of 4 arguments\n"); + return 0; + } + + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows, &iCols, &ROImat); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows*iCols!=4) + { + Scierror(999,"Invalid Argument\n"); + return 0; + } + + if(ROImat[0]<0 || ROImat[1]<0 || ROImat[2]<0 || ROImat[3]<0) + { + Scierror(999,"Arguments cannot be negative\n"); + return 0; + } + + if(ROImat[0]>image.cols || ROImat[1]>image.rows || ROImat[0]+ROImat[2]>image.cols + || ROImat[1]+ROImat[3]>image.rows) + { + Scierror(999,"Please make sure the arguments are within the image range\n"); + return 0; + } + + providedArgs[3] = 1; + } + + /// filterbyConvexity + else if(strcmp(currentArg, "filterByConvexity") == 0) + { + if(iter + 1 <= nbInputArguments and !providedArgs[4]) + { + sciErr = getVarAddressFromPosition(pvApiCtx, ++iter, &piAddr); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr, &iRows1, &iCols1, &convexity); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + if(iRows1 != 1 or iCols1 != 2) + { + Scierror(999, "Incorrect dimension of matrix for argument .\n"); + return 0; + } + + providedArgs[4] = 1; + } + else if(providedArgs[4]) // Send an error message if an argument is provided more than once. Same for all optional arguments. + { + Scierror(999, "Please provide optional arguments only once.\n"); + return 0; + } + else // Send an error message if name of argument is given but type is incorrect. Same for all optional arguments. + { + Scierror(999, "Incorrect number of arguments provided. Please check the documentation for more information.\n"); + return 0; + } + } + + else + { + Scierror(9,"Invalid argument passed"); + return 0; + } + } + /// End of error check and input get; + + /// params for holding the parameters values; + SimpleBlobDetector::Params params; + + /// if area is provided + if(providedArgs[0] == 1) + { + params.filterByArea = true; + params.minArea = area[0]; + params.maxArea = area[1]; + } + + /// if threshold is provided + if(providedArgs[1] == 1) + { + sciprint("%d %d", int(threshold[0]), int(threshold[1])); + params.minThreshold = int(threshold[0]); + params.maxThreshold = int(threshold[1]); + } + + /// if Circularity is provided + if(providedArgs[2] == 1) + { + params.filterByCircularity = true; + params.minCircularity = circularity[0]; + params.maxCircularity = circularity[1]; + } + + if(providedArgs[3]==0) + { + ROImat=(double *)malloc(sizeof(double)*1*4); + ROImat[0]=0; + ROImat[1]=0; + ROImat[2]=image.cols; + ROImat[3]=image.rows; + } + + Rect masker(ROImat[0], ROImat[1], ROImat[2], ROImat[3]); + Mat mask(image.size(), CV_8UC1, Scalar::all(0)); + + // Creating ROI + try + { + mask(masker).setTo(Scalar::all(255)); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + } + + /// if convexity is provided + if(providedArgs[4] == 1) + { + params.filterByConvexity = true; + params.minConvexity = convexity[0]; + params.maxConvexity = convexity[1]; + } + + Ptr detector = SimpleBlobDetector::create(params); + /// to store the keypoints of blobs detected + vector keyPoints; + Mat descriptors; + + try + { + image.convertTo(image, CV_8UC1); + /// fuction to detect blob in the image + detector->detect(image, keyPoints); + } + catch(Exception &e) + { + const char *err = e.what(); + Scierror(999, "%s", err); + return 0; + } + + key_value = (double*)malloc(sizeof(double) * (int)keyPoints.size() * 2); + + double *size_value = NULL; + size_value = (double*)malloc(sizeof(double) * (int)keyPoints.size() * 1); + + int total_keypoints = (int)keyPoints.size(); + + vector< KeyPoint >::iterator it; + + i = 0; + for(it = keyPoints.begin(); it != keyPoints.end(); ++it) + { + KeyPoint temp = keyPoints[i]; + + // x coordinate + key_value[i + 0 * total_keypoints] = it->pt.x; + + // y coordinate + key_value[i + 1 * total_keypoints] = it->pt.y; + + // size + size_value[i + 0 * total_keypoints] = (int)it->size; + + //area + //key_value[i + 3 * total_keypoints] = it->Area; + i++; + } + + // Creating output arguments + sciErr = createList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, 2, &piAddr); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 1, total_keypoints, 2, key_value); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 2, total_keypoints, 1, size_value); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + // sciErr = createMatrixOfDoubleInList(pvApiCtx, nbInputArgument(pvApiCtx) + 1, piAddr, 3, 1, dcols, _descriptors); + // if(sciErr.iErr) + // { + // printError(&sciErr, 0); + // return 0; + // } + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + } +/* ==================================================================== */ +} From 26775288c4b2b5742233f458ba6781f7defe70f3 Mon Sep 17 00:00:00 2001 From: Siddhant Narang Date: Wed, 8 Nov 2017 23:23:16 +0530 Subject: [PATCH 3/4] Add files via upload --- sci_gateway/cpp/opencv_triangulatePoints.cpp | 166 +++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 sci_gateway/cpp/opencv_triangulatePoints.cpp diff --git a/sci_gateway/cpp/opencv_triangulatePoints.cpp b/sci_gateway/cpp/opencv_triangulatePoints.cpp new file mode 100644 index 0000000..4ee38bd --- /dev/null +++ b/sci_gateway/cpp/opencv_triangulatePoints.cpp @@ -0,0 +1,166 @@ +/*************************************************** +Author : Deepshikha +***************************************************/ + +#include +#include "opencv2/core/core.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/opencv.hpp" +#include "opencv2/calib3d/calib3d.hpp" +#include +using namespace cv; +using namespace std; + +extern "C" +{ + #include "api_scilab.h" + #include "Scierror.h" + #include "BOOL.h" + #include + #include + #include "../common.h" + + int opencv_triangulatePoints(char *fname, unsigned long fname_len) + { + //variables + int i,j,n,m; + int iRows=0,iCols=0; + int *piAddr1 = NULL; + int *piAddr2 = NULL; + int *piAddr3 = NULL; + int *piAddr4 = NULL; + + double *pdblReal = NULL; + + SciErr sciErr; + + /*------------------------------------------- Checking Input Argument ----------------------------------------------------*/ + + CheckInputArgument(pvApiCtx, 4, 4); + CheckOutputArgument(pvApiCtx, 1, 1) ; + + /*------------------------------------- Projection matrix 1 :- First argument of the input -------------------------------------*/ + + sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr1); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr1, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=3 or iCols!=4){ + Scierror(iRows,"Projection matrix (arg 1) must be a 3 X 4 matrix"); + return 0; + } + Mat projMat1(iRows, iCols, CV_64F); + for(i = 0; i < iRows; i++) + for(j = 0; j < iCols; j++){ + projMat1.at(i,j) = pdblReal[i + (j * iRows)]; + } + + /* ------------------------------------ Projection matrix 2 :- Second argument of the input -------------------------------------*/ + + sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr2, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + if(iRows!=3 or iCols!=4){ + Scierror(iRows,"Projection matrix (arg 2) must be a 3 X 4 matrix"); + return 0; + } + Mat projMat2(iRows, iCols, CV_64F); + for(i=0;i(i,j) = pdblReal[i + (j * iRows)]; + + + /* ------------------------------------ Points matrix 1 :- Third argument of the input -------------------------------------*/ + + sciErr = getVarAddressFromPosition(pvApiCtx,3,&piAddr3); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr3, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + n = iCols; + if(iRows!=2){ + Scierror(iRows,"Points matrix (arg 3) must be a 2 X N matrix"); + return 0; + } + Mat newPoint1(2, iCols, CV_64F); + for(i = 0; i < 2; i++) + for(j = 0; j < iCols; j++) + newPoint1.at(i,j) = pdblReal[ i + ( j * iRows )]; + + + /* ------------------------------------ Points matrix 2 :- Fourth argument of the input -------------------------------------*/ + + sciErr = getVarAddressFromPosition(pvApiCtx, 4, &piAddr4); + if (sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + sciErr = getMatrixOfDouble(pvApiCtx, piAddr4, &iRows, &iCols, &pdblReal); + if(sciErr.iErr) + { + printError(&sciErr, 0); + return 0; + } + + m = iCols; + if(iRows!=2){ + Scierror(iRows,"Points matrix (arg 4) must be a 2 X N matrix"); + return 0; + } + Mat newPoint2(iRows, iCols, CV_64F); + for(i = 0; i < iRows; i++) + for(j = 0; j < iCols; j++) + newPoint2.at(i,j) = pdblReal[ i + ( j * iRows )]; + + if(n!=m){ + Scierror(n,"No of columns of arg 3 and arg 4 must be same"); + return 0; + } + Mat new_image(4, n, CV_64F); + + triangulatePoints(projMat1, projMat2, newPoint1, newPoint2, new_image); + + string tempstring = type2str(new_image.type()); + char *checker; + checker = (char *)malloc(tempstring.size() + 1); + memcpy(checker, tempstring.c_str(), tempstring.size() + 1); + returnImage(checker,new_image,1); + free(checker); + + + //Assigning the list as the Output Variable + AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; + //Returning the Output Variables as arguments to the Scilab environment + ReturnArguments(pvApiCtx); + return 0; + + } +/* ==================================================================== */ +} \ No newline at end of file From 8dfbdbdfd38c73dc8a02d1a25678c4a6a724fe18 Mon Sep 17 00:00:00 2001 From: Siddhant Narang Date: Wed, 8 Nov 2017 23:24:03 +0530 Subject: [PATCH 4/4] Update triangulatePoints.sci --- macros/triangulatePoints.sci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macros/triangulatePoints.sci b/macros/triangulatePoints.sci index ac94b1e..6adc814 100644 --- a/macros/triangulatePoints.sci +++ b/macros/triangulatePoints.sci @@ -36,7 +36,7 @@ function points4D = triangulatePoints(projMat1, projMat2, points1, points2) // Deepshikha - points4D = raw_triangulatePoints(projMat1, projMat2, points1, points2) + points4D = opencv_triangulatePoints(projMat1, projMat2, points1, points2) endfunction