diff --git a/AdvancedVision/AdvancedVision.sln b/AdvancedVision/AdvancedVision.sln index 32d916b..ae2249e 100644 --- a/AdvancedVision/AdvancedVision.sln +++ b/AdvancedVision/AdvancedVision.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.12 +# Visual Studio 14 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AdvancedVision", "AdvancedVision.vcxproj", "{D07114EF-4EC2-45EE-944D-5A269C142C0F}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AdvancedVision", "AdvancedVision.vcxproj", "{E2412F90-006E-4A20-B924-F7D795DB8241}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NeuralDetector", "..\NeuralDetector\NeuralDetector.vcxproj", "{E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,19 +15,24 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Debug|x64.ActiveCfg = Debug|x64 - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Debug|x64.Build.0 = Debug|x64 - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Debug|x86.ActiveCfg = Debug|Win32 - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Debug|x86.Build.0 = Debug|Win32 - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Release|x64.ActiveCfg = Release|x64 - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Release|x64.Build.0 = Release|x64 - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Release|x86.ActiveCfg = Release|Win32 - {D07114EF-4EC2-45EE-944D-5A269C142C0F}.Release|x86.Build.0 = Release|Win32 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Debug|x64.ActiveCfg = Debug|x64 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Debug|x64.Build.0 = Debug|x64 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Debug|x86.ActiveCfg = Debug|Win32 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Debug|x86.Build.0 = Debug|Win32 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Release|x64.ActiveCfg = Release|x64 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Release|x64.Build.0 = Release|x64 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Release|x86.ActiveCfg = Release|Win32 + {E2412F90-006E-4A20-B924-F7D795DB8241}.Release|x86.Build.0 = Release|Win32 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Debug|x64.ActiveCfg = Debug|x64 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Debug|x64.Build.0 = Debug|x64 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Debug|x86.ActiveCfg = Debug|Win32 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Debug|x86.Build.0 = Debug|Win32 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Release|x64.ActiveCfg = Release|x64 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Release|x64.Build.0 = Release|x64 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Release|x86.ActiveCfg = Release|Win32 + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {718B94D4-63F0-4DFC-84A7-C7CA7AF5ACA9} - EndGlobalSection EndGlobal diff --git a/AdvancedVision/AdvancedVision.vcxproj b/AdvancedVision/AdvancedVision.vcxproj index 3f90d4f..6354a7e 100644 --- a/AdvancedVision/AdvancedVision.vcxproj +++ b/AdvancedVision/AdvancedVision.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -19,36 +19,35 @@ - 15.0 - {d07114ef-4ec2-45ee-944d-5a269c142c0f} + {E2412F90-006E-4A20-B924-F7D795DB8241} Win32Proj AdvancedVision - 10.0.15063.0 + 8.1 Application true - v141 + v140 Unicode Application false - v141 + v140 true Unicode Application true - v141 + v140 Unicode Application false - v141 + v140 true Unicode @@ -84,11 +83,10 @@ - NotUsing + + Level3 - Disabled WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) D:\Code\OpenCV\install\include;%(AdditionalUsingDirectories) @@ -101,11 +99,10 @@ - NotUsing + + Level3 - Disabled _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) D:\Code\OpenCV\install\include;%(AdditionalUsingDirectories) @@ -118,58 +115,65 @@ - NotUsing Level3 - MaxSpeed + + true true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) - D:\Code\OpenCV\install\include;%(AdditionalUsingDirectories) Console true true true - opencv_world330.lib;opencv_world330d.lib;%(AdditionalDependencies) D:\Code\OpenCV\install\x64\vc14\lib;%(AdditionalLibraryDirectories) + opencv_world330.lib;opencv_world330d.lib;%(AdditionalDependencies) - NotUsing Level3 - MaxSpeed + + true true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) - D:\Code\OpenCV\install\include;%(AdditionalUsingDirectories) Console true true true - opencv_world330.lib;opencv_world330d.lib;%(AdditionalDependencies) D:\Code\OpenCV\install\x64\vc14\lib;%(AdditionalLibraryDirectories) + opencv_world330.lib;opencv_world330d.lib;%(AdditionalDependencies) - - - - + + + + + + - + + - + + + + + + + + + diff --git a/AdvancedVision/AdvancedVision.vcxproj.filters b/AdvancedVision/AdvancedVision.vcxproj.filters index fc83533..df5c0c6 100644 --- a/AdvancedVision/AdvancedVision.vcxproj.filters +++ b/AdvancedVision/AdvancedVision.vcxproj.filters @@ -13,29 +13,74 @@ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + {95b73545-78c3-479d-878f-c51a63f4f3bf} + + + {70ee2ada-2a6b-4960-8b07-1bbdb13f0f8a} + - - - - - Source Files - Source Files - + Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files\Features + + + Source Files\Features + + Source Files\Features + + Source Files - + Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\Features + + + Header Files\Features + + Header Files\Features + + Header Files diff --git a/AdvancedVision/BPN.cpp b/AdvancedVision/BPN.cpp new file mode 100644 index 0000000..f67883a --- /dev/null +++ b/AdvancedVision/BPN.cpp @@ -0,0 +1,144 @@ +// Demo: Training of a Neural Network / Back-Propagation algorithm +// Jan Oostindie, Avans Hogeschool, dd 6-12-2016 +// email: jac.oostindie@avans.nl + +#include "BPN.h" + + +// Maximale fout die toegestaan wordt in de output voor de training input +const double MAX_OUTPUT_ERROR = 1E-10; + +// maximaal aantal runs dat uitgevoerd wordt bij het trainen +const int MAXRUNS = 10000; + +int run(int argc, char** argv) +{ + // IT, OT: input trainingset, output trainingset + Mat ITset, OTset; + + // V0, W0 : weightfactor matrices + // dV0, dW0 : weightfactor correction matrices + Mat V0, W0, dW0, dV0; + + // default number of hiddenNeurons. The definite number is user input + // inputNeurons and outputNeurons are implicitly determined via + // the trainingset, i.e.: inputNeurons = ITset.cols ; outputNeurons = OTset.cols; + int hiddenNeurons = 2; + + cout << endl << "Load testtrainingset..." << endl << endl; + //loadTrainingSet1(ITset, OTset); + loadBinaryTrainingSet1(ITset, OTset); + + cout << "Training Input " << endl << endl; + cout << ITset << endl << endl; + cout << "Training Output " << endl << endl; + cout << OTset << endl << endl; + + cout << " ===> BPN format: " << endl << + "BPN Inputlayer = " << ITset.cols << " neurons" << endl << + "BPN Outputlayer = " << OTset.cols << " neurons" << endl << endl; + cout << "Please choose a number of hidden neurons: "; + cin >> hiddenNeurons; + cout << "Thank you!" << endl << endl << endl; + + cout << "Initialize BPN ..." << endl; + initializeBPN(ITset.cols, hiddenNeurons, OTset.cols, V0, dV0, W0, dW0); + //testBPN(ITset, OTset, V0, dV0, W0, dW0); + + cout << "initial values of weight matrices V0 and W0" << endl; + cout << "*******************************************" << endl; + cout << V0 << endl << endl << W0 << endl << endl; + cout << "Press ENTER => "; + string dummy; + getline(cin, dummy); + getline(cin, dummy); + + // IT: current training input of the inputlayer + // OT: desired training output of the BPN + // OH: output of the hiddenlayer + // OO: output of the outputlayer + Mat IT, OT, OH, OO; + + // outputError0: error on output for the current input and weighfactors V0, W0 + // outputError1: error on output for the current input and new calculated + // weighfactors, i.e. V1, W1 + double outputError0, outputError1, sumSqrDiffError = MAX_OUTPUT_ERROR + 1; + Mat V1, W1; + + int runs = 0; + while ((sumSqrDiffError > MAX_OUTPUT_ERROR) && (runs < MAXRUNS)) { + + sumSqrDiffError = 0; + + for (int inputSetRowNr = 0; inputSetRowNr < ITset.rows; inputSetRowNr++) { + + IT = transpose(getRow(ITset, inputSetRowNr)); + + OT = transpose(getRow(OTset, inputSetRowNr)); + + calculateOutputHiddenLayer(IT, V0, OH); + + calculateOutputBPN(OH, W0, OO); + + adaptVW(OT, OO, OH, IT, W0, dW0, V0, dV0, W1, V1); + + calculateOutputBPNError(OO, OT, outputError0); + + calculateOutputBPNError(BPN(IT, V1, W1), OT, outputError1); + + sumSqrDiffError += (outputError1 - outputError0) * (outputError1 - outputError0); + + V0 = V1; + W0 = W1; + } + cout << "sumSqrDiffError = " << sumSqrDiffError << endl; + runs++; + } + + cout << "BPN Training is ready!" << endl << endl; + cout << "Runs = " << runs << endl << endl; + + Mat inputVectorTrainingSet, outputVectorTrainingSet, outputVectorBPN; + + // druk voor elke input vector uit de trainingset de output vector uit trainingset af + // tezamen met de output vector die het getrainde BPN (zie V0, W0) genereerd bij de + // betreffende input vector. + cout << setw(16) << " " << "Training Input" << setw(12) << "|" << " Expected Output " + << setw(1) << "|" << " Output BPN " << setw(6) << "|" << endl << endl; + for (int row = 0; row < ITset.rows; row++) { + + // haal volgende inputvector op uit de training set + inputVectorTrainingSet = transpose(getRow(ITset, row)); + + // druk de inputvector af in een regel afgesloten met | + for (int r = 0; r < inputVectorTrainingSet.rows; r++) + cout << setw(8) << getEntry(inputVectorTrainingSet, r, 0); + cout << setw(2) << "|"; + + // haal bijbehorende outputvector op uit de training set + outputVectorTrainingSet = transpose(getRow(OTset, row)); + + // druk de outputvector van de training set af in dezelfde regel afgesloten met | + for (int r = 0; r < outputVectorTrainingSet.rows; r++) + cout << setw(8) << round(getEntry(outputVectorTrainingSet, r, 0)); + cout << setw(2) << "|"; + + // bepaal de outputvector die het getrainde BPN oplevert + // bij de inputvector uit de trainingset + outputVectorBPN = BPN(inputVectorTrainingSet, V0, W0); + + // druk de output vector van het BPN af in dezelfde regel afgesloten met | + for (int r = 0; r < outputVectorBPN.rows; r++) + cout << setw(8) << round(getEntry(outputVectorBPN, r, 0)); + cout << setw(2) << "|"; + + cout << endl; + } + + cout << endl << endl << "Press ENTER for exit"; + getline(cin, dummy); + getline(cin, dummy); + + return 0; +} + diff --git a/AdvancedVision/BPN.h b/AdvancedVision/BPN.h new file mode 100644 index 0000000..785e597 --- /dev/null +++ b/AdvancedVision/BPN.h @@ -0,0 +1,11 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "avansvisionlib20.h" // versie 2.0 (!) + +int run(int argc, char ** argv); diff --git a/AdvancedVision/BoundingBox.cpp b/AdvancedVision/BoundingBox.cpp index 468af8e..05bb1b6 100644 --- a/AdvancedVision/BoundingBox.cpp +++ b/AdvancedVision/BoundingBox.cpp @@ -80,6 +80,7 @@ int BoundingBox::split(const vector> & contours, const Mat &image, Rect r = Rect(center.x - (largest.width / 2), center.y - (largest.height / 2),largest.width, largest.height); Mat roi(image, r); + //imshow(name, roi); imwrite("output/" + name + "_" + to_string(nr) + ".bmp", roi); nr++; diff --git a/AdvancedVision/Calibrate.cpp b/AdvancedVision/Calibrate.cpp new file mode 100644 index 0000000..08f4349 --- /dev/null +++ b/AdvancedVision/Calibrate.cpp @@ -0,0 +1,268 @@ +// Demonstratie: camera callibratie met schaakbord patroon +// saven van de callibratie data in een yml-file +// Jan Oostindie, dd 16-3-2015 +// bron: www.aishack.in + +#include "Calibrate.h" + +int calibrateCamera() { + // The number of boards you want to capture, the number of internal corners horizontally + // and the number of internal corners vertically (That's just how the algorithm works). + int numBoards = 10; + int numCornersHor = 9; + int numCornersVer = 6; + + // We also create some additional variables that we'll be using later on. + int numSquares = numCornersHor * numCornersVer; + Size board_sz = Size(numCornersHor, numCornersVer); + + // We want live feed for our calibration! + VideoCapture capture(1); + + if (!capture.isOpened()) { //check if video device has been initialised + cout << "cannot open camera"; + } + + // - object_points is the physical position of the corners (in 3D space). + // This has to be measured by us. + // - image_points is the location of the corners in the image (in 2 dimensions). + // - Once the program has actual physical locations and locations on the image, it can calculate + // the relation between the two. Because we'll use a chessboard, these points have a definite + // relations between them (they lie on straight lines and on squares). + // - So the "expected" - "actual" relation can be used to correct the distortions in the image. + vector> object_points; + vector> image_points; + + // Next, we create a list of corners. This will temporarily hold the current snapshot's chessboard corners. + // keep track of the number of successfully captured chessboards + vector corners; + int successes = 0; + + // - Create a list of coordinates (0,0,0), (0,1,0), (0,2,0)...(1,4,0)... so on. + // Each corresponds to a particular vertex. + // - You're essentially setting up the units of calibration. + // Suppose the squares in your chessboards were 30 mm in size and you supplied these + // coordinates as (0,0,0), (0, 30, 0), etc, you'd get all unknowns in millimeters. + vector obj; + for (int j = 0; j < numSquares; j++) + obj.push_back(Point3f(j / numCornersHor, j%numCornersHor, 0.0f)); + + // Then we create two images and get the first snapshot from the camera: + Mat image; + Mat gray_image; + capture >> image; + + // As long as the number of successful entries has been less than the number required, + // we keep looping: + while (successes < numBoards) + { + // convert to gray scale + cvtColor(image, gray_image, CV_BGR2GRAY); + + // And we're here. The key functions: + // findChessboardCorners tries to find a chessboard in the image. + // IF found THEN the rough corners are returned. + bool found = findChessboardCorners(image, board_sz, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS); + if (found) + { + // cornerSubPix refines the found corners. + // De rough corners returned by findChessbooardCorners and the gray_image are input, + // the refined corners are output. + cornerSubPix(gray_image, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1)); + + // draw the refined corners on the image i.e. chessboard. + drawChessboardCorners(gray_image, board_sz, corners, found); + } + + // show results + imshow("orginal", image); + imshow("gray image", gray_image); + + capture >> image; + + int key = waitKey(1); + + // Leave the program by pressing ESC-key + if (key == 27) return 0; + + // spacebar and chessboard found ==> save the snap + if (key == ' ' && found != 0) + { + image_points.push_back(corners); + object_points.push_back(obj); + + printf("Snap stored!"); + + successes++; + + if (successes >= numBoards) + break; + } + } // while + + // Next, we get ready to do the calibration. We declare variables that will hold the unknowns: + // Matrix intrinsic contains cx,cy,fx,fy + // Matrix disCoeffs contains the distortion coefficients: 3 numbers radial distortion and 2 numbers tangential distortion + Mat intrinsic = Mat(3, 3, CV_32FC1); + Mat distCoeffs; + vector rvecs; + vector tvecs; + + // We modify the intrinsic matrix with whatever we know. + // The camera's aspect ratio is 1 (that's usually the case... + // i.e. fx = fy = f. If not, change it as required. + // Elements (0,0) and (1,1) are the focal lengths along the X and Y axis. + intrinsic.ptr(0)[0] = 1; + intrinsic.ptr(1)[1] = 1; + + // Determine the intrinsic matrix, distortion coefficients and the rotation+translation vectors. + // Note: The calibrateCamera function converts all matrices into 64F format even if you + // initialize it to 32F. + calibrateCamera(object_points, image_points, image.size(), intrinsic, distCoeffs, rvecs, tvecs); + + cout << endl << endl << "intrinsic = " << intrinsic << endl << endl; + cout << "distCoeffs = " << distCoeffs << endl; + + /***** saven van de callibratie data *****/ + + // YML-file aanmaken + FileStorage fs("ueyecallib.yml", FileStorage::WRITE); + + // wegschrijven van callibratie data naar de YML-file + fs << "intrinsic" << intrinsic << "distCoeffs" << distCoeffs; + + // de file afsluiten + fs.release(); + + Mat imageUndistorted; + Mat cimage; + bool finished = false; + + while (!finished) + { + capture >> cimage; + undistort(cimage, imageUndistorted, intrinsic, distCoeffs); + + imshow("undistorted", imageUndistorted); + + if (waitKey(100) >= 0) + { + finished = true; + } + } + + destroyAllWindows(); + + return 1; +} + +void setCalibrationAndTakePhotos() { + //lees callibratiedata uit + // YML-file met callibratie data openen + FileStorage fs("ueyecallib.yml", FileStorage::READ); + + // callibratie data ophalen + Mat intrinsic, distCoeffs; + fs["intrinsic"] >> intrinsic; + fs["distCoeffs"] >> distCoeffs; + + // callibratie matrices tonen op het scherm + cout << "intrinsic matrix: " << intrinsic << endl; + cout << "distortion coeffs: " << distCoeffs << endl; + + // sluiten van de YML-file + fs.release(); + + /***** callibratie data gebruiken *****/ + + // Now that we have the distortion coefficients, we can undistort the images. + // Here's a small loop that will do this: + Mat imageUndistorted; + + VideoCapture capture = VideoCapture(1); + Mat image; + bool finished = false; + int run = 1; + + //get filename + std::string filename; + std::cout << "Enter filename: "; + std::getline(std::cin, filename); + + while (!finished) + { + + Mat imageUndistorted; + Mat cimage; + bool done = false; + while (!done) + { + capture >> cimage; + undistort(cimage, imageUndistorted, intrinsic, distCoeffs); + + imshow("undistorted", imageUndistorted); + + if (waitKey(100) >= 0) + { + done = true; + destroyWindow("undistorted"); + } + } + + capture >> image; + undistort(image, imageUndistorted, intrinsic, distCoeffs); + + // De afbeelding converteren naar een grijswaarde afbeelding + Mat gray_image; + cvtColor(imageUndistorted, gray_image, CV_BGR2GRAY); + + // Gray image thresholden + Mat binaryImage; + threshold(gray_image, binaryImage, 165, 1, CV_THRESH_BINARY_INV); + + // Alvorens bewerkingen uit te voeren op het beeld converteren we deze + // naar een Mat object met grotere diepte (depth), t.w. 16 bits signed + Mat binary16S; + binaryImage.convertTo(binary16S, CV_16S); + + // haal de contouren uit het binary image + vector> contours; + int aantal = allContours(binary16S, contours); + + cout << "Found " << aantal << " contours" << endl; + + // Creeer een witte image + IplImage* iplimage = cvCreateImage(cvSize(binary16S.cols, binary16S.rows), IPL_DEPTH_8U, 3); + Mat contourImage = cvarrToMat(iplimage); + contourImage = Scalar(255, 255, 255); + + // teken de contouren op de witte image + drawContours(contourImage, contours, -1, CV_RGB(255, 0, 0)); + + imshow("Contour", contourImage); + + waitKey(0); + + //Split images + FloodFill::largest(contours, image, filename); + + cout << "Finished writing object to disk" << endl; + + waitKey(0); + + destroyWindow("Contour"); + + run++; + } +} + +int startCalibrate() +{ + //calibrateCamera(); + + setCalibrationAndTakePhotos(); + cout << "Program finished" << endl; + waitKey(0); + + return 0; +} \ No newline at end of file diff --git a/AdvancedVision/Calibrate.h b/AdvancedVision/Calibrate.h new file mode 100644 index 0000000..ef84af5 --- /dev/null +++ b/AdvancedVision/Calibrate.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "avansvisionlib20.h" +#include "MooreBoundaryTrackingAlgorithm.h" +#include "BoundingBox.h" +#include "FloodFill.h" + + +int calibrateCamera(); + +void setCalibrationAndTakePhotos(); + +int startCalibrate(); diff --git a/AdvancedVision/FloodFill.cpp b/AdvancedVision/FloodFill.cpp index fc0ed55..9f662e4 100644 --- a/AdvancedVision/FloodFill.cpp +++ b/AdvancedVision/FloodFill.cpp @@ -22,6 +22,9 @@ int FloodFill::enclosedPixels(const vector& contourVec, vector & r regionPixels.push_back(p); st.push(p); + double runs = 0; + double maxruns = 4000000; + while (st.size() > 0) { Point p = st.top(); @@ -45,6 +48,14 @@ int FloodFill::enclosedPixels(const vector& contourVec, vector & r st.push(check); } } + + runs++; + + if (runs > maxruns) + { + cout << "Reached max number of runs" << endl; + break; + } } //floodfill(contourVec, regionPixels, p); @@ -202,11 +213,73 @@ int FloodFill::split(const vector> & contours, const Mat &image, s resultImage.at(Point(p.x - topx, p.y - topy)) = image.at(p); } - imshow("Test", resultImage); - waitKey(0); + //imshow(name, resultImage); imwrite("output/" + name + "_" + to_string(i) + ".bmp", resultImage); } + return 1; +} + +int FloodFill::largest(const vector> & contours, const Mat &image, string filename) +{ + //Create filenames + std::string base_filename = filename.substr(filename.find_last_of("/\\") + 1); + std::string::size_type const p(base_filename.find_last_of('.')); + std::string name = base_filename.substr(0, p); + + vector> bounds; + BoundingBox::allBoundingBoxes(contours, bounds); + + //Find largest bounding box + Size largest = Size(0, 0); + int total = 0; + int bin = -1; + for (int i = 0; i < bounds.size(); i++) + { + vector box = bounds[i]; + + int height = abs(box[2].y - box[1].y); + int width = abs(box[1].x - box[0].x); + int size = height + width; + + if (height > largest.height) + largest.height = height; + if (width > largest.width) + largest.width = width; + + if (size > total) + { + total = size; + bin = i; + } + } + + vector region; + enclosedPixels(contours[bin], region); + + // Creeer een witte image + IplImage* iplimage = cvCreateImage(cvSize(largest.width, largest.height), IPL_DEPTH_8U, 3); + Mat resultImage = cvarrToMat(iplimage); + resultImage = Scalar(255, 255, 255); + + Point center = Point((bounds[bin][0].x + bounds[bin][2].x) / 2, (bounds[bin][0].y + bounds[bin][2].y) / 2); + int topx = center.x - (largest.width / 2); + int topy = center.y - (largest.height / 2); + + //Kopieren van pixels + for (Point p : region) + { + resultImage.at(Point(p.x - topx, p.y - topy)) = image.at(p); + } + for (Point p : contours[bin]) + { + resultImage.at(Point(p.x - topx, p.y - topy)) = image.at(p); + } + + + //imshow(name, resultImage); + imwrite("output/" + name + "_" + to_string(bin) + ".bmp", resultImage); + return 1; } \ No newline at end of file diff --git a/AdvancedVision/FloodFill.h b/AdvancedVision/FloodFill.h index f487a4b..4da8b3f 100644 --- a/AdvancedVision/FloodFill.h +++ b/AdvancedVision/FloodFill.h @@ -20,5 +20,6 @@ public: static Point findStartPoint(vector vec); static int floodfill(const vector & contourVec, vector & regionPixels, Point &p); static int split(const vector> & contours, const Mat &image, string filename); + static int largest(const vector> & contours, const Mat &image, string filename); }; diff --git a/AdvancedVision/Main.cpp b/AdvancedVision/Main.cpp new file mode 100644 index 0000000..586b38e --- /dev/null +++ b/AdvancedVision/Main.cpp @@ -0,0 +1,44 @@ +#include "Main.h" +#include "avansvisionlib20.h" +#include "NeuralNetwork.h" +#include "Calibrate.h" + +int main(int argc, char *argv[]) +{ + startCalibrate(); + + Mat in, out; + + // input of trainingset (without bias) + // remark: nummber of columns == number of inputneurons of the BPN + in = (Mat_(8, 2) << + 0, 0, + 0, 0, + 0, 1, + 0, 1, + 1, 0, + 1, 0, + 1, 1, + 1, 1); + + // output of trainingset + // remark: nummber of columns == number of outputneurons of the BPN + out = (Mat_(8, 1) << + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0); + + run(in, out); + + cout << "Press enter to exit" << endl; + cin.ignore(); + + + return 0; +} + diff --git a/AdvancedVision/Main.h b/AdvancedVision/Main.h new file mode 100644 index 0000000..1000125 --- /dev/null +++ b/AdvancedVision/Main.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace cv; + +int main(int argc, char * argv[]); diff --git a/AdvancedVision/MooreBoundaryTrackingAlgorithm.cpp b/AdvancedVision/MooreBoundaryTrackingAlgorithm.cpp index 9e088cd..7aea84d 100644 --- a/AdvancedVision/MooreBoundaryTrackingAlgorithm.cpp +++ b/AdvancedVision/MooreBoundaryTrackingAlgorithm.cpp @@ -1,5 +1,5 @@ #include "MooreBoundaryTrackingAlgorithm.h" -#include "avansvisionlib.h" +#include "avansvisionlib20.h" //direction values //starting at position 0. Definition of relative positions: @@ -49,10 +49,11 @@ int allContours(Mat binaryImage, vector>& contourVecVec) } while (b0 != firstb0 && b1 != firstb1); - cout << "Klaar met het vinden van contouren" << endl; - - if(contourVec.size() > 4) + if (contourVec.size() > 4) + { + cout << "Klaar met het vinden van contouren" << endl; contourVecVec.push_back(contourVec); + } } return numberOfBlobs; //number of objects diff --git a/AdvancedVision/NeuralNetwork.cpp b/AdvancedVision/NeuralNetwork.cpp new file mode 100644 index 0000000..f62e361 --- /dev/null +++ b/AdvancedVision/NeuralNetwork.cpp @@ -0,0 +1,102 @@ +// Demo: Training of a Neural Network / Back-Propagation algorithm +// Jan Oostindie, Avans Hogeschool, dd 6-12-2016 +// email: jac.oostindie@avans.nl + +#include "NeuralNetwork.h" + +// Maximale fout die toegestaan wordt in de output voor de training input +const double MAX_OUTPUT_ERROR = 1E-10; + +// maximaal aantal runs dat uitgevoerd wordt bij het trainen +const int MAXRUNS = 10000; + +Mat run(Mat ITset, Mat OTset) +{ + // V0, W0 : weightfactor matrices + // dV0, dW0 : weightfactor correction matrices + Mat V0, W0, dW0, dV0; + + // default number of hiddenNeurons. The definite number is user input + // inputNeurons and outputNeurons are implicitly determined via + // the trainingset, i.e.: inputNeurons = ITset.cols ; outputNeurons = OTset.cols; + int hiddenNeurons = 5; + + //loadTrainingSet1(ITset, OTset); + loadBinaryTrainingSet1(ITset, OTset); + initializeBPN(ITset.cols, hiddenNeurons, OTset.cols, V0, dV0, W0, dW0); + //testBPN(ITset, OTset, V0, dV0, W0, dW0); + + + // IT: current training input of the inputlayer + // OT: desired training output of the BPN + // OH: output of the hiddenlayer + // OO: output of the outputlayer + Mat IT, OT, OH, OO; + + // outputError0: error on output for the current input and weighfactors V0, W0 + // outputError1: error on output for the current input and new calculated + // weighfactors, i.e. V1, W1 + double outputError0, outputError1, sumSqrDiffError = MAX_OUTPUT_ERROR + 1; + Mat V1, W1; + + cout << "Starting neural training..." << endl; + + int runs = 0; + while ((sumSqrDiffError > MAX_OUTPUT_ERROR) && (runs < MAXRUNS)) { + + sumSqrDiffError = 0; + + for (int inputSetRowNr = 0; inputSetRowNr < ITset.rows; inputSetRowNr++) { + + IT = transpose(getRow(ITset, inputSetRowNr)); + + OT = transpose(getRow(OTset, inputSetRowNr)); + + calculateOutputHiddenLayer(IT, V0, OH); + + calculateOutputBPN(OH, W0, OO); + + adaptVW(OT, OO, OH, IT, W0, dW0, V0, dV0, W1, V1); + + calculateOutputBPNError(OO, OT, outputError0); + + calculateOutputBPNError(BPN(IT, V1, W1), OT, outputError1); + + sumSqrDiffError += (outputError1 - outputError0) * (outputError1 - outputError0); + + V0 = V1; + W0 = W1; + } + runs++; + } + + cout << "Training complete in " << runs << " runs" << endl; + + Mat inputVectorTrainingSet, outputVectorTrainingSet, outputVectorBPN; + + // druk voor elke input vector uit de trainingset de output vector uit trainingset af + // tezamen met de output vector die het getrainde BPN (zie V0, W0) genereerd bij de + // betreffende input vector. + for (int row = 0; row < ITset.rows; row++) { + + // haal volgende inputvector op uit de training set + inputVectorTrainingSet = transpose(getRow(ITset, row)); + + // haal bijbehorende outputvector op uit de training set + outputVectorTrainingSet = transpose(getRow(OTset, row)); + + // bepaal de outputvector die het getrainde BPN oplevert + // bij de inputvector uit de trainingset + outputVectorBPN = BPN(inputVectorTrainingSet, V0, W0); + + // druk de output vector van het BPN af in dezelfde regel afgesloten met | + for (int r = 0; r < outputVectorBPN.rows; r++) + cout << setw(8) << round(getEntry(outputVectorBPN, r, 0)); + cout << setw(2) << "|"; + + cout << endl; + } + + return outputVectorBPN; +} + diff --git a/AdvancedVision/NeuralNetwork.h b/AdvancedVision/NeuralNetwork.h new file mode 100644 index 0000000..c3384e7 --- /dev/null +++ b/AdvancedVision/NeuralNetwork.h @@ -0,0 +1,10 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "avansvisionlib20.h" // versie 2.0 (!) + +Mat run(Mat in, Mat out); diff --git a/AdvancedVision/Source.cpp b/AdvancedVision/Source.cpp index 3a7e2d0..df0efb1 100644 --- a/AdvancedVision/Source.cpp +++ b/AdvancedVision/Source.cpp @@ -1,33 +1,79 @@ -#include -#include -#include -#include -#include -#include #include #include -#include -#include +#include using namespace cv; using namespace std; +int test1(int argc, char** argv); +int test2(); +int test3(); + int main2(int argc, char** argv) { - Mat image = imread("input/Week2/basisfiguren.jpg", CV_LOAD_IMAGE_COLOR); - if (!image.data) + return test3(); +} + +int test1(int argc, char** argv) +{ + if (argc != 2) + { + cout << " Usage: display_image ImageToLoadAndDisplay" << endl; + return -1; + } + + Mat image; + image = imread(argv[1], IMREAD_COLOR); // Read the file + + if (!image.data) // Check for invalid input { cout << "Could not open or find the image" << std::endl; return -1; } - Mat gray_image; - cvtColor(image, gray_image, CV_BGR2GRAY); - - imshow("Source", image); - imshow("Gray image", gray_image); - - waitKey(0); + namedWindow("Display window", WINDOW_AUTOSIZE); // Create a window for display. + imshow("Display window", image); // Show our image inside it. + waitKey(0); // Wait for a keystroke in the window return 0; -} \ No newline at end of file +} + +int test2() +{ + int c; + IplImage* color_img; + CvCapture* cv_cap = cvCaptureFromCAM(0); + cvNamedWindow("Video", 0); // create window + for (;;) { + color_img = cvQueryFrame(cv_cap); // get frame + if (color_img != 0) + cvShowImage("Video", color_img); // show frame + c = cvWaitKey(10); // wait 10 ms or for key stroke + if (c == 27) + break; // if ESC, break and quit + } + /* clean up */ + cvReleaseCapture(&cv_cap); + cvDestroyWindow("Video"); + return 0; +} + +int test3() +{ + VideoCapture stream1(0); //0 is the id of video device.0 if you have only one camera. + + if (!stream1.isOpened()) { //check if video device has been initialised + cout << "cannot open camera"; + } + + //unconditional loop + while (true) { + Mat cameraFrame; + stream1.read(cameraFrame); + imshow("cam", cameraFrame); + if (waitKey(30) >= 0) + break; + } + return 0; +} + diff --git a/AdvancedVision/VCPP1_Kenneth-Ewijk_Davey-Matthijssen_2017-11-24.pdf b/AdvancedVision/VCPP1_Kenneth-Ewijk_Davey-Matthijssen_2017-11-24.pdf new file mode 100644 index 0000000..265c133 Binary files /dev/null and b/AdvancedVision/VCPP1_Kenneth-Ewijk_Davey-Matthijssen_2017-11-24.pdf differ diff --git a/AdvancedVision/VCPP1_Kenneth-Ewijk_Davey-Matthijssen_2017-11-24.zip b/AdvancedVision/VCPP1_Kenneth-Ewijk_Davey-Matthijssen_2017-11-24.zip new file mode 100644 index 0000000..bced227 Binary files /dev/null and b/AdvancedVision/VCPP1_Kenneth-Ewijk_Davey-Matthijssen_2017-11-24.zip differ diff --git a/AdvancedVision/allContoursTestprogramma.cpp b/AdvancedVision/allContoursTestprogramma.cpp index a57a426..4a6f402 100644 --- a/AdvancedVision/allContoursTestprogramma.cpp +++ b/AdvancedVision/allContoursTestprogramma.cpp @@ -11,16 +11,17 @@ #include "opencv2/highgui/highgui.hpp" #include #include -#include "avansvisionlib.h" +#include "avansvisionlib20.h" #include "MooreBoundaryTrackingAlgorithm.h" #include "BoundingBox.h" #include "FloodFill.h" +#include "allContoursTestprogramma.h" using namespace cv; using namespace std; -int main(int argc, char *argv[]) +int main2(int argc, char *argv[]) { // zie: project properties - configuration properties - debugging - command arguments if (argc != 2) @@ -65,7 +66,7 @@ int main(int argc, char *argv[]) // Stel een threshold in. Laad evt de figuur eerst in VisionLab om een goede // threshold te bepalen. // ! Comment this line out when using rummikub images - threshold(gray_image, binaryImage, 165, 1, CV_THRESH_BINARY_INV); + threshold(gray_image, binaryImage, 220, 1, CV_THRESH_BINARY_INV); // Alvorens bewerkingen uit te voeren op het beeld converteren we deze // naar een Mat object met grotere diepte (depth), t.w. 16 bits signed @@ -80,9 +81,9 @@ int main(int argc, char *argv[]) int aantal = allContours(binary16S, contours); // <<<<*** De opdracht is dus om deze functie te maken *** // druk alle punten van alle gevonden contouren af - string line; cout << "Aantal gevonden contouren = " << aantal << endl; - getline(cin, line); + cin.get(); + /* for (int i = 0; i < contours.size(); i++) { cout << "*** Contour " << i + 1 << " ***" << endl; @@ -101,14 +102,16 @@ int main(int argc, char *argv[]) cout << "Aantal gevonden boundaries = " << aantalB << endl; - - /* + cout << "Fill" << endl; - vector region; - Point center = FloodFill::findStartPoint(contours[0]); - cout << "Center point: " << center.x << ", " << center.y << endl; - FloodFill::enclosedPixels(contours[0], region); - */ + vector> regions; + for (vector contour : contours) + { + vector region; + FloodFill::enclosedPixels(contour, region); + regions.push_back(region); + } + // Creeer een witte image IplImage* iplimage = cvCreateImage(cvSize(binary16S.cols, binary16S.rows), IPL_DEPTH_8U, 3); @@ -118,31 +121,39 @@ int main(int argc, char *argv[]) // teken de contouren op de witte image drawContours(contourImage, contours, -1, CV_RGB(255, 0, 0)); drawContours(contourImage, bounds, -1, CV_RGB(0, 0, 255)); + drawContours(contourImage, regions, -1, CV_RGB(0, 255, 0)); /* - for (Point p : region) + for (vector region : regions) { - circle(contourImage, p, 1, CV_RGB(0, 255, 0)); + for (Point p : region) + { + circle(contourImage, p, 1, CV_RGB(0, 255, 0)); + } }*/ // druk het image met de contouren af imshow("Found contours", contourImage); waitKey(0); + //BoundingBox::split(contours, image, argv[1]); + //Split images FloodFill::split(contours, image, argv[1]); //haal bending energy waarde op + /* cout << "Bending Energy" << endl << "-----------" << endl; for (int i = 0; i < contours.size(); i++) { cout << "[" << i << "] " << getBendingEnergy(contours[i]) << endl; } - + */ - waitKey(0); + cout << "End program with any key" << endl; + cin.get(); return 0; } \ No newline at end of file diff --git a/AdvancedVision/allContoursTestprogramma.h b/AdvancedVision/allContoursTestprogramma.h new file mode 100644 index 0000000..e69de29 diff --git a/AdvancedVision/avansvisionlib20.cpp b/AdvancedVision/avansvisionlib20.cpp new file mode 100644 index 0000000..820ff40 --- /dev/null +++ b/AdvancedVision/avansvisionlib20.cpp @@ -0,0 +1,1049 @@ +// avansvisionlib - Growing Visionlibrary of Avans based on OpenCV 2.4.10 +// Goal: deep understanding of vision algorithms by means of developing own (new) algorithms. +// deep understanding of neural networks +// +// Copyright Jan Oostindie, version 2.0 dd 5-12-2016 (= Neural Network (BPN) added to version 1.0 dd 5-11-2016.) +// Contains basic functions to perform calculations on matrices/images of class Mat. Including BLOB labeling functions +// Contains a BPN neural network. +// Note: Students of Avans are free to use this library in projects and for own vision competence development. Others may ask permission to use it by means +// of sending an email to Jan Oostindie, i.e. jac.oostindie@avans.nl + +#include "avansvisionlib20.h" +#include +#include /* srand, rand */ +#include /* time */ + +// pre: (i < m.rows) & (j < m.cols) +// Mat is call by reference +void setEntry(Mat m, int i, int j, double value) { + int index = i * m.cols + j; + double * p = m.ptr(0); + p[index] = value; +} // setEntry + +// pre: (i < m.rows) & (j < m.cols) +double getEntry(Mat m, int i, int j) { + int index = i * m.cols + j; + double * p = m.ptr(0); + return *(p + index); +} // getEntry + + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) +double inproduct(Mat row, Mat col) { + double * p1 = row.ptr(0); + double * p2 = col.ptr(0); + double sumproducts = 0; + for (int i = 0; i < row.cols; i++) + sumproducts += p1[i] * p2[i]; + return sumproducts; +} // inproduct + +void printMatrix(Mat m) { + for (int i = 0; i < m.rows; i++) { + for (int j = 0; j < m.cols; j++) + cout << getEntry(m, i, j) << " "; + cout << endl; + } + cout << endl; +} // printMatrix + + +Mat getRow(Mat m, int rowNr) { + Mat result = Mat_(1, m.cols); + double entry; + for (int colNr = 0; colNr < m.cols; colNr++) { + entry = getEntry(m, rowNr, colNr); + // cout << " ** getRow ** " << endl; + // cout << " entry = " << entry << endl; + setEntry(result, 0, colNr, entry); + } + return result; +} // getRow + +Mat getCol(Mat m, int colNr) { + Mat result = Mat_(m.rows, 1); + double entry; + for (int rowNr = 0; rowNr < m.rows; rowNr++) { + entry = getEntry(m, rowNr, colNr); + // cout << " ** getColumn ** " << endl; + // cout << " entry = " << entry << endl; + setEntry(result, rowNr, 0, entry); + } + return result; +} // getCol + + + +// pre: (a.cols == b.rows) +Mat multiply(Mat a, Mat b) +{ + Mat result = Mat_(a.rows, b.cols); + double inprod; + for (int arow = 0; arow < a.rows; arow++) { + for (int bcol = 0; bcol < b.cols; bcol++) { + inprod = inproduct(getRow(a, arow), getCol(b, bcol)); + setEntry(result, arow, bcol, inprod); + } + } + return result; +} // multiply + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +Mat add(Mat a, Mat b) +{ + Mat result = Mat_(a.rows, a.cols); + double entrysum; + for (int row = 0; row < a.rows; row++) { + for (int col = 0; col < a.cols; col++) { + entrysum = getEntry(a, row, col) + getEntry(b, row, col); + setEntry(result, row, col, entrysum); + } + } + return result; +} // add + + +Mat transpose(Mat m) { + Mat result = Mat_(m.cols, m.rows); + for (int row = 0; row < m.rows; row++) + for (int col = 0; col < m.cols; col++) + setEntry(result, col, row, getEntry(m, row, col)); + return result; +} // transpose + + +// func: sets all entries of a matrix to a value +// pre: true +void setValue(Mat m, double value) { + for (int row = 0; row < m.rows; row++) + for (int col = 0; col < m.cols; col++) + setEntry(m, row, col, value); +} // setValue + + +double generateRandomValue(double min, double max) { + int steps = rand() % 100 + 1; + double dx = (max - min) / 100; + return min + dx * steps; +} // generateRandomValue + + +// func: sets all entries of a matrix to a random value in interval [min,max] +// pre: true +void setRandomValue(Mat m, double min, double max) { + srand(time(NULL)); + for (int row = 0; row < m.rows; row++) + for (int col = 0; col < m.cols; col++) + setEntry(m, row, col, generateRandomValue(min, max)); +} // randomValue + + + +/*********************************** Image operaties ****************************************/ +// NB images are supposed to have 1 channel (B/W image) and depth 16 bits signed (CV_16S) +/********************************************************************************************/ + +void setEntryImage(Mat m, int i, int j, _int16 value) { + int index = i * m.cols + j; + _int16 * p = m.ptr<_int16>(0); + p[index] = value; +} // setEntry + +// pre: (i < m.rows) & (j < m.cols) +_int16 getEntryImage(Mat m, int i, int j) { + int index = i * m.cols + j; + _int16 * p = m.ptr<_int16>(0); + return *(p + index); +} // getEntryImage + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) +_int16 inproductImage(Mat row, Mat col) { + _int16 * p1 = row.ptr<_int16>(0); + _int16 * p2 = col.ptr<_int16>(0); + _int16 sumproducts = 0; + for (int i = 0; i < row.cols; i++) + sumproducts += p1[i] * p2[i]; + return sumproducts; +} // inproductImage + + +Mat getRowImage(Mat m, int rowNr) { + Mat result = Mat_<_int16>(1, m.cols); + _int16 entry; + for (int colNr = 0; colNr < m.cols; colNr++) { + entry = getEntryImage(m, rowNr, colNr); + setEntryImage(result, 0, colNr, entry); + } + return result; +} // getRow + +Mat getColImage(Mat m, int colNr) { + Mat result = Mat_<_int16>(m.rows, 1); + _int16 entry; + for (int rowNr = 0; rowNr < m.rows; rowNr++) { + entry = getEntryImage(m, rowNr, colNr); + setEntryImage(result, rowNr, 0, entry); + } + return result; +} // getColImage + +Mat multiplyImage(Mat a, Mat b) +{ + Mat result = Mat_<_int16>(a.rows, b.cols); + _int16 inprod; + for (int arow = 0; arow < a.rows; arow++) { + for (int bcol = 0; bcol < b.cols; bcol++) { + inprod = inproductImage(getRow(a, arow), getColImage(b, bcol)); + setEntry(result, arow, bcol, inprod); + } + } + return result; +} // multiplyImage + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +Mat addImage(Mat a, Mat b) +{ + Mat result = Mat_<_int16>(a.rows, a.cols); + _int16 entrysum; + for (int row = 0; row < a.rows; row++) { + for (int col = 0; col < a.cols; col++) { + entrysum = getEntryImage(a, row, col) + getEntryImage(b, row, col); + setEntryImage(result, row, col, entrysum); + } + } + return result; +} // addImage + + +// func: searches the maximum pixel value in the image +// return: maximum pixel +_int16 maxPixelImage(Mat m) { + _int16 max = getEntryImage(m, 0, 0); + _int16 next; + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + next = getEntryImage(m, row, col); + if (next > max) max = next; + } + } + return max; +} // maxPixelImage + +// func: searches the minimum pixel value in the image +// return: minimum pixel value +_int16 minPixelImage(Mat m) { + _int16 min = getEntryImage(m, 0, 0); + _int16 next; + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + next = getEntryImage(m, row, col); + if (next < min) min = next; + } + } + return min; +} // minPixelImage + +// func: determines the range of the image, i.e. the minimum +// and maximum pixel value in the image +// post: range = minPixelValue, maxPixelValue +void getPixelRangeImage(Mat m, _int16 &minPixelValue, _int16 &maxPixelValue) { + _int16 max = getEntryImage(m, 0, 0); + _int16 min = getEntryImage(m, 0, 0); + _int16 next; + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + next = getEntryImage(m, row, col); + if (next > max) max = next; + else + if (next < min) min = next; + } + } + minPixelValue = min; + maxPixelValue = max; +} // getPixelRangeImage + + +// func: stretches the image to a specified range +void stretchImage(Mat m, _int16 minPixelValue, _int16 maxPixelValue) { + _int16 min, max, oldValue, newValue; + getPixelRangeImage(m, min, max); + double scale = maxPixelValue - minPixelValue; + scale /= (max - min); + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + oldValue = getEntryImage(m, row, col); + newValue = scale * (oldValue - min) + minPixelValue; + setEntryImage(m, row, col, newValue); + } + } +} // stretchImage + + +// func: shows a 16S image on the screen +// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageStretch(Mat m, string windowTitle) { + Mat mCopy; + m.copyTo(mCopy); + stretchImage(mCopy, 0, 255); + mCopy.convertTo(mCopy, CV_8U); + // namedWindow(windowTitle, CV_WINDOW_AUTOSIZE); + imshow(windowTitle, mCopy); + waitKey(0); +} // show16SImage + +// func: shows a 16S image on the screen. All values clipped to the interval 0-255 +// i.e. value < 0 => 0; 0 <= value <= 255 => value ; value > 255 => 255 +/// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageClip(Mat m, string windowTitle) { + Mat mCopy; + m.copyTo(mCopy); + mCopy.convertTo(mCopy, CV_8U); + // namedWindow("show16SImageClip", CV_WINDOW_AUTOSIZE); + imshow(windowTitle, mCopy); + waitKey(0); +} // show16SImage + + +// func: histogram gamma correction +// pre: image has depth 8 bits unsigned and 1 or 3 channels +// post: entry(i,j) = 255*power(entry@pre(i,j)/255)^gamma +void gammaCorrection(Mat image, float gamma) { + unsigned char lut[256]; + for (int i = 0; i < 256; i++) { + lut[i] = saturate_cast(pow((float)(i / 255.0), gamma) * 255.0f); + } + // dst = src.clone(); + const int channels = image.channels(); + switch (channels) { + case 1: { + MatIterator_ it, end; + for (it = image.begin(), end = image.end(); it != end; it++) + *it = lut[(*it)]; + break; + } + case 3: { + MatIterator_ it, end; + for (it = image.begin(), end = image.end(); it != end; it++) { + (*it)[0] = lut[((*it)[0])]; + (*it)[1] = lut[((*it)[1])]; + (*it)[2] = lut[((*it)[2])]; + } + break; + } + } // switch +} // gammaCorrection + + +// func: makes a administration used for labeling blobs. +// the function adds a edge of 1 pixel wide tot a binary image, all with value 0. +// All 1's are made -1. The result is returned. +// This function is used by function labelBLOBs +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// return_matrix: All "1" are made "-1" meaning value 1 and unvisited. +Mat makeAdmin(Mat binaryImage) { + Mat result = Mat_<_int16>(binaryImage.rows + 2, binaryImage.cols + 2); + + // eerste rij 0 maken + for (int col = 0; col < result.cols; col++) + setEntryImage(result, 0, col, 0); + + // binaryImage copieren naar admin waarbij een 1 steeds wordt omgezet naar -1. + for (int row = 1; row < (result.rows - 1); row++) { + + // 0 vooraan de rij zetten + setEntryImage(result, row, 0, 0); + + // rij binaryImage copieren + _int16 value; + for (int col = 1; col < result.cols - 1; col++) { + value = getEntryImage(binaryImage, row - 1, col - 1); + if (value == 1) value = -1; + setEntryImage(result, row, col, value); + } + + // 0 achteraan de rij zetten + setEntryImage(result, row, result.cols - 1, 0); + } // for + + // laatste rij 0 maken + for (int col = 0; col < result.cols; col++) + setEntryImage(result, result.rows - 1, col, 0); + + return result; +} // makeAdmin + + +// func: Searches the next blob after position (row,col) i.e. searches +// the next -1 in admin +// post: if return_value == 1 then (row,col) contains the position +// where the next blob starts. +// return_value: 1 next blob found ; starting position is (row,col) +// 0 no blob found ; (row, col) == (-1, -1) +bool findNextBlob(Mat admin, int & row, int & col) { + + bool found = false; + + // zoeken in de huidige rij + for (int currCol = col; (currCol < (admin.cols - 1)) & !found; currCol++) + if (getEntryImage(admin, row, currCol) == -1) { + found = true; + // row unchanged + col = currCol; + } + + // zoeken vanaf de volgende rij + for (int currRow = row + 1; (currRow < (admin.rows - 1)) &!found; currRow++) + for (int currCol = 1; (currCol < (admin.cols - 1)) & !found; currCol++) + if (getEntryImage(admin, currRow, currCol) == -1) { + found = true; + row = currRow; + col = currCol; + } + + if (!found) { + row = -1; + col = -1; + } + return found; +}; // findNextBlob + +// func: gets the entry of a neighbour pixel with relative position nr. +// Definition of relative positions nr: +// 7 0 1 +// 6 X 2 +// 5 4 3 +_int16 getEntryNeighbour(const Mat & admin, int x, int y, int nr) { + switch (nr) { + case 0: return getEntryImage(admin, x - 1, y); break; + case 1: return getEntryImage(admin, x - 1, y + 1); break; + case 2: return getEntryImage(admin, x, y + 1); break; + case 3: return getEntryImage(admin, x + 1, y + 1); break; + case 4: return getEntryImage(admin, x + 1, y); break; + case 5: return getEntryImage(admin, x + 1, y - 1); break; + case 6: return getEntryImage(admin, x, y - 1); break; + case 7: return getEntryImage(admin, x - 1, y - 1); break; + default: cout << "ERROR getEntryNeighbour " << endl; + } +} // getEntryNeighbour + +// func: determines if there are more than 1 adjacent 1's +bool moreNext1(const Mat & admin, int x, int y) { + int cnt1 = 0; + bool more = false; + for (int nr = 0; (nr <= 7) & !more; nr++) + if (getEntryNeighbour(admin, x, y, nr) == -1) { + cnt1++; + if (cnt1 > 1) more = true; + } + return more; +} // moreNext1 + +// func: searches the first 1 when rotating around the pixel (currX,currY), +// starting at position 0. Definition of relative positions: +// 7 0 1 +// 6 X 2 +// 5 4 3 +void findNext1(Mat admin, int & currX, int & currY, int & next1) { + int rotX, rotY; + + rotX = currX - 1; rotY = currY; //0 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 0; + else { + rotX = currX - 1; rotY = currY + 1; //1 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 1; + else { + rotX = currX; rotY = currY + 1; //2 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 2; + else { + rotX = currX + 1; rotY = currY + 1; //3 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 3; + else { + rotX = currX + 1; rotY = currY; //4 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 4; + else { + rotX = currX + 1; rotY = currY - 1; //5 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 5; + else { + rotX = currX; rotY = currY - 1; //6 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 6; + else { + rotX = currX - 1; rotY = currY - 1; //7 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 7; + else next1 = -99; + } // 6 + } // 5 + } // 4 + } // 3 + } // 2 + } // 1 + } //0 + if (next1 >= 0) { + currX = rotX; + currY = rotY; + } +} // findNext1 + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// This function is used by function labelBLOB's which labels all blobs. +// return_value: area of the blob +// Evaluation: This function uses a iterative algorithm in which a special labeling technique is +// is used which gives the opportunity to trace all individiual pixels. This makes it +// possible for example to save only these pixels on disk or to translate the object in +// in the image. +// The disadvantagae however is that the algorithm is more complicated an maybe a little bit +// slower than the recursive variant. +int labelIter(Mat & admin, int row, int col, int blobNr) { + // Every visited pixel is labeled with: + // blobNr*10 + + // + // definition of relative positions + // 7 0 1 + // 6 X 2 + // 5 4 3 + // + // The first visited pixel, i.e. (row,col), is labeled with: + // blobNr * 10 + 8 + + int x = row, y = col; + setEntryImage(admin, x, y, blobNr * 10 + 8); + + int next1 = -999; + int area = 1; + + // flag more is set when any entry in the path has two or more + // unvisited neighbours because we visit only one at a time. + bool allLabeledFlag = true; + while (allLabeledFlag) { + allLabeledFlag = false; + bool pathLabeled = false; + while (!pathLabeled) { + + if (!allLabeledFlag) allLabeledFlag = moreNext1(admin, x, y); + findNext1(admin, x, y, next1); + + if (next1 >= 0) { + setEntryImage(admin, x, y, blobNr * 10 + next1); + area++; + } + else { + //findprevious + switch (getEntryImage(admin, x, y) % 10) { + case 0: x += 1; break; + case 1: x += 1; y -= 1; break; + case 2: y -= 1; break; + case 3: x -= 1; y -= 1; break; + case 4: x -= 1; break; + case 5: x -= 1; y += 1; break; + case 6: y += 1; break; + case 7: x += 1; y += 1; break; + case 8: pathLabeled = true; break; // currIndex should be 0 now + default: cout << "Error func labelIter!"; + } // case + } // else + } // while + } // while (more) + return area; +} // labelIter + + +// func: labels all pixels of one blob which starts at position (topX,topY) with blobNr. +// During the labeling proces the centre of gravity is calculated. +// This function is used by function labelBLOBInfo +// return_value: area of the blob +// Evaluation: This function uses a iterative algorithm in which a special labeling technique is +// is used which gives the opportunity to trace all individiual pixels. This makes it +// possible for example to save only these pixels on disk or to translate the object in +// in the image. +// The disadvantagae however is that the algorithm is more complicated an maybe a little bit +// slower than the recursive variant. +int labelIterInfo(Mat & admin, int topX, int topY, int blobNr, + int & xGravity, int & yGravity) { + + // Every visited pixel is labeled with: + // blobNr*10 + + // + // definition of relative positions + // 7 0 1 + // 6 X 2 + // 5 4 3 + // + // The first visited pixel, i.e. (row,col), is labeled with: + // blobNr * 10 + 8 + + xGravity = topX; + yGravity = topY; + int x = topX, y = topY; + setEntryImage(admin, topX, topY, blobNr * 10 + 8); + + int next1 = -999; + int area = 1; + + // allLabeledFlag is set when any entry in the path has two or more + // unvisited neighbours because we visit only one at a time. + // This algorithm good be speeded up by using a stack (future improvement) + bool allLabeledFlag = true; + while (allLabeledFlag) { + allLabeledFlag = false; + bool pathLabeled = false; + while (!pathLabeled) { + + if (!allLabeledFlag) allLabeledFlag = moreNext1(admin, x, y); + findNext1(admin, x, y, next1); + + if (next1 >= 0) { + setEntryImage(admin, x, y, blobNr * 10 + next1); + area++; + xGravity += x; + yGravity += y; + } + else { + //findprevious + switch (getEntryImage(admin, x, y) % 10) { + case 0: x += 1; break; + case 1: x += 1; y -= 1; break; + case 2: y -= 1; break; + case 3: x -= 1; y -= 1; break; + case 4: x -= 1; break; + case 5: x -= 1; y += 1; break; + case 6: y += 1; break; + case 7: x += 1; y += 1; break; + case 8: pathLabeled = true; break; // currIndex should be 0 now + default: cout << "Error func labelIter!"; + } // case + } // else + } // while + } // while (more) + xGravity /= area; + yGravity /= area; + return area; +} // labelIterInfo + + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// return_value: area of the blob +// Evaluation: This function uses a recursive algorithm which has the advantage that it is easy and trasparent. +// The disadvantagae however is that it claims a lot of spacee on the stack. I.e. every found +// pixel results in a function call which in case of large blobs causes a stack overflow. +int labelRecursive(Mat & admin, int row, int col, int blobNr) { + int area = 0; + // bij waarde -1 is het pixel nog niet bezocht + if (getEntryImage(admin, row, col) == -1) { + //cout << "(row,col) = " << "(" << row << "," << col << ")" << endl; + // pixel labelen met het volgnummer van de blob + setEntryImage(admin, row, col, blobNr); + area = 1; + + // alle pixels rondom huidige pixel bezoeken + // (row-1,col-1) (row-1,col ) (row-1,col+1) + // (row ,col-1) (row, col ) (row ,col+1) + // (row+1,col-1) (row, col ) (row+1,col+1) + area += labelRecursive(admin, row - 1, col, blobNr); + area += labelRecursive(admin, row - 1, col + 1, blobNr); + area += labelRecursive(admin, row, col + 1, blobNr); + area += labelRecursive(admin, row + 1, col + 1, blobNr); + area += labelRecursive(admin, row, col, blobNr); + area += labelRecursive(admin, row + 1, col - 1, blobNr); + area += labelRecursive(admin, row, col - 1, blobNr); + area += labelRecursive(admin, row - 1, col - 1, blobNr); + } + return area; +} // label + +// func: retrieves a labeledImage from the labeling administration +// pre : admin is contains labeled pixels with neighbour number information. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +void retrieveLabeledImage(const Mat & admin, Mat & labeledImage) { + labeledImage = Mat_<_int16>(admin.rows - 2, admin.cols - 2); + + for (int row = 1; row < admin.rows - 1; row++) { + for (int col = 1; col < admin.cols - 1; col++) { + setEntryImage(labeledImage, row - 1, col - 1, + getEntryImage(admin, row, col) / 10); + } + } +} // retrieveLabeledImage + + +// func: labeling of all blobs in a binary image +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// return_value: the total number of objects. +int labelBLOBs(Mat binaryImage, Mat & labeledImage) { + + // admin contains the administration of the recursive process. + // meaning of the entry values: + // -1: a "1" which is not visited yet. Changes to 1 when visited. + // 0: always a "0" + // 1, 2, 3,... : a "1" which is visited and is labeled with the object number. + Mat admin = makeAdmin(binaryImage); + int row = 1; + int col = 1; + + // init volgnummer + int blobNr = 0; + + // label alle BLOBs met een volgnummer + while ((row > 0) & (row < (admin.rows - 1)) & + (col > 0) & (col < (admin.cols - 1))) + if (findNextBlob(admin, row, col)) labelIter(admin, row, col, ++blobNr); + + retrieveLabeledImage(admin, labeledImage); + + // laatste volgnummer is gelijk aan het aantal gevonden blobs + return blobNr; +} // labelBLOBs + +// func: removes a BLOB from the labeling administration +// pre: (posx,posy) is the position of the BLOB, blobNr the number +// of the blob to be removed. +void removeBLOB(Mat & admin, int blobNr) { + _int16 value; + for (int row = 1; row < admin.rows - 2; row++) + for (int col = 1; col < admin.cols - 2; col++) { + value = getEntryImage(admin, row, col); + while (value > 10) value /= 10; + if (value == blobNr) setEntryImage(admin, row, col, 0); + } +} // removeBLOB + +// func: labeling of all blobs in a binary image with a area in [threhAreaMin,threhAreaMax]. Default +// threshold is [1,INT_MAX]. Alle gathered data during the labeling proces is returned, +// i.e. the positions of the firstpixel of each blob, the position of the blobs (i.e. the +// centres of gravity) and the area's of all blobs. +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// areaVec: contains all area's of the blobs. The index corresponds to the number +// of the blobs. Index 0 has no meaning. +// return_value: the total number of objects. +int labelBLOBsInfo(Mat binaryImage, Mat & labeledImage, + vector & firstpixelVec, vector & posVec, + vector & areaVec, + int threshAreaMin, int threshAreaMax) { + + // admin contains the administration of the recursive process. + // meaning of the entry values: + // -1: a "1" which is not visited yet. + // 0: always a "0" + // 1, 2, 3,... : a "1" which is visited and is labeled with the object number. + Mat admin = makeAdmin(binaryImage); + int row = 1; + int col = 1; + + // init volgnummer + int blobNr = 0; + int area; + int xGravity, yGravity; + // label alle BLOBs met een volgnummer + while ((row > 0) & (row < (admin.rows - 1)) & + (col > 0) & (col < (admin.cols - 1))) + + if (findNextBlob(admin, row, col)) { + + area = labelIterInfo(admin, row, col, ++blobNr, xGravity, yGravity); + + if ((area >= threshAreaMin) & (area <= threshAreaMax)) { + firstpixelVec.push_back(new Point2d(row - 1, col - 1)); + posVec.push_back(new Point2d(xGravity - 1, yGravity - 1)); + areaVec.push_back(area); + } + else removeBLOB(admin, blobNr--); + } + + retrieveLabeledImage(admin, labeledImage); + + // laatste volgnummer is gelijk aan het aantal gevonden blobs + return blobNr; +} // labelBLOBsInfo + + +/*BEGIN********************************************** BACK PROPAGATION NEURAL NETWORK ****************************************************************/ + +// TRAININGSET: I0 because of bias V0 +// +// setnr I0 I1 I2 I3 I4 O1 O2 +// 1 1.0 0.4 -0.7 0.1 0.71 0.0 0.0 +// 2 1.0 0.3 -0.5 0.05 0.34 0.0 0.0 +// 3 1.0 0.6 0.1 0.3 0.12 0.0 1.0 +// 4 1.0 0.2 0.4 0.25 0.34 0.0 1.0 +// 5 1.0 -0.2 0.12 0.56 1.0 1.0 0.0 +// 6 1.0 0.1 -0.34 0.12 0.56 1.0 0.0 +// 7 1.0 -0.6 0.12 0.56 1.0 1.0 1.0 +// 8 1.0 0.56 -0.2 0.12 0.56 1.0 1.0 + +void loadTrainingSet1(Mat & ITset, Mat & OTset) { + + // input of trainingset + // remark: nummber of columns == number of inputneurons of the BPN + ITset = (Mat_(8, 5) << + 1, 0.4, -0.7, 0.1, 0.71, + 1, 0.3, -0.5, 0.05, 0.34, + 1, 0.6, 0.1, 0.3, 0.12, + 1, 0.2, 0.4, 0.25, 0.34, + 1, -0.2, 0.12, 0.56, 1.0, + 1, 0.1, -0.34, 0.12, 0.56, + 1, 0.6, 0.12, 0.56, 1.0, + 1, 0.56, -0.2, 0.12, 0.56); + + // output of trainingset + // remark: nummber of columns == number of outputneurons of the BPN + OTset = (Mat_(8, 2) << + 0, 0, + 0, 0, + 0, 1, + 0, 1, + 1, 0, + 1, 0, + 1, 1, + 1, 1); +} // loadTestTrainingSet1 + + +// TRAININGSET binary function O1 = (I1 OR I2) AND I3 +// without bias +// setnr I1 I2 I3 O1 +// 1 0 0 0 0 +// 2 0 0 1 0 +// 3 0 1 0 0 +// 4 0 1 1 1 +// 5 1 0 0 0 +// 6 1 0 1 1 +// 7 1 1 0 0 +// 8 1 1 1 1 +void loadBinaryTrainingSet1(Mat & ITset, Mat & OTset) { + + // input of trainingset (without bias) + // remark: nummber of columns == number of inputneurons of the BPN + ITset = (Mat_(8, 2) << + 0, 0, + 0, 0, + 0, 1, + 0, 1, + 1, 0, + 1, 0, + 1, 1, + 1, 1); + + // output of trainingset + // remark: nummber of columns == number of outputneurons of the BPN + OTset = (Mat_(8, 1) << + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0); + +} // loadBinaryTrainingSet1 + + +// func: Initialization of the (1) weigthmatrices V0 and W0 and (2) of the delta matrices dV0 and dW0. +// pre: inputNeurons, hiddenNeurons and outputNeurons define the Neural Network. +// From this numbers the dimensions of the weightmatrices can be determined. +// post: V0 and W0 have random values between 0.1 and 0.9 +void initializeBPN(int inputNeurons, int hiddenNeurons, int outputNeurons, + Mat & V0, Mat & dV0, Mat & W0, Mat & dW0) { + + // Instellen van alle weegfactoren met een random waarde + V0 = Mat_(inputNeurons, hiddenNeurons); + W0 = Mat_(hiddenNeurons, outputNeurons); + setRandomValue(V0, 0.1, 0.9); + setRandomValue(W0, 0.1, 0.9); + + // Initiele aanpassing van de weegfactoren W + dV0 = Mat_(inputNeurons, hiddenNeurons); + dW0 = Mat_(hiddenNeurons, outputNeurons); + setValue(dV0, 0); + setValue(dW0, 0); +} // initializeBPN + +// Test of a BPN with all values defined explicitly +void testBPN(Mat & IT, Mat & OT, Mat & V0, Mat & dV0, Mat & W0, Mat & dW0) { + + // input of trainingset + // remark: number of columns == number of inputneurons of the BPN + IT = (Mat_(5, 2) << + 0.4, -0.7, + 0.3, -0.5, + 0.6, 0.1, + 0.2, 0.4, + 0.1, -0.2); + + // output of trainingset + // remark: nummber of columns == number of outputneurons of the BPN + OT = (Mat_(5, 1) << + 0.1, + 0.05, + 0.3, + 0.25, + 0.12); + + // STEP2: Initializing the weights + V0 = (Mat_(2, 2) << + 0.1, 0.4, + -0.2, 0.2); + + W0 = (Mat_(2, 1) << + 0.2, + -0.5); + + // Initiele aanpassing van de weegfactoren W + dW0 = (Mat_(2, 1) << + 0.0, + 0.0); + + // Initiele aanpassing van de weegfactoren V + dV0 = (Mat_(2, 2) << + 0.0, 0.0, + 0.0, 0.0); + +} // testBPN + + + + +// func: Given an inputvector of the inputlayer and a weightmatrix V calculates the outputvector of the hiddenlayer +// pre: II is input of the inputlayer. V = matrix with weightfactors between inputlayer and the hiddenlayer. +// post: OH is the outputvector of the hidden layer +void calculateOutputHiddenLayer(Mat II, Mat V, Mat & OH) { + + // STEP1: Output inputlayer := Input inputlayer + Mat OI; + II.copyTo(OI); + + // STEP2: Initializing the weights, already done, see input of this function + + // STEP3: Calculate input of the hiddenlayer, i.e. IH = V0transposed * OI + Mat Vtr = transpose(V); + Mat IH = multiply(Vtr, OI); + + // STEP4: Calculate output of the hiddenlayer, i.e. OH(i) = 1/(1+EXP(-IH(i))) + int hiddenNeurons = V.cols; + OH = Mat_(hiddenNeurons, 1); + for (int row = 0; row < hiddenNeurons; row++) + setEntry(OH, row, 0, 1 / (1 + exp(-getEntry(IH, row, 0)))); + +} // calculateOutputHiddenLayer + +// func: Given the outputvector of the hiddenlayer and a weigthmatrix W calculates the outputvector of the outputlayer +// pre: OH is the outputvector of the hiddenlayer. W = matrix with weightfactors between hiddenlayer and the outputlayer. +// post: OO is the outputvector of the output layer +void calculateOutputBPN(Mat OH, Mat W, Mat & OO) { + + // STEP5: Calculate input of the outputlayer, i.e. IO = W0transposed * OH + Mat Wtr = transpose(W); + Mat IO = multiply(Wtr, OH); + + // STEP6: Calculate output of the outputlayer, i.e. OO(i) = 1/(1+EXP(-IO(i))) + int outputNeurons = W.cols; + OO = Mat_(outputNeurons, 1); + for (int row = 0; row < outputNeurons; row++) + setEntry(OO, row, 0, 1 / (1 + exp(-getEntry(IO, row, 0)))); + +} // calculateOutputBPN + + +// func: Calculates the total error Error = 1/2*Sigma(OTi-OOi)^2. +// OTi is the expected output according to the trainingvector i +// OOi is the calculated output from the current neural network of the traininngvector i +// pre: OO is the outputvector of the outputlayer. OT is the expected outputvector from the trainingset +// post: OO is the outputvector of the output layer +void calculateOutputBPNError(Mat OO, Mat OT, double & outputError) { + + // STEP7: Calculate the error, i.e. Error = 1/2*Sigma(TOi-OOi)^2 + double sumSqrErr = 0, diff = 0; + for (int row = 0; row < OT.rows; row++) { + diff = getEntry(OT, row, 0) - getEntry(OO, row, 0); + sumSqrErr += (diff * diff); + } + outputError = 0.5 * sumSqrErr; + +} // calculateOutputBPNError + + +void adaptVW(Mat OT, Mat OO, Mat OH, Mat OI, Mat W0, Mat dW0, Mat V0, Mat dV0, Mat & W, Mat & V, + double ALPHA, double ETHA) { + + + /*BEGIN*** AANPASSING VAN DE WEEGFACTOREN W ****/ + + // STEP8: + // E = 1/2 Sigma(OOi - di)^2 ==> dE/dOO = Sigma(OOi - di) + // dE/dIO = dE/dOO * dOO/dIO = Sigma((OOi - Ti) * OOi * (1 - OOi)) + // Here: d = dE/dIO = (T-OO) * OO * (1 - OO) + Mat OOerror = Mat_(OT.rows, 1); + OOerror = OT - OO; + + Mat d = Mat_(OT.rows, 1); + double di; + for (int row = 0; row < OT.rows; row++) { + di = (getEntry(OT, row, 0) - getEntry(OO, row, 0)) * getEntry(OO, row, 0) * (1 - getEntry(OO, row, 0)); + setEntry(d, row, 0, di); + } + + // Y = OH * d + Mat dtr = transpose(d); + Mat Y = Mat_(OH.rows, OT.rows); + Y = multiply(OH, dtr); // OH = mx1 ; d = nx1 ; dtr = 1xn + + // STEP9: dW1 = alpha * dW0 + etha * Y // assume etha = 0.6 + Mat dW = Mat_(OH.rows, OT.rows); + dW = ALPHA * dW0 + ETHA * Y; + + /*END*** AANPASSING VAN DE WEEGFACTOREN W ****/ + + /*BEGIN*** AANPASSING VAN DE WEEGFACTOREN V ****/ + + // STEP10: OHerror = W0 * d + Mat OHerror = Mat_(OH.rows, 1); + OHerror = W0 * d; + + // STEP11: + // d = dE/dIO = OOerror * OO * (1 - OO) // OOError = TO - OO + // d*= dE/dIH = OHerror * OH * (1 - OH) // OHerror = W0 * d + Mat dstar = Mat_(OH.rows, 1); + double dstari; + for (int row = 0; row < OH.rows; row++) { + dstari = getEntry(OHerror, row, 0) * getEntry(OH, row, 0) * (1 - getEntry(OH, row, 0)); + setEntry(dstar, row, 0, dstari); + } + + // STEP12: + // X = OI * dstar + Mat dstartr = transpose(dstar); + Mat X = Mat_(OI.rows, OH.rows); + X = OI * dstartr; + + // STEP13: dV1 = ALPHA * dV0 + ETHA * X // assume etha = 0.6 + Mat dV; + dV = ALPHA * dV0 + ETHA * X; + /*END*** AANPASSING VAN DE WEEGFACTOREN V ****/ + + /* Update van de matrices met gewichtsfactoren */ + + // STEP14: + V = Mat_(V0.rows, V0.cols); + W = Mat_(W0.rows, W0.cols); + V = V0 + dV; + W = W0 + dW; + +}; // adaptVW + + +Mat BPN(Mat II, Mat V, Mat W) { + Mat OH, OO; + calculateOutputHiddenLayer(II, V, OH); + calculateOutputBPN(OH, W, OO); + return OO; +} // BPN + +/*END********************************************** BACK PROPAGATION NEURAL NETWORK ****************************************************************/ diff --git a/AdvancedVision/avansvisionlib20.h b/AdvancedVision/avansvisionlib20.h new file mode 100644 index 0000000..de23e5d --- /dev/null +++ b/AdvancedVision/avansvisionlib20.h @@ -0,0 +1,335 @@ +// avansvisionlib - Growing Visionlibrary of Avans based on OpenCV 2.4.10 +// Goal: deep understanding of vision algorithms by means of developing own (new) algorithms. +// deep understanding of neural networks +// +// Copyright Jan Oostindie, version 2.0 dd 5-12-2016 (= Neural Network (BPN) added to version 1.0 dd 5-11-2016.) +// Contains basic functions to perform calculations on matrices/images of class Mat. Including BLOB labeling functions +// Contains a BPN neural network. +// Note: Students of Avans are free to use this library in projects and for own vision competence development. Others may ask permission to use it by means +// of sending an email to Jan Oostindie, i.e. jac.oostindie@avans.nl +#pragma once +#include +#include +#include +#include +#include + +using namespace cv; +using namespace std; + +// remark: a function call with a Mat-object parameter is a call by reference + +/*********************** PROTOTYPES of the function library ************************/ + +// func: setup a specified entry (i,j) of a matrix m with a specific value +// pre: (i < m.rows) & (j < m.cols) +void setEntry(Mat m, int i, int j, double value); + +// func: get the value of a specified entry (i,j) of a matrix m +// pre: (i < m.rows) & (j < m.cols) +// return: == m(i,j) +double getEntry(Mat m, int i, int j); + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) & (row.rows == 1) & (col.cols == 1) +double inproduct(Mat row, Mat col); + +// func: prints matrix m in the console +// pre: true +void printMatrix(Mat m); + +// func: select and get a row of a matrix m. rowNr contains the row number +// pre: 0 < rowNr < m.rows +// return: contains the selected row +Mat getRow(Mat m, int rowNr); + +// func: get a column of a matrix m. colNr contains the column number +// pre: 0 < colNr < m.cols +// return: contains the selected column +Mat getCol(Mat m, int colNr); + +// func: multiply two matrices a and b +// pre: (a.cols == b.rows) +// return: .rows == b.rows & .cols == b.cols +Mat multiply(Mat a, Mat b); + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +// return: (i,j) == a(i,j) + b(i,j) for all (0,0) <= (i,j) < (a.rows,a.cols) +Mat add(Mat a, Mat b); + +// func: transposes a matrix +// return: (i,j) = m(j,i) & .rows = m.cols & .cols = m.rows +Mat transpose(Mat m); + +// func: sets all entries of a matrix to a certain value +// pre: true +void setValue(Mat m, double value); + +// func: generates a randomvalue between min and max +// pre: true +double generateRandomValue(double min, double max); + + +// func: sets all entries of a matrix to a random value +// pre: true +void setRandomValue(Mat m, double min, double max); + + + +/*********************************** Image operaties ****************************************/ +// NB images are supposed to have 1 channel (B/W image) and depth 16 bits signed (CV_16S) +/********************************************************************************************/ + +// func: setup a specified entry (i,j) of a matrix m with a specific value +// pre: (i < m.rows) & (j < m.cols) +void setEntryImage(Mat m, int i, int j, _int16 value); + +// func: get the value of a specified entry (i,j) of a matrix m +// pre: (i < m.rows) & (j < m.cols) +// return: == m(i,j) +_int16 getEntryImage(Mat m, int i, int j); + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) & (row.rows == 1) & (col.cols == 1) +_int16 inproductImage(Mat row, Mat col); + +// func: select and get a row of a matrix m. rowNr contains the row number +// pre: 0 < rowNr < m.rows +// return: contains the selected row +Mat getRowImage(Mat m, int rowNr); + +// func: get a column of a matrix m. colNr contains the column number +// pre: 0 < colNr < m.cols +// return: contains the selected column +Mat getColImage(Mat m, int colNr); + +// func: multiply two matrices a and b +// pre: (a.cols == b.rows) +// return: .rows == b.rows & .cols == b.cols +Mat multiplyImage(Mat a, Mat b); + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +// return: (i,j) == a(i,j) + b(i,j) for all (0,0) <= (i,j) < (a.rows,a.cols) +Mat addImage(Mat a, Mat b); + + +// func: searches the maximum pixel value in the image +// return: maximum pixel value +_int16 maxPixelImage(Mat m); + +// func: searches the minimum pixel value in the image +// return: minimum pixel value +_int16 minPixelImage(Mat m); + +// func: determines the range of the image, i.e. the minimum +// and maximum pixel value in the image +// post: range = minPixelValue, maxPixelValue +void getPixelRangeImage(Mat m, _int16 &minPixelValue, _int16 &maxPixelValue); + +// func: transform scale the image +// return: maximum pixel value +void stretchImage(Mat m, _int16 minPixelValue, _int16 maxPixelValue); + +// func: shows a 16S image on the screen. All values mapped on the interval 0-255 +/// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageStretch(Mat m, string windowTitle = "show16SImageStretch"); + + +// func: shows a 16S image on the screen. All values clipped to the interval 0-255 +// i.e. value < 0 => 0; 0 <= value <= 255 => value ; value > 255 => 255 +/// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageClip(Mat m, string windowTitle = "show16SImageClip"); + + + +// func: histogram gamma correction +// pre: image has depth 8 bits unsigned and 1 or 3 channels +// post: entry(i,j) = 255*power(entry@pre(i,j)/255)^gamma +void gammaCorrection(Mat image, float gamma); + + +// func: makes a administration used for labeling blobs. +// the function adds a edge of 1 pixel wide tot a binary image, all with value 0. +// All 1's are made -1. The result is returned. +// This function is used by function labelBLOBs +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// return_matrix: All "1" are made "-1" meaning value 1 and unvisited. +Mat makeAdmin(Mat binaryImage); + + +// func: Searches the next blob after position (row,col) +// post: if return_value == 1 then (row,col) contains the position +// where the next blob starts. +// return_value: true => blob found ; starting position is (row,col) +// false => no blob found ; (row, col) == (-1, -1) +bool findNextBlob(Mat admin, int & row, int & col); + + +// func: searches the first 1 when rotating around the pixel (currX,currY), +// starting at position 0. Definition of relative positions: +// 7 0 1 +// 6 X 2 +// 5 4 3 +void findNext1(Mat admin, int & currX, int & currY, int & next1); + +// func: gets the entry of a neighbour pixel with relative position nr. +// Definition of relative positions nr: +// 7 0 1 +// 6 X 2 +// 5 4 3 +_int16 getEntryNeighbour(const Mat & admin, int x, int y, int nr); + + +// func: determines if there are more than 1 adjacent 1's +bool moreNext1(const Mat & admin, int x, int y); + + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// This function is used by function labelBLOB's which labels all blobs. +// return_value: area of the blob +// Evaluation: This function uses a iterative algorithm in which a special labeling technique is +// is used which gives the opportunity to trace all individiual pixels. This makes it +// possible for example to save only these pixels on disk or to translate the object in +// in the image. +// The disadvantagae however is that the algorithm is more complicated an maybe a little bit +// slower than the recursive variant. +int labelIter(Mat & admin, int row, int col, int blobNr); + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// return_value: area of the blob +// Evaluation: This function uses a recursive algorithm which has the advantage that it is easy and trasparent. +// The disadvantagae however is that it claims a lot of spacee on the stack. I.e. every found +// pixel results in a function call which in case of large blobs causes a stack overflow. +int labelRecursive(Mat & admin, int row, int col, int blobNr); + +// func: retrieves a labeledImage from the labeling administration +// pre : admin is contains labeled pixels with neighbour number information. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +void retrieveLabeledImage(const Mat & admin, Mat & labeledImage); + +// func: labeling of all blobs in a binary image +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// return_value: the total number of objects. +int labelBLOBs(Mat binaryImage, Mat & labeledImage); + + +// func: labeling of all blobs in a binary image with a area in [threshAreaMin,threshAreaMax]. Default +// threshold is [1,INT_MAX]. Alle gathered data during the labeling proces is returned, +// i.e. the positions of the firstpixel of each blob, the position of the blobs (i.e. the +// centres of gravity) and the area's of all blobs. +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// areaVec: contains all area's of the blobs. The index corresponds to the number +// of the blobs. Index 0 has no meaning. +// return_value: the total number of objects. +int labelBLOBsInfo(Mat binaryImage, Mat & labeledImage, + vector & firstpixelVec, vector & posVec, + vector & areaVec, + int threshAreaMin = 1, int threshAreaMax = INT_MAX); + + +/*****************************************************************************************************************************************************/ +/*BEGIN********************************************** BACK PROPAGATION NEURAL NETWORK ****************************************************************/ +/*****************************************************************************************************************************************************/ + +// func: loads an example of a training set +// pre: true +// post: ITset input training set. Each row contains a number of features. +// OTset output training set. Each row contains the expected output belonging to the corresponding row of features in the input training set. +// +// TRAININGSET: I0 because of bias V0 +// +// setnr I0 I1 I2 I3 I4 O1 O2 +// 1 1.0 0.4 -0.7 0.1 0.71 0.0 0.0 +// 2 1.0 0.3 -0.5 0.05 0.34 0.0 0.0 +// 3 1.0 0.6 0.1 0.3 0.12 0.0 1.0 +// 4 1.0 0.2 0.4 0.25 0.34 0.0 1.0 +// 5 1.0 -0.2 0.12 0.56 1.0 1.0 0.0 +// 6 1.0 0.1 -0.34 0.12 0.56 1.0 0.0 +// 7 1.0 -0.6 0.12 0.56 1.0 1.0 1.0 +// 8 1.0 0.56 -0.2 0.12 0.56 1.0 1.0 +void loadTrainingSet1(Mat & ITset, Mat & OTset); + + +// func: loads an example of a training set in which only binary numbers are used. +// pre: true +// post: ITset input training set. Each row contains a number of binary numbers. +// OTset output training set. Each row contains the expected output belonging to the corresponding row of binary numbers in the input training set. +// +// TRAININGSET binary function O1 = (I1 OR I2) AND I3 +// without bias +// setnr I1 I2 I3 O1 +// 1 0 0 0 0 +// 2 0 0 1 0 +// 3 0 1 0 0 +// 4 0 1 1 1 +// 5 1 0 0 0 +// 6 1 0 1 1 +// 7 1 1 0 0 +// 8 1 1 1 1 +void loadBinaryTrainingSet1(Mat & ITset, Mat & OTset); + + +// func: Initialization of the (1) weigthmatrices V0 and W0 and (2) of the delta matrices dV0 and dW0. +// pre: inputNeurons, hiddenNeurons and outputNeurons define the Neural Network. +// (from these numbers the dimensions of the weightmatrices can be determined) +// post: V0 and W0 have random values between 0.1 and 0.9 +void initializeBPN(int inputNeurons, int hiddenNeurons, int outputNeurons, + Mat & V0, Mat & dV0, Mat & W0, Mat & dW0); + + +// Test of a BPN with all values defined explicitly. +// pre: true +// post: IT is the input training set ; OT is the corresponding output training set. ; V0, W0 are the weight matrices of a BPN with 1 hidden layer; +// dV0, dW0 are the initial delta matrices of the weight factor matrices. +void testBPN(Mat & IT, Mat & OT, Mat & V0, Mat & dV0, Mat & W0, Mat & dW0); + +// func: Given an inputvector of the inputlayer and a weightmatrix V calculates the outputvector of the hiddenlayer +// pre: II is input of the inputlayer. V = matrix with weightfactors between inputlayer and the hiddenlayer. +// post: OH is the outputvector of the hidden layer +void calculateOutputHiddenLayer(Mat II, Mat V, Mat & OH); + + +// func: Given the outputvector of the hiddenlayer and a weigthmatrix W calculates the outputvector of the outputlayer +// pre: OH is the outputvector of the hiddenlayer. W = matrix with weightfactors between hiddenlayer and the outputlayer. +// post: OO is the outputvector of the output layer +void calculateOutputBPN(Mat OH, Mat W, Mat & OO); + + +// func: Calculates the total error Error = 1/2*Sigma(OTi-OOi)^2. +// OTi is the expected output according to the trainingvector i +// OOi is the calculated output from the current neural network of the traininngvector i +// pre: OO is the outputvector of the outputlayer. OT is the expected outputvector from the trainingset +// post: OO is the outputvector of the output layer +void calculateOutputBPNError(Mat OO, Mat OT, double & outputError); + + +// func: calculates the updates of the weight factor matrices V0 and W0 on basics of the calculated output matrix and the expected output matrix. +// A back propagation algorithm is used. +// pre: OT is the expected outputvector from the trainingset ; OO is the calculated outputvector of the outputlayer ; +// OH is the calculated output of the hiddenlayer ; OI is the output of the inputlayer (normaly equal to the input of the inputlayer) +// V0 is the weight matrix between the input layer and the hidden layer ; W0 is the weight matrix between the hiddenlayer and the output layer. +// dV0, dW0 are the correction matrices. +// post: V is the adapted weight matrix between the inputlayer and the hidden layer ; W is the weight matrix between the hiddenlayer and the output layer. +void adaptVW(Mat OT, Mat OO, Mat OH, Mat OI, Mat W0, Mat dW0, Mat V0, Mat dV0, Mat & W, Mat & V, + double ALPHA = 1.0, double ETHA = 0.6); + + +// func: given an inputvector calculates the output of a BPN with weigth matrices V and W. +// pre: II is the input vector of the BPN ; +// V is the weight factor matrix between the input layer and the hidden layer +// W is the weight factor matrix between the hidden layer and the output layer +// return: output vector +Mat BPN(Mat II, Mat V, Mat W); + + +/*****************************************************************************************************************************************************/ +/*END********************************************** BACK PROPAGATION NEURAL NETWORK ******************************************************************/ +/*****************************************************************************************************************************************************/ + diff --git a/AdvancedVision/input/bladeren.jpg b/AdvancedVision/input/bladeren.jpg new file mode 100644 index 0000000..7dcaf53 Binary files /dev/null and b/AdvancedVision/input/bladeren.jpg differ diff --git a/AdvancedVision/input/blokjes.jpg b/AdvancedVision/input/blokjes.jpg new file mode 100644 index 0000000..4de2d6a Binary files /dev/null and b/AdvancedVision/input/blokjes.jpg differ diff --git a/AdvancedVision/input/rummikub.bmp b/AdvancedVision/input/rummikub.bmp new file mode 100644 index 0000000..b058cdf Binary files /dev/null and b/AdvancedVision/input/rummikub.bmp differ diff --git a/AdvancedVision/input/rummikubbin.bmp b/AdvancedVision/input/rummikubbin.bmp new file mode 100644 index 0000000..4b3a030 Binary files /dev/null and b/AdvancedVision/input/rummikubbin.bmp differ diff --git a/AdvancedVision/input/rummikubbw.bmp b/AdvancedVision/input/rummikubbw.bmp new file mode 100644 index 0000000..eec4358 Binary files /dev/null and b/AdvancedVision/input/rummikubbw.bmp differ diff --git a/AdvancedVision/input/testset2.png b/AdvancedVision/input/testset2.png index 1992c15..d46e82d 100644 Binary files a/AdvancedVision/input/testset2.png and b/AdvancedVision/input/testset2.png differ diff --git a/AdvancedVision/input/testsetg.png b/AdvancedVision/input/testsetg.png new file mode 100644 index 0000000..5a583e5 Binary files /dev/null and b/AdvancedVision/input/testsetg.png differ diff --git a/AdvancedVision/output/card_0.bmp b/AdvancedVision/output/card_0.bmp new file mode 100644 index 0000000..e780e48 Binary files /dev/null and b/AdvancedVision/output/card_0.bmp differ diff --git a/AdvancedVision/output/note_0.bmp b/AdvancedVision/output/note_0.bmp new file mode 100644 index 0000000..5e2d37e Binary files /dev/null and b/AdvancedVision/output/note_0.bmp differ diff --git a/AdvancedVision/output/note_1.bmp b/AdvancedVision/output/note_1.bmp new file mode 100644 index 0000000..8070e3e Binary files /dev/null and b/AdvancedVision/output/note_1.bmp differ diff --git a/AdvancedVision/perceptron.cpp b/AdvancedVision/perceptron.cpp new file mode 100644 index 0000000..f563c73 --- /dev/null +++ b/AdvancedVision/perceptron.cpp @@ -0,0 +1,140 @@ +/* Functionaliteit: Werking van een Neuron (Perceptron) + +W1*I1 + w2*I2 = input + +input > threshold = > output = 1 + +input < threshold = > output = 0 + +aanpassing w1, w2 en threshold op basis van een gelabeld paar(I1, I2, correctoutput) + +aanpassing threshold = -(correctoutput – output) + +aanpassing W1 = aanpassing threshold * I1 + +aanpassing W2 = aanpassing threshold * I2 + +Jan Oostindie +Avans Hogeschool +Breda +email: jac.oostindie@avanns.nl +dd 9-9-2016 + +*/ + +#include +#include +#include "perceptron.h" + +using namespace std; + + +double perceptronOutput(double x1, double x2, double x3, double W1, double W2, double W3, double threshold) { + // bereken input + double input = W1*x1 + W2*x2 + W3*x3; + + // bepaal output + if (input > threshold) return 1.0; + else return 0.0; +} // perceptronOutput + + +void run() { + + const int rows = 8; + + // waarheidstabel AND functie + double tabel[rows][4] = { { 0.0, 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 1.0, 0.0 }, + { 0.0, 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 1.0, 0.0 }, + { 1.0, 0.0, 0.0, 0.0 }, + { 1.0, 0.0, 1.0, 0.0 }, + { 1.0, 1.0, 0.0, 1.0 }, + { 1.0, 1.0, 1.0, 1.0 } }; + + // startwaarden van de weegfactoren (willekeurig) + double W1 = 1003; + double W2 = 456; + double W3 = 738; + + // startwaarde van de threshold (willekeurig) + double threshold = 185; + + // input en output variabele + double input, output, deltaOutput; + + // aanpassingen + double deltaThreshold = 0.0, deltaW1 = 0.0, deltaW2 = 0.0, deltaW3 = 0.0; + + // boolean flag wordt gehezen als output meer dan EPSILON afwijkt van verwachte output + bool flag = false; + const int EPSILON = 0.000001; + + // waarheidstabel afdrukken + cout << "Waarheidstabel waarvoor het perceptron wordt getraind" << endl; + for (int rij = 0; rij < rows; rij++) { + cout << setw(3) << tabel[rij][0] << setw(3) << tabel[rij][1] << setw(3) << tabel[rij][2] << setw(3) << tabel[rij][3] << endl; + cout << endl; + } + cout << "Press ENTER to continue" << endl; + cin.ignore(); + + int aantalRuns = 0; + do { + // voer een run uit + flag = false; + for (int rij = 0; rij < rows; rij++) { + + // bereken actuele output van het nog ongetrainde perceptron + output = perceptronOutput(tabel[rij][0], tabel[rij][1], tabel[rij][2], W1, W2, W3, threshold); + + // bereken de afwijking van de actuele output t.o.v. verwachte output + deltaOutput = (output - tabel[rij][3]); + + if (abs(deltaOutput) > EPSILON) { + + flag = true; + + // berekening aanpassing W1 en W2 + deltaW1 = -deltaOutput*tabel[rij][0]; + deltaW2 = -deltaOutput*tabel[rij][1]; + deltaW3 = -deltaOutput*tabel[rij][2]; + + // threshold, W1 en W2 aanpassen + threshold += deltaOutput; + W1 += deltaW1; + W2 += deltaW2; + W3 += deltaW3; + + } // if + + } // for + + cout << "Runs " << ++aantalRuns << + " Threshold = " << threshold << endl; + } + while (flag); + + cout << "Berekende threshold = " << threshold << endl; + cout << "Berekende W1 = " << W1 << endl; + cout << "Berekende W2 = " << W2 << endl; + cout << "Berekende W3 = " << W3 << endl; + cout << "Press ENTER to continue" << endl; + cin.ignore(); + + // genereer waarheidstabel met getrainde perceptron + cout << "waarheidstabel gegenereerd met perceptron => " << endl; + for (int rij = 0; rij < rows; rij++) { + cout << setw(3) << tabel[rij][0] << setw(3) << tabel[rij][1] << setw(3) << tabel[rij][2] << setw(3) << perceptronOutput(tabel[rij][0], tabel[rij][1], tabel[rij][2], W1, W2, W3, threshold) << endl; + } + + cout << "Press ENTER to continue" << endl; + cin.ignore(); + +} // main + + + + + diff --git a/AdvancedVision/perceptron.h b/AdvancedVision/perceptron.h new file mode 100644 index 0000000..26fe579 --- /dev/null +++ b/AdvancedVision/perceptron.h @@ -0,0 +1,5 @@ +#pragma once + +double perceptronOutput(double x1, double x2, double x3, double W1, double W2, double W3, double threshold); + +void run(); diff --git a/AdvancedVision/ueyecallib.yml b/AdvancedVision/ueyecallib.yml new file mode 100644 index 0000000..b8bbb8c --- /dev/null +++ b/AdvancedVision/ueyecallib.yml @@ -0,0 +1,15 @@ +%YAML:1.0 +--- +intrinsic: !!opencv-matrix + rows: 3 + cols: 3 + dt: d + data: [ 5.9775286050661805e+02, 0., 3.2072411619271747e+02, 0., + 5.9771212606858990e+02, 2.3945023396597830e+02, 0., 0., 1. ] +distCoeffs: !!opencv-matrix + rows: 1 + cols: 5 + dt: d + data: [ -2.1240784744163693e-01, 1.5432560677868865e-01, + -1.4662305986052036e-03, 5.8131805718548036e-04, + -4.7909930415801667e-02 ] diff --git a/NeuralDetector/Camera.cpp b/NeuralDetector/Camera.cpp new file mode 100644 index 0000000..79e08a5 --- /dev/null +++ b/NeuralDetector/Camera.cpp @@ -0,0 +1,198 @@ +#include "Camera.h" + +using namespace cv; +using namespace std; + +Camera::Camera(int port) +{ + Camera::port = port; + capture = VideoCapture(port); + + if (!capture.isOpened()) + { + cout << "Failed to open camera on port " << port << endl; + } + + //lees callibratiedata uit + // YML-file met callibratie data openen + FileStorage fs(filename, FileStorage::READ); + + // callibratie data ophalen + fs["intrinsic"] >> intrinsic; + fs["distCoeffs"] >> distCoeffs; + + // sluiten van de YML-file + fs.release(); +} + +Camera::~Camera() +{ +} + +bool Camera::Calibrate() +{ + // The number of boards you want to capture, the number of internal corners horizontally + // and the number of internal corners vertically (That's just how the algorithm works). + int numBoards = 10; + int numCornersHor = 9; + int numCornersVer = 7; + + // We also create some additional variables that we'll be using later on. + int numSquares = numCornersHor * numCornersVer; + Size board_sz = Size(numCornersHor, numCornersVer); + + // We want live feed for our calibration! + + if (!capture.isOpened()) { //check if video device has been initialised + cout << "cannot open camera"; + } + + // - object_points is the physical position of the corners (in 3D space). + // This has to be measured by us. + // - image_points is the location of the corners in the image (in 2 dimensions). + // - Once the program has actual physical locations and locations on the image, it can calculate + // the relation between the two. Because we'll use a chessboard, these points have a definite + // relations between them (they lie on straight lines and on squares). + // - So the "expected" - "actual" relation can be used to correct the distortions in the image. + vector> object_points; + vector> image_points; + + // Next, we create a list of corners. This will temporarily hold the current snapshot's chessboard corners. + // keep track of the number of successfully captured chessboards + vector corners; + int successes = 0; + + // - Create a list of coordinates (0,0,0), (0,1,0), (0,2,0)...(1,4,0)... so on. + // Each corresponds to a particular vertex. + // - You're essentially setting up the units of calibration. + // Suppose the squares in your chessboards were 30 mm in size and you supplied these + // coordinates as (0,0,0), (0, 30, 0), etc, you'd get all unknowns in millimeters. + vector obj; + for (int j = 0; j < numSquares; j++) + obj.push_back(Point3f(j / numCornersHor, j%numCornersHor, 0.0f)); + + // Then we create two images and get the first snapshot from the camera: + Mat image; + Mat gray_image; + capture >> image; + + // As long as the number of successful entries has been less than the number required, + // we keep looping: + while (successes < numBoards) + { + // convert to gray scale + cvtColor(image, gray_image, CV_BGR2GRAY); + + // And we're here. The key functions: + // findChessboardCorners tries to find a chessboard in the image. + // IF found THEN the rough corners are returned. + bool found = findChessboardCorners(image, board_sz, corners, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS); + if (found) + { + // cornerSubPix refines the found corners. + // De rough corners returned by findChessbooardCorners and the gray_image are input, + // the refined corners are output. + cornerSubPix(gray_image, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30, 0.1)); + + // draw the refined corners on the image i.e. chessboard. + drawChessboardCorners(gray_image, board_sz, corners, found); + } + + // show results + imshow("orginal", image); + imshow("gray image", gray_image); + + capture >> image; + + int key = waitKey(1); + + // Leave the program by pressing ESC-key + if (key == 27) return 0; + + // spacebar and chessboard found ==> save the snap + if (key == ' ' && found != 0) + { + image_points.push_back(corners); + object_points.push_back(obj); + + successes++; + + cout << "Stored snap " << successes << "/" << numBoards << endl; + + if (successes >= numBoards) + break; + } + } // while + + // Next, we get ready to do the calibration. We declare variables that will hold the unknowns: + // Matrix intrinsic contains cx,cy,fx,fy + // Matrix disCoeffs contains the distortion coefficients: 3 numbers radial distortion and 2 numbers tangential distortion + intrinsic = Mat(3, 3, CV_32FC1); + distCoeffs; + vector rvecs; + vector tvecs; + + // We modify the intrinsic matrix with whatever we know. + // The camera's aspect ratio is 1 (that's usually the case... + // i.e. fx = fy = f. If not, change it as required. + // Elements (0,0) and (1,1) are the focal lengths along the X and Y axis. + intrinsic.ptr(0)[0] = 1; + intrinsic.ptr(1)[1] = 1; + + // Determine the intrinsic matrix, distortion coefficients and the rotation+translation vectors. + // Note: The calibrateCamera function converts all matrices into 64F format even if you + // initialize it to 32F. + calibrateCamera(object_points, image_points, image.size(), intrinsic, distCoeffs, rvecs, tvecs); + + /***** saven van de callibratie data *****/ + + // YML-file aanmaken + FileStorage fs(filename, FileStorage::WRITE); + + // wegschrijven van callibratie data naar de YML-file + fs << "intrinsic" << intrinsic << "distCoeffs" << distCoeffs; + + // de file afsluiten + fs.release(); + destroyAllWindows(); + + return true; +} + +Mat Camera::getImage() +{ + Mat imageUndistorted; + Mat image; + Mat RGB_img; + + capture >> image; + + undistort(image, imageUndistorted, intrinsic, distCoeffs); + + Rect region_of_interest = Rect(10, 10, image.cols - 20, image.rows - 20); + Mat image_roi = imageUndistorted(region_of_interest); + + return image_roi; +} + +Mat Camera::takeImage() +{ + Mat image; + + bool finished = false; + + while (!finished) + { + image = getImage(); + + imshow("Live feed", image); + + if (waitKey(100) > 0) + { + finished = true; + destroyWindow("Live feed"); + } + } + + return image; +} diff --git a/NeuralDetector/Camera.h b/NeuralDetector/Camera.h new file mode 100644 index 0000000..0b3d396 --- /dev/null +++ b/NeuralDetector/Camera.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#include "avansvisionlib20.h" + +class Camera +{ +public: + Camera(int port); + ~Camera(); + bool Calibrate(); + Mat getImage(); + Mat takeImage(); +private: + const string filename = "calibration.yml"; + int port = 0; + VideoCapture capture; + Mat intrinsic, distCoeffs; +}; + diff --git a/NeuralDetector/FeatureExtractor.cpp b/NeuralDetector/FeatureExtractor.cpp new file mode 100644 index 0000000..ab6909c --- /dev/null +++ b/NeuralDetector/FeatureExtractor.cpp @@ -0,0 +1,165 @@ +#include "FeatureExtractor.h" + + + +FeatureExtractor::FeatureExtractor(vector contour) +{ + FeatureExtractor::contour = contour; + + rect = minAreaRect(contour); +} + + +FeatureExtractor::~FeatureExtractor() +{ +} + +void FeatureExtractor::Extract(Mat &ref) +{ + double ar = AspectRatio(); + double cr = Circularity(); + double bendingEnergy = getBendingEnergy(); + double convexHullBendingEnergy = getConvexHullBendingEnergy(); + double radius = getMinEnclosingCircleRadius(); + double perimeter = getPerimeter(); + double numDefects = convexDefects(); + + //ref = (Mat_(1, 7) << 1.0, convexHullBendingEnergy / 100.0, ar, cr, bendingEnergy / 10000.0, , perimeter / 10000.0); + ref = (Mat_(1, 5) << 1.0, ar, cr / 10.0, convexHullBendingEnergy / 100.0, numDefects / 100.0); +} + +double FeatureExtractor::AspectRatio() +{ + double ar = 0; + + if(rect.size.width > rect.size.height) + ar = (rect.size.height / rect.size.width); + else + ar = (rect.size.width / rect.size.height); + + return ar; +} + +double FeatureExtractor::Circularity() +{ + double radius = getMinEnclosingCircleRadius(); + double carea = radius * radius * M_PI; + double rectarea = rect.size.width * rect.size.height; + double cir = carea / rectarea; + + return cir; +} + +RotatedRect FeatureExtractor::Rectangle() +{ + return rect; +} + +double FeatureExtractor::getMinEnclosingCircleRadius() +{ + float radius; + Point2f center; + minEnclosingCircle(contour, center, radius); + + double rad = (double)radius; + + return rad; +} + +double FeatureExtractor::getPerimeter() +{ + double per = arcLength(contour, true); + + return per; +} + +double FeatureExtractor::getBendingEnergy() +{ + double energy = 0; + int dir = 0; + int prevdir = 0; + + Point previousPoint = contour[contour.size() - 1]; + + for (Point p : contour) + { + dir = discoverNextRelativeDirection(previousPoint, p); + energy += (dir - prevdir + 8) % 8; + prevdir = dir; + previousPoint = p; + } + + return energy; +} + +double FeatureExtractor::getConvexHullBendingEnergy() { + + vector convex; + convexHull(contour, convex); + double energy = 0; + int dir = 0; + int prevdir = 0; + + Point previousPoint = convex[convex.size() - 1]; + + for (Point p : convex) + { + dir = discoverNextRelativeDirection(previousPoint, p); + energy += (dir - prevdir + 8) % 8; + prevdir = dir; + previousPoint = p; + } + + return energy; +} + +int FeatureExtractor::discoverNextRelativeDirection(const cv::Point &pos, const cv::Point &target) +{ + for (int i = 0; i < 8; i++) { + int dir = i; + + int newX = pos.x + rotateX[dir]; + int newY = pos.y + rotateY[dir]; + + if (target.x == newX && target.y == newY) + return dir; + } + + return -1; +} + +double FeatureExtractor::convexDefects() +{ + vector hullsI(contour.size()); // Indices to contour points + vector defects; + convexHull(contour, hullsI, false); + convexityDefects(contour, hullsI, defects); + + return (double)defects.size(); +} + +void FeatureExtractor::findContour(Mat &image, vector &contour) +{ + Mat canny_output; + vector > contours; + vector hierarchy; + + Canny(image, canny_output, 20, 150, 3); + findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); + + int large = 0; + int contouridx = -1; + + for (int i = 0; i < contours.size(); i++) + { + double a = arcLength(contours[i], false); + + if (a > large) + { + large = a; + contouridx = i; + } + } + + contour = contours[contouridx]; +} \ No newline at end of file diff --git a/NeuralDetector/FeatureExtractor.h b/NeuralDetector/FeatureExtractor.h new file mode 100644 index 0000000..2bffe8e --- /dev/null +++ b/NeuralDetector/FeatureExtractor.h @@ -0,0 +1,39 @@ +#pragma once +#define _USE_MATH_DEFINES + +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" +#include +#include +#include +#include + +using namespace std; +using namespace cv; + +class FeatureExtractor +{ +public: + FeatureExtractor(vector contour); + ~FeatureExtractor(); + + void Extract(Mat& ref); + + double AspectRatio(); + double Circularity(); + RotatedRect Rectangle(); + double getMinEnclosingCircleRadius(); + double getPerimeter(); + double getBendingEnergy(); + double getConvexHullBendingEnergy(); + double convexDefects(); + + static void findContour(Mat &image, vector &contour); +private: + vector contour; + RotatedRect rect; + int rotateX[8] = { 0, 1, 1, 1, 0, -1, -1, -1 }; + int rotateY[8] = { -1, -1, 0, 1, 1, 1, 0, -1 }; + int discoverNextRelativeDirection(const cv::Point &pos, const cv::Point &target); +}; + diff --git a/NeuralDetector/Main.cpp b/NeuralDetector/Main.cpp new file mode 100644 index 0000000..051b9bb --- /dev/null +++ b/NeuralDetector/Main.cpp @@ -0,0 +1,132 @@ +#include +#include +#include + +#include "Training.h" +#include "Camera.h" +#include "FeatureExtractor.h" + +using namespace std; +using namespace cv; + +int run(); + +int main(int argc, char** argv) +{ + Camera cam(1); + Training tr; + + cout << "Welcome to Jarvis" << endl; + cout << "Would you like to calibrate the camera (c), take pictures (p), train the network (t) or run the neural network (r)?" << endl; + + char c; + cin >> c; + + switch (c) { + case 'c': + cam.Calibrate(); + break; + case 'p': + tr.CreateTrainingSet(); + break; + case 't': + tr.LoadTrainingSet(); + break; + case 'r': + run(); + break; + default: + return 0; + } + + cout << "The program has finished, press enter to exit" << endl; + cin.ignore(); + + return 0; +} + +int run() +{ + Camera cam = Camera(1); + NeuralNetwork bpn; + bpn.Read(); + + while (true) + { + //Take picture and pre-process + Mat image, gray_image, binaryImage; + + image = cam.takeImage(); + cvtColor(image, gray_image, CV_BGR2GRAY); + + //Find contour + vector contour; + FeatureExtractor::findContour(gray_image, contour); + + //Extrax features + FeatureExtractor ext = FeatureExtractor(contour); + Mat descriptors = Mat_(); + + ext.Extract(descriptors); + + descriptors = transpose(descriptors); + + string cls; + bpn.Predict(descriptors, cls); + + cout << "It\'s a " << cls << endl; + + // teken de contouren + Point2f vertices2f[4]; + ext.Rectangle().points(vertices2f); + + // Convert them so we can use them in a fillConvexPoly + Point vertices[4]; + for (int i = 0; i < 4; ++i) { + vertices[i] = vertices2f[i]; + } + + // Now we can fill the rotated rectangle with our specified color + fillConvexPoly(image, vertices, 4, Scalar(0, 0, 255)); + + vector> contours; + contours.push_back(contour); + drawContours(image, contours, -1, CV_RGB(0, 255, 0), 4); + putText(image, cls, cvPoint(15, 30), + FONT_HERSHEY_COMPLEX, 1.0, cvScalar(0, 0, 0), 1, CV_AA); + + imshow("Neural detection", image); + + waitKey(0); + + destroyAllWindows(); + } +} + + +/* +// Creeer een witte image +IplImage* iplimage = cvCreateImage(cvSize(binaryImage.cols, binaryImage.rows), IPL_DEPTH_8U, 3); +Mat contourImage = cvarrToMat(iplimage); +contourImage = Scalar(255, 255, 255); + +// teken de contouren op de witte image +vector> contours; +contours.push_back(contour); + +Point2f vertices2f[4]; +ext.Rectangle().points(vertices2f); + +// Convert them so we can use them in a fillConvexPoly +Point vertices[4]; +for (int i = 0; i < 4; ++i) { + vertices[i] = vertices2f[i]; +} + +// Now we can fill the rotated rectangle with our specified color +fillConvexPoly(contourImage, vertices, 4, Scalar(0, 255, 0)); +drawContours(contourImage, contours, -1, CV_RGB(255, 0, 0)); + +imshow("Features", contourImage); +waitKey(0); +*/ \ No newline at end of file diff --git a/NeuralDetector/NeuralDetector.vcxproj b/NeuralDetector/NeuralDetector.vcxproj new file mode 100644 index 0000000..14491bd --- /dev/null +++ b/NeuralDetector/NeuralDetector.vcxproj @@ -0,0 +1,177 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {E74AD02B-6B3F-431B-8D7E-DBFED7E6B671} + Win32Proj + NeuralDetector + 8.1 + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) + D:\Code\OpenCV\install\include;%(AdditionalUsingDirectories) + + + Console + true + D:\Code\OpenCV\install\x64\vc14\lib;%(AdditionalLibraryDirectories) + opencv_world330d.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) + D:\Code\OpenCV\install\include;%(AdditionalUsingDirectories) + + + Console + true + D:\Code\OpenCV\install\x64\vc14\lib;%(AdditionalLibraryDirectories) + opencv_world330d.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + D:\Code\OpenCV\install\x64\vc14\lib;%(AdditionalLibraryDirectories) + opencv_world330.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + D:\Code\OpenCV\install\include;%(AdditionalIncludeDirectories) + + + Console + true + true + true + D:\Code\OpenCV\install\x64\vc14\lib;%(AdditionalLibraryDirectories) + opencv_world330.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NeuralDetector/NeuralDetector.vcxproj.filters b/NeuralDetector/NeuralDetector.vcxproj.filters new file mode 100644 index 0000000..64d0be2 --- /dev/null +++ b/NeuralDetector/NeuralDetector.vcxproj.filters @@ -0,0 +1,57 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/NeuralDetector/NeuralNetwork.cpp b/NeuralDetector/NeuralNetwork.cpp new file mode 100644 index 0000000..a81442c --- /dev/null +++ b/NeuralDetector/NeuralNetwork.cpp @@ -0,0 +1,222 @@ +// Demo: Training of a Neural Network / Back-Propagation algorithm +// Jan Oostindie, Avans Hogeschool, dd 6-12-2016 +// email: jac.oostindie@avans.nl + +#include "NeuralNetwork.h" + +NeuralNetwork::NeuralNetwork() +{ + V0 = Mat(); + W0 = Mat(); +} + +NeuralNetwork::~NeuralNetwork() +{ +} + +Mat NeuralNetwork::Train(Mat& ITset, Mat& OTset) +{ + // V0, W0 : weightfactor matrices + // dV0, dW0 : weightfactor correction matrices + Mat dW0, dV0; + + // default number of hiddenNeurons. The definite number is user input + // inputNeurons and outputNeurons are implicitly determined via + // the trainingset, i.e.: inputNeurons = ITset.cols ; outputNeurons = OTset.cols; + int hiddenNeurons = 8; + + //loadTrainingSet1(ITset, OTset); + initializeBPN(ITset.cols, hiddenNeurons, OTset.cols, V0, dV0, W0, dW0); + //testBPN(ITset, OTset, V0, dV0, W0, dW0); + + + // IT: current training input of the inputlayer + // OT: desired training output of the BPN + // OH: output of the hiddenlayer + // OO: output of the outputlayer + Mat IT, OT, OH, OO; + + // outputError0: error on output for the current input and weighfactors V0, W0 + // outputError1: error on output for the current input and new calculated + // weighfactors, i.e. V1, W1 + double outputError0, outputError1, sumSqrDiffError = MAX_OUTPUT_ERROR + 1; + Mat V1, W1; + + cout << endl << "Starting neural training..." << endl; + + int runs = 0; + while ((sumSqrDiffError > MAX_OUTPUT_ERROR) && (runs < MAXRUNS)) { + + sumSqrDiffError = 0; + + for (int inputSetRowNr = 0; inputSetRowNr < ITset.rows; inputSetRowNr++) { + + IT = transpose(getRow(ITset, inputSetRowNr)); + + OT = transpose(getRow(OTset, inputSetRowNr)); + + calculateOutputHiddenLayer(IT, V0, OH); + + calculateOutputBPN(OH, W0, OO); + + adaptVW(OT, OO, OH, IT, W0, dW0, V0, dV0, W1, V1); + + calculateOutputBPNError(OO, OT, outputError0); + + calculateOutputBPNError(BPN(IT, V1, W1), OT, outputError1); + + sumSqrDiffError += (outputError1 - outputError0) * (outputError1 - outputError0); + + V0 = V1; + W0 = W1; + } + runs++; + + if (runs % 1000 == 0) + cout << "Completed " << runs << " runs, still working on it.. (" << sumSqrDiffError << ")" << endl; + } + + cout << "Training complete in " << runs << " runs" << endl; + + Mat inputVectorTrainingSet, outputVectorTrainingSet, outputVectorBPN; + + // druk voor elke input vector uit de trainingset de output vector uit trainingset af + // tezamen met de output vector die het getrainde BPN (zie V0, W0) genereerd bij de + // betreffende input vector. + for (int row = 0; row < ITset.rows; row++) { + + // haal volgende inputvector op uit de training set + inputVectorTrainingSet = transpose(getRow(ITset, row)); + + // haal bijbehorende outputvector op uit de training set + outputVectorTrainingSet = transpose(getRow(OTset, row)); + + // bepaal de outputvector die het getrainde BPN oplevert + // bij de inputvector uit de trainingset + outputVectorBPN = BPN(inputVectorTrainingSet, V0, W0); + } + + write(); + + return outputVectorBPN; +} + +void NeuralNetwork::Predict(Mat& ITset, string& name) +{ + Mat output; + output = transpose(BPN(ITset, V0, W0)); + + mat_class(output, name); +} + +void NeuralNetwork::Read() +{ + load(); +} + +void NeuralNetwork::write() +{ + for (pair p : classes) + cout << p.first << " - " << p.second << endl; + + FileStorage fs("factors.yml", FileStorage::WRITE); + fs << "W0" << W0 << "V0" << V0; + fs.release(); + + FileStorage fs2("classes.yml", FileStorage::WRITE); + + fs2 << "classes" << "{:"; + + for (pair p : classes) + { + string el = "e" + to_string(p.first); + fs2 << el << p.second; + } + + fs2 << "}"; + + fs2.release(); +} + +void NeuralNetwork::load() +{ + FileStorage fs("factors.yml", FileStorage::READ); + + fs["W0"] >> W0; + fs["V0"] >> V0; + + fs.release(); + + FileStorage fs2("classes.yml", FileStorage::READ); + + classes.clear(); + + FileNode cls = fs2["classes"]; + FileNodeIterator it = cls.begin(), it_end = cls.end(); + int idx = 0; + + // iterate through a sequence using FileNodeIterator + for (; it != it_end; ++it, idx++) + { + cv::FileNode item = *it; + std::string key = item.name(); + string value = (string)item; + + classes.insert(pair(idx, value)); + } + + cout << endl << "Available classes: " << endl; + + for (pair p : classes) + cout << p.first << " - " << p.second << endl; + + cout << endl; + + fs2.release(); +} + +void NeuralNetwork::getClass(const string& name, Mat& ref) +{ + save_class(name, ref); +} + +void NeuralNetwork::save_class(const string& name, Mat& ref) +{ + for (pair p : classes) + { + if (p.second == name) + { + class_mat(p.first, ref); + return; + } + } + + classes.insert(pair(classidx, name)); + class_mat(classidx, ref); + classidx++; +} + +void NeuralNetwork::class_mat(int index, Mat& ref) +{ + ref = cv::Mat::zeros(cv::Size(numclasses, 1), CV_32F); + ref.at(index) = 1; +} + +void NeuralNetwork::mat_class(Mat& ref, string& name) +{ + double maxvalue = 0; + int index = 0; + + for (int i = 0; i < ref.cols; i++) + { + double temp = getEntry(ref, 0, i); + + if (temp > maxvalue) + { + maxvalue = temp; + index = i; + } + } + + name = classes[index] + " " + to_string(maxvalue*100) + "%"; +} \ No newline at end of file diff --git a/NeuralDetector/NeuralNetwork.h b/NeuralDetector/NeuralNetwork.h new file mode 100644 index 0000000..3277282 --- /dev/null +++ b/NeuralDetector/NeuralNetwork.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +#include "avansvisionlib20.h" // versie 2.0 (!) + +class NeuralNetwork +{ +public: + NeuralNetwork(); + ~NeuralNetwork(); + Mat Train(Mat& in, Mat& out); + void Predict(Mat& ITset, string& name); + void Read(); + void getClass(const string& name, Mat& ref); +private: + Mat V0, W0; + const int MAXRUNS = 30000; + const double MAX_OUTPUT_ERROR = 1E-11; + void write(); + void load(); + + const int numclasses = 10; + map classes; + int classidx = 0; + void save_class(const string& name, Mat& ref); + void class_mat(int index, Mat& ref); + void mat_class(Mat& ref, string& name); +}; \ No newline at end of file diff --git a/NeuralDetector/OpenNetwork.h b/NeuralDetector/OpenNetwork.h new file mode 100644 index 0000000..28241b9 --- /dev/null +++ b/NeuralDetector/OpenNetwork.h @@ -0,0 +1,8 @@ +#pragma once +class OpenNetwork +{ +public: + OpenNetwork(); + ~OpenNetwork(); +}; + diff --git a/NeuralDetector/Training.cpp b/NeuralDetector/Training.cpp new file mode 100644 index 0000000..218dd2f --- /dev/null +++ b/NeuralDetector/Training.cpp @@ -0,0 +1,148 @@ +#include "Training.h" + +using namespace cv; +using namespace std; + + +Training::Training() +{ + +} + + +Training::~Training() +{ +} + +void Training::CreateTrainingSet() +{ + Camera cam = Camera(1); + bool running = true; + + while (running) + { + string in; + cout << "Ready for next category" << endl; + cout << "Please specifiy name or type exit to stop: "; + cin >> in; + + if (in == "exit") + { + running = false; + break; + } + + bool takingPhotos = true; + int i = 0; + + while (takingPhotos) + { + Mat image; + image = cam.getImage(); + + imshow("Live feed", image); + + int key = waitKey(100); + switch (key) + { + case 32: + imwrite("training/" + in + "_" + to_string(i) + ".bmp", image); + cout << "Image taken #" << i << endl; + i++; + break; + case 27: + destroyWindow("Live feed"); + takingPhotos = false; + running = false; + break; + case 110: + destroyWindow("Live feed"); + takingPhotos = false; + default: + break; + } + } + } +} + +void Training::LoadTrainingSet() +{ + NeuralNetwork bpn; + + Mat ITset = Mat_(); + Mat OTset = Mat_(); + + vector files; + string dir = "training/"; + + read_directory(dir, files); + + cout << "Found " << files.size()-2 << " files in " << dir << endl; + + random_shuffle(files.begin(), files.end()); + + for (string file : files) + { + string loc = dir + file; + + Mat image; + image = imread(loc, CV_LOAD_IMAGE_COLOR); + + if (!image.data) + continue; + + cout << "Loaded " << file << endl; + + string classname; + class_name(file, classname); + + Mat gray_image, binaryImage; + cvtColor(image, gray_image, CV_BGR2GRAY); + threshold(gray_image, binaryImage, 200, 1, CV_THRESH_BINARY_INV); + + //Extract Features + vector contour; + FeatureExtractor::findContour(gray_image, contour); + FeatureExtractor ftext = FeatureExtractor(contour); + + Mat descriptors; + ftext.Extract(descriptors); + Mat output; + bpn.getClass(classname, output); + + ITset.push_back(descriptors); + OTset.push_back(output); + } + + destroyAllWindows(); + + cout << "Finished loading all files" << endl; + + bpn.Train(ITset, OTset); + + cout << "Training complete" << endl; + + cin.ignore(); +} + + + +void Training::read_directory(const string& name, vector &v) +{ + string pattern = name; + pattern.append("\\*"); + WIN32_FIND_DATA data; + HANDLE hFind; + if ((hFind = FindFirstFile(pattern.c_str() , &data)) != INVALID_HANDLE_VALUE) { + do { + v.push_back(data.cFileName); + } while (FindNextFile(hFind, &data) != 0); + FindClose(hFind); + } +} + +void Training::class_name(const string& name, string& classname) +{ + string::size_type const p(name.find_last_of('_')); + classname = name.substr(0, p); +} \ No newline at end of file diff --git a/NeuralDetector/Training.h b/NeuralDetector/Training.h new file mode 100644 index 0000000..970b610 --- /dev/null +++ b/NeuralDetector/Training.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include + +#include + +#include "Camera.h" +#include "FeatureExtractor.h" +#include "NeuralNetwork.h" + +class Training +{ +public: + Training(); + ~Training(); + + void CreateTrainingSet(); + void LoadTrainingSet(); +private: + void read_directory(const string& name, vector &v); + void class_name(const string& name, string& classname); +}; + diff --git a/NeuralDetector/avansvisionlib20.cpp b/NeuralDetector/avansvisionlib20.cpp new file mode 100644 index 0000000..62ce8e8 --- /dev/null +++ b/NeuralDetector/avansvisionlib20.cpp @@ -0,0 +1,1051 @@ +// avansvisionlib - Growing Visionlibrary of Avans based on OpenCV 2.4.10 +// Goal: deep understanding of vision algorithms by means of developing own (new) algorithms. +// deep understanding of neural networks +// +// Copyright Jan Oostindie, version 2.0 dd 5-12-2016 (= Neural Network (BPN) added to version 1.0 dd 5-11-2016.) +// Contains basic functions to perform calculations on matrices/images of class Mat. Including BLOB labeling functions +// Contains a BPN neural network. +// Note: Students of Avans are free to use this library in projects and for own vision competence development. Others may ask permission to use it by means +// of sending an email to Jan Oostindie, i.e. jac.oostindie@avans.nl + +#include "avansvisionlib20.h" +#include +#include /* srand, rand */ +#include /* time */ + +// pre: (i < m.rows) & (j < m.cols) +// Mat is call by reference +void setEntry(Mat m, int i, int j, double value) { + int index = i * m.cols + j; + double * p = m.ptr(0); + p[index] = value; +} // setEntry + +// pre: (i < m.rows) & (j < m.cols) +double getEntry(Mat m, int i, int j) { + int index = i * m.cols + j; + double * p = m.ptr(0); + return *(p + index); +} // getEntry + + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) +double inproduct(Mat row, Mat col) { + double * p1 = row.ptr(0); + double * p2 = col.ptr(0); + double sumproducts = 0; + for (int i = 0; i < row.cols; i++) + sumproducts += p1[i] * p2[i]; + return sumproducts; +} // inproduct + +void printMatrix(Mat m) { + for (int i = 0; i < m.rows; i++) { + for (int j = 0; j < m.cols; j++) + cout << getEntry(m, i, j) << " "; + cout << endl; + } + cout << endl; +} // printMatrix + + +Mat getRow(Mat m, int rowNr) { + Mat result = Mat_(1, m.cols); + double entry; + for (int colNr = 0; colNr < m.cols; colNr++) { + entry = getEntry(m, rowNr, colNr); + // cout << m << endl; + // cout << " ** getRow ** " << endl; + // cout << " entry = " << entry << endl; + setEntry(result, 0, colNr, entry); + } + return result; +} // getRow + +Mat getCol(Mat m, int colNr) { + Mat result = Mat_(m.rows, 1); + double entry; + for (int rowNr = 0; rowNr < m.rows; rowNr++) { + entry = getEntry(m, rowNr, colNr); + // cout << " ** getColumn ** " << endl; + // cout << " entry = " << entry << endl; + setEntry(result, rowNr, 0, entry); + } + return result; +} // getCol + + + +// pre: (a.cols == b.rows) +Mat multiply(Mat a, Mat b) +{ + assert(a.cols == b.rows); + Mat result = Mat_(a.rows, b.cols); + double inprod; + for (int arow = 0; arow < a.rows; arow++) { + for (int bcol = 0; bcol < b.cols; bcol++) { + inprod = inproduct(getRow(a, arow), getCol(b, bcol)); + setEntry(result, arow, bcol, inprod); + } + } + return result; +} // multiply + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +Mat add(Mat a, Mat b) +{ + Mat result = Mat_(a.rows, a.cols); + double entrysum; + for (int row = 0; row < a.rows; row++) { + for (int col = 0; col < a.cols; col++) { + entrysum = getEntry(a, row, col) + getEntry(b, row, col); + setEntry(result, row, col, entrysum); + } + } + return result; +} // add + + +Mat transpose(Mat m) { + Mat result = Mat_(m.cols, m.rows); + for (int row = 0; row < m.rows; row++) + for (int col = 0; col < m.cols; col++) + setEntry(result, col, row, getEntry(m, row, col)); + return result; +} // transpose + + +// func: sets all entries of a matrix to a value +// pre: true +void setValue(Mat m, double value) { + for (int row = 0; row < m.rows; row++) + for (int col = 0; col < m.cols; col++) + setEntry(m, row, col, value); +} // setValue + + +double generateRandomValue(double min, double max) { + int steps = rand() % 100 + 1; + double dx = (max - min) / 100; + return min + dx * steps; +} // generateRandomValue + + +// func: sets all entries of a matrix to a random value in interval [min,max] +// pre: true +void setRandomValue(Mat m, double min, double max) { + srand(time(NULL)); + for (int row = 0; row < m.rows; row++) + for (int col = 0; col < m.cols; col++) + setEntry(m, row, col, generateRandomValue(min, max)); +} // randomValue + + + +/*********************************** Image operaties ****************************************/ +// NB images are supposed to have 1 channel (B/W image) and depth 16 bits signed (CV_16S) +/********************************************************************************************/ + +void setEntryImage(Mat m, int i, int j, _int16 value) { + int index = i * m.cols + j; + _int16 * p = m.ptr<_int16>(0); + p[index] = value; +} // setEntry + +// pre: (i < m.rows) & (j < m.cols) +_int16 getEntryImage(Mat m, int i, int j) { + int index = i * m.cols + j; + _int16 * p = m.ptr<_int16>(0); + return *(p + index); +} // getEntryImage + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) +_int16 inproductImage(Mat row, Mat col) { + _int16 * p1 = row.ptr<_int16>(0); + _int16 * p2 = col.ptr<_int16>(0); + _int16 sumproducts = 0; + for (int i = 0; i < row.cols; i++) + sumproducts += p1[i] * p2[i]; + return sumproducts; +} // inproductImage + + +Mat getRowImage(Mat m, int rowNr) { + Mat result = Mat_<_int16>(1, m.cols); + _int16 entry; + for (int colNr = 0; colNr < m.cols; colNr++) { + entry = getEntryImage(m, rowNr, colNr); + setEntryImage(result, 0, colNr, entry); + } + return result; +} // getRow + +Mat getColImage(Mat m, int colNr) { + Mat result = Mat_<_int16>(m.rows, 1); + _int16 entry; + for (int rowNr = 0; rowNr < m.rows; rowNr++) { + entry = getEntryImage(m, rowNr, colNr); + setEntryImage(result, rowNr, 0, entry); + } + return result; +} // getColImage + +Mat multiplyImage(Mat a, Mat b) +{ + Mat result = Mat_<_int16>(a.rows, b.cols); + _int16 inprod; + for (int arow = 0; arow < a.rows; arow++) { + for (int bcol = 0; bcol < b.cols; bcol++) { + inprod = inproductImage(getRow(a, arow), getColImage(b, bcol)); + setEntry(result, arow, bcol, inprod); + } + } + return result; +} // multiplyImage + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +Mat addImage(Mat a, Mat b) +{ + Mat result = Mat_<_int16>(a.rows, a.cols); + _int16 entrysum; + for (int row = 0; row < a.rows; row++) { + for (int col = 0; col < a.cols; col++) { + entrysum = getEntryImage(a, row, col) + getEntryImage(b, row, col); + setEntryImage(result, row, col, entrysum); + } + } + return result; +} // addImage + + +// func: searches the maximum pixel value in the image +// return: maximum pixel +_int16 maxPixelImage(Mat m) { + _int16 max = getEntryImage(m, 0, 0); + _int16 next; + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + next = getEntryImage(m, row, col); + if (next > max) max = next; + } + } + return max; +} // maxPixelImage + +// func: searches the minimum pixel value in the image +// return: minimum pixel value +_int16 minPixelImage(Mat m) { + _int16 min = getEntryImage(m, 0, 0); + _int16 next; + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + next = getEntryImage(m, row, col); + if (next < min) min = next; + } + } + return min; +} // minPixelImage + +// func: determines the range of the image, i.e. the minimum +// and maximum pixel value in the image +// post: range = minPixelValue, maxPixelValue +void getPixelRangeImage(Mat m, _int16 &minPixelValue, _int16 &maxPixelValue) { + _int16 max = getEntryImage(m, 0, 0); + _int16 min = getEntryImage(m, 0, 0); + _int16 next; + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + next = getEntryImage(m, row, col); + if (next > max) max = next; + else + if (next < min) min = next; + } + } + minPixelValue = min; + maxPixelValue = max; +} // getPixelRangeImage + + +// func: stretches the image to a specified range +void stretchImage(Mat m, _int16 minPixelValue, _int16 maxPixelValue) { + _int16 min, max, oldValue, newValue; + getPixelRangeImage(m, min, max); + double scale = maxPixelValue - minPixelValue; + scale /= (max - min); + for (int row = 0; row < m.rows; row++) { + for (int col = 0; col < m.cols; col++) { + oldValue = getEntryImage(m, row, col); + newValue = scale * (oldValue - min) + minPixelValue; + setEntryImage(m, row, col, newValue); + } + } +} // stretchImage + + +// func: shows a 16S image on the screen +// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageStretch(Mat m, string windowTitle) { + Mat mCopy; + m.copyTo(mCopy); + stretchImage(mCopy, 0, 255); + mCopy.convertTo(mCopy, CV_8U); + // namedWindow(windowTitle, CV_WINDOW_AUTOSIZE); + imshow(windowTitle, mCopy); + waitKey(0); +} // show16SImage + +// func: shows a 16S image on the screen. All values clipped to the interval 0-255 +// i.e. value < 0 => 0; 0 <= value <= 255 => value ; value > 255 => 255 +/// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageClip(Mat m, string windowTitle) { + Mat mCopy; + m.copyTo(mCopy); + mCopy.convertTo(mCopy, CV_8U); + // namedWindow("show16SImageClip", CV_WINDOW_AUTOSIZE); + imshow(windowTitle, mCopy); + waitKey(0); +} // show16SImage + + +// func: histogram gamma correction +// pre: image has depth 8 bits unsigned and 1 or 3 channels +// post: entry(i,j) = 255*power(entry@pre(i,j)/255)^gamma +void gammaCorrection(Mat image, float gamma) { + unsigned char lut[256]; + for (int i = 0; i < 256; i++) { + lut[i] = saturate_cast(pow((float)(i / 255.0), gamma) * 255.0f); + } + // dst = src.clone(); + const int channels = image.channels(); + switch (channels) { + case 1: { + MatIterator_ it, end; + for (it = image.begin(), end = image.end(); it != end; it++) + *it = lut[(*it)]; + break; + } + case 3: { + MatIterator_ it, end; + for (it = image.begin(), end = image.end(); it != end; it++) { + (*it)[0] = lut[((*it)[0])]; + (*it)[1] = lut[((*it)[1])]; + (*it)[2] = lut[((*it)[2])]; + } + break; + } + } // switch +} // gammaCorrection + + +// func: makes a administration used for labeling blobs. +// the function adds a edge of 1 pixel wide tot a binary image, all with value 0. +// All 1's are made -1. The result is returned. +// This function is used by function labelBLOBs +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// return_matrix: All "1" are made "-1" meaning value 1 and unvisited. +Mat makeAdmin(Mat binaryImage) { + Mat result = Mat_<_int16>(binaryImage.rows + 2, binaryImage.cols + 2); + + // eerste rij 0 maken + for (int col = 0; col < result.cols; col++) + setEntryImage(result, 0, col, 0); + + // binaryImage copieren naar admin waarbij een 1 steeds wordt omgezet naar -1. + for (int row = 1; row < (result.rows - 1); row++) { + + // 0 vooraan de rij zetten + setEntryImage(result, row, 0, 0); + + // rij binaryImage copieren + _int16 value; + for (int col = 1; col < result.cols - 1; col++) { + value = getEntryImage(binaryImage, row - 1, col - 1); + if (value == 1) value = -1; + setEntryImage(result, row, col, value); + } + + // 0 achteraan de rij zetten + setEntryImage(result, row, result.cols - 1, 0); + } // for + + // laatste rij 0 maken + for (int col = 0; col < result.cols; col++) + setEntryImage(result, result.rows - 1, col, 0); + + return result; +} // makeAdmin + + +// func: Searches the next blob after position (row,col) i.e. searches +// the next -1 in admin +// post: if return_value == 1 then (row,col) contains the position +// where the next blob starts. +// return_value: 1 next blob found ; starting position is (row,col) +// 0 no blob found ; (row, col) == (-1, -1) +bool findNextBlob(Mat admin, int & row, int & col) { + + bool found = false; + + // zoeken in de huidige rij + for (int currCol = col; (currCol < (admin.cols - 1)) & !found; currCol++) + if (getEntryImage(admin, row, currCol) == -1) { + found = true; + // row unchanged + col = currCol; + } + + // zoeken vanaf de volgende rij + for (int currRow = row + 1; (currRow < (admin.rows - 1)) &!found; currRow++) + for (int currCol = 1; (currCol < (admin.cols - 1)) & !found; currCol++) + if (getEntryImage(admin, currRow, currCol) == -1) { + found = true; + row = currRow; + col = currCol; + } + + if (!found) { + row = -1; + col = -1; + } + return found; +}; // findNextBlob + +// func: gets the entry of a neighbour pixel with relative position nr. +// Definition of relative positions nr: +// 7 0 1 +// 6 X 2 +// 5 4 3 +_int16 getEntryNeighbour(const Mat & admin, int x, int y, int nr) { + switch (nr) { + case 0: return getEntryImage(admin, x - 1, y); break; + case 1: return getEntryImage(admin, x - 1, y + 1); break; + case 2: return getEntryImage(admin, x, y + 1); break; + case 3: return getEntryImage(admin, x + 1, y + 1); break; + case 4: return getEntryImage(admin, x + 1, y); break; + case 5: return getEntryImage(admin, x + 1, y - 1); break; + case 6: return getEntryImage(admin, x, y - 1); break; + case 7: return getEntryImage(admin, x - 1, y - 1); break; + default: cout << "ERROR getEntryNeighbour " << endl; + } +} // getEntryNeighbour + +// func: determines if there are more than 1 adjacent 1's +bool moreNext1(const Mat & admin, int x, int y) { + int cnt1 = 0; + bool more = false; + for (int nr = 0; (nr <= 7) & !more; nr++) + if (getEntryNeighbour(admin, x, y, nr) == -1) { + cnt1++; + if (cnt1 > 1) more = true; + } + return more; +} // moreNext1 + +// func: searches the first 1 when rotating around the pixel (currX,currY), +// starting at position 0. Definition of relative positions: +// 7 0 1 +// 6 X 2 +// 5 4 3 +void findNext1(Mat admin, int & currX, int & currY, int & next1) { + int rotX, rotY; + + rotX = currX - 1; rotY = currY; //0 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 0; + else { + rotX = currX - 1; rotY = currY + 1; //1 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 1; + else { + rotX = currX; rotY = currY + 1; //2 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 2; + else { + rotX = currX + 1; rotY = currY + 1; //3 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 3; + else { + rotX = currX + 1; rotY = currY; //4 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 4; + else { + rotX = currX + 1; rotY = currY - 1; //5 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 5; + else { + rotX = currX; rotY = currY - 1; //6 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 6; + else { + rotX = currX - 1; rotY = currY - 1; //7 + if (getEntryImage(admin, rotX, rotY) == -1) next1 = 7; + else next1 = -99; + } // 6 + } // 5 + } // 4 + } // 3 + } // 2 + } // 1 + } //0 + if (next1 >= 0) { + currX = rotX; + currY = rotY; + } +} // findNext1 + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// This function is used by function labelBLOB's which labels all blobs. +// return_value: area of the blob +// Evaluation: This function uses a iterative algorithm in which a special labeling technique is +// is used which gives the opportunity to trace all individiual pixels. This makes it +// possible for example to save only these pixels on disk or to translate the object in +// in the image. +// The disadvantagae however is that the algorithm is more complicated an maybe a little bit +// slower than the recursive variant. +int labelIter(Mat & admin, int row, int col, int blobNr) { + // Every visited pixel is labeled with: + // blobNr*10 + + // + // definition of relative positions + // 7 0 1 + // 6 X 2 + // 5 4 3 + // + // The first visited pixel, i.e. (row,col), is labeled with: + // blobNr * 10 + 8 + + int x = row, y = col; + setEntryImage(admin, x, y, blobNr * 10 + 8); + + int next1 = -999; + int area = 1; + + // flag more is set when any entry in the path has two or more + // unvisited neighbours because we visit only one at a time. + bool allLabeledFlag = true; + while (allLabeledFlag) { + allLabeledFlag = false; + bool pathLabeled = false; + while (!pathLabeled) { + + if (!allLabeledFlag) allLabeledFlag = moreNext1(admin, x, y); + findNext1(admin, x, y, next1); + + if (next1 >= 0) { + setEntryImage(admin, x, y, blobNr * 10 + next1); + area++; + } + else { + //findprevious + switch (getEntryImage(admin, x, y) % 10) { + case 0: x += 1; break; + case 1: x += 1; y -= 1; break; + case 2: y -= 1; break; + case 3: x -= 1; y -= 1; break; + case 4: x -= 1; break; + case 5: x -= 1; y += 1; break; + case 6: y += 1; break; + case 7: x += 1; y += 1; break; + case 8: pathLabeled = true; break; // currIndex should be 0 now + default: cout << "Error func labelIter!"; + } // case + } // else + } // while + } // while (more) + return area; +} // labelIter + + +// func: labels all pixels of one blob which starts at position (topX,topY) with blobNr. +// During the labeling proces the centre of gravity is calculated. +// This function is used by function labelBLOBInfo +// return_value: area of the blob +// Evaluation: This function uses a iterative algorithm in which a special labeling technique is +// is used which gives the opportunity to trace all individiual pixels. This makes it +// possible for example to save only these pixels on disk or to translate the object in +// in the image. +// The disadvantagae however is that the algorithm is more complicated an maybe a little bit +// slower than the recursive variant. +int labelIterInfo(Mat & admin, int topX, int topY, int blobNr, + int & xGravity, int & yGravity) { + + // Every visited pixel is labeled with: + // blobNr*10 + + // + // definition of relative positions + // 7 0 1 + // 6 X 2 + // 5 4 3 + // + // The first visited pixel, i.e. (row,col), is labeled with: + // blobNr * 10 + 8 + + xGravity = topX; + yGravity = topY; + int x = topX, y = topY; + setEntryImage(admin, topX, topY, blobNr * 10 + 8); + + int next1 = -999; + int area = 1; + + // allLabeledFlag is set when any entry in the path has two or more + // unvisited neighbours because we visit only one at a time. + // This algorithm good be speeded up by using a stack (future improvement) + bool allLabeledFlag = true; + while (allLabeledFlag) { + allLabeledFlag = false; + bool pathLabeled = false; + while (!pathLabeled) { + + if (!allLabeledFlag) allLabeledFlag = moreNext1(admin, x, y); + findNext1(admin, x, y, next1); + + if (next1 >= 0) { + setEntryImage(admin, x, y, blobNr * 10 + next1); + area++; + xGravity += x; + yGravity += y; + } + else { + //findprevious + switch (getEntryImage(admin, x, y) % 10) { + case 0: x += 1; break; + case 1: x += 1; y -= 1; break; + case 2: y -= 1; break; + case 3: x -= 1; y -= 1; break; + case 4: x -= 1; break; + case 5: x -= 1; y += 1; break; + case 6: y += 1; break; + case 7: x += 1; y += 1; break; + case 8: pathLabeled = true; break; // currIndex should be 0 now + default: cout << "Error func labelIter!"; + } // case + } // else + } // while + } // while (more) + xGravity /= area; + yGravity /= area; + return area; +} // labelIterInfo + + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// return_value: area of the blob +// Evaluation: This function uses a recursive algorithm which has the advantage that it is easy and trasparent. +// The disadvantagae however is that it claims a lot of spacee on the stack. I.e. every found +// pixel results in a function call which in case of large blobs causes a stack overflow. +int labelRecursive(Mat & admin, int row, int col, int blobNr) { + int area = 0; + // bij waarde -1 is het pixel nog niet bezocht + if (getEntryImage(admin, row, col) == -1) { + //cout << "(row,col) = " << "(" << row << "," << col << ")" << endl; + // pixel labelen met het volgnummer van de blob + setEntryImage(admin, row, col, blobNr); + area = 1; + + // alle pixels rondom huidige pixel bezoeken + // (row-1,col-1) (row-1,col ) (row-1,col+1) + // (row ,col-1) (row, col ) (row ,col+1) + // (row+1,col-1) (row, col ) (row+1,col+1) + area += labelRecursive(admin, row - 1, col, blobNr); + area += labelRecursive(admin, row - 1, col + 1, blobNr); + area += labelRecursive(admin, row, col + 1, blobNr); + area += labelRecursive(admin, row + 1, col + 1, blobNr); + area += labelRecursive(admin, row, col, blobNr); + area += labelRecursive(admin, row + 1, col - 1, blobNr); + area += labelRecursive(admin, row, col - 1, blobNr); + area += labelRecursive(admin, row - 1, col - 1, blobNr); + } + return area; +} // label + +// func: retrieves a labeledImage from the labeling administration +// pre : admin is contains labeled pixels with neighbour number information. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +void retrieveLabeledImage(const Mat & admin, Mat & labeledImage) { + labeledImage = Mat_<_int16>(admin.rows - 2, admin.cols - 2); + + for (int row = 1; row < admin.rows - 1; row++) { + for (int col = 1; col < admin.cols - 1; col++) { + setEntryImage(labeledImage, row - 1, col - 1, + getEntryImage(admin, row, col) / 10); + } + } +} // retrieveLabeledImage + + +// func: labeling of all blobs in a binary image +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// return_value: the total number of objects. +int labelBLOBs(Mat binaryImage, Mat & labeledImage) { + + // admin contains the administration of the recursive process. + // meaning of the entry values: + // -1: a "1" which is not visited yet. Changes to 1 when visited. + // 0: always a "0" + // 1, 2, 3,... : a "1" which is visited and is labeled with the object number. + Mat admin = makeAdmin(binaryImage); + int row = 1; + int col = 1; + + // init volgnummer + int blobNr = 0; + + // label alle BLOBs met een volgnummer + while ((row > 0) & (row < (admin.rows - 1)) & + (col > 0) & (col < (admin.cols - 1))) + if (findNextBlob(admin, row, col)) labelIter(admin, row, col, ++blobNr); + + retrieveLabeledImage(admin, labeledImage); + + // laatste volgnummer is gelijk aan het aantal gevonden blobs + return blobNr; +} // labelBLOBs + +// func: removes a BLOB from the labeling administration +// pre: (posx,posy) is the position of the BLOB, blobNr the number +// of the blob to be removed. +void removeBLOB(Mat & admin, int blobNr) { + _int16 value; + for (int row = 1; row < admin.rows - 2; row++) + for (int col = 1; col < admin.cols - 2; col++) { + value = getEntryImage(admin, row, col); + while (value > 10) value /= 10; + if (value == blobNr) setEntryImage(admin, row, col, 0); + } +} // removeBLOB + +// func: labeling of all blobs in a binary image with a area in [threhAreaMin,threhAreaMax]. Default +// threshold is [1,INT_MAX]. Alle gathered data during the labeling proces is returned, +// i.e. the positions of the firstpixel of each blob, the position of the blobs (i.e. the +// centres of gravity) and the area's of all blobs. +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// areaVec: contains all area's of the blobs. The index corresponds to the number +// of the blobs. Index 0 has no meaning. +// return_value: the total number of objects. +int labelBLOBsInfo(Mat binaryImage, Mat & labeledImage, + vector & firstpixelVec, vector & posVec, + vector & areaVec, + int threshAreaMin, int threshAreaMax) { + + // admin contains the administration of the recursive process. + // meaning of the entry values: + // -1: a "1" which is not visited yet. + // 0: always a "0" + // 1, 2, 3,... : a "1" which is visited and is labeled with the object number. + Mat admin = makeAdmin(binaryImage); + int row = 1; + int col = 1; + + // init volgnummer + int blobNr = 0; + int area; + int xGravity, yGravity; + // label alle BLOBs met een volgnummer + while ((row > 0) & (row < (admin.rows - 1)) & + (col > 0) & (col < (admin.cols - 1))) + + if (findNextBlob(admin, row, col)) { + + area = labelIterInfo(admin, row, col, ++blobNr, xGravity, yGravity); + + if ((area >= threshAreaMin) & (area <= threshAreaMax)) { + firstpixelVec.push_back(new Point2d(row - 1, col - 1)); + posVec.push_back(new Point2d(xGravity - 1, yGravity - 1)); + areaVec.push_back(area); + } + else removeBLOB(admin, blobNr--); + } + + retrieveLabeledImage(admin, labeledImage); + + // laatste volgnummer is gelijk aan het aantal gevonden blobs + return blobNr; +} // labelBLOBsInfo + + +/*BEGIN********************************************** BACK PROPAGATION NEURAL NETWORK ****************************************************************/ + +// TRAININGSET: I0 because of bias V0 +// +// setnr I0 I1 I2 I3 I4 O1 O2 +// 1 1.0 0.4 -0.7 0.1 0.71 0.0 0.0 +// 2 1.0 0.3 -0.5 0.05 0.34 0.0 0.0 +// 3 1.0 0.6 0.1 0.3 0.12 0.0 1.0 +// 4 1.0 0.2 0.4 0.25 0.34 0.0 1.0 +// 5 1.0 -0.2 0.12 0.56 1.0 1.0 0.0 +// 6 1.0 0.1 -0.34 0.12 0.56 1.0 0.0 +// 7 1.0 -0.6 0.12 0.56 1.0 1.0 1.0 +// 8 1.0 0.56 -0.2 0.12 0.56 1.0 1.0 + +void loadTrainingSet1(Mat & ITset, Mat & OTset) { + + // input of trainingset + // remark: nummber of columns == number of inputneurons of the BPN + ITset = (Mat_(8, 5) << + 1, 0.4, -0.7, 0.1, 0.71, + 1, 0.3, -0.5, 0.05, 0.34, + 1, 0.6, 0.1, 0.3, 0.12, + 1, 0.2, 0.4, 0.25, 0.34, + 1, -0.2, 0.12, 0.56, 1.0, + 1, 0.1, -0.34, 0.12, 0.56, + 1, 0.6, 0.12, 0.56, 1.0, + 1, 0.56, -0.2, 0.12, 0.56); + + // output of trainingset + // remark: nummber of columns == number of outputneurons of the BPN + OTset = (Mat_(8, 2) << + 0, 0, + 0, 0, + 0, 1, + 0, 1, + 1, 0, + 1, 0, + 1, 1, + 1, 1); +} // loadTestTrainingSet1 + + +// TRAININGSET binary function O1 = (I1 OR I2) AND I3 +// without bias +// setnr I1 I2 I3 O1 +// 1 0 0 0 0 +// 2 0 0 1 0 +// 3 0 1 0 0 +// 4 0 1 1 1 +// 5 1 0 0 0 +// 6 1 0 1 1 +// 7 1 1 0 0 +// 8 1 1 1 1 +void loadBinaryTrainingSet1(Mat & ITset, Mat & OTset) { + + // input of trainingset (without bias) + // remark: nummber of columns == number of inputneurons of the BPN + ITset = (Mat_(8, 2) << + 0, 0, + 0, 0, + 0, 1, + 0, 1, + 1, 0, + 1, 0, + 1, 1, + 1, 1); + + // output of trainingset + // remark: nummber of columns == number of outputneurons of the BPN + OTset = (Mat_(8, 1) << + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0); + +} // loadBinaryTrainingSet1 + + +// func: Initialization of the (1) weigthmatrices V0 and W0 and (2) of the delta matrices dV0 and dW0. +// pre: inputNeurons, hiddenNeurons and outputNeurons define the Neural Network. +// From this numbers the dimensions of the weightmatrices can be determined. +// post: V0 and W0 have random values between 0.1 and 0.9 +void initializeBPN(int inputNeurons, int hiddenNeurons, int outputNeurons, + Mat & V0, Mat & dV0, Mat & W0, Mat & dW0) { + + // Instellen van alle weegfactoren met een random waarde + V0 = Mat_(inputNeurons, hiddenNeurons); + W0 = Mat_(hiddenNeurons, outputNeurons); + setRandomValue(V0, 0.1, 0.9); + setRandomValue(W0, 0.1, 0.9); + + // Initiele aanpassing van de weegfactoren W + dV0 = Mat_(inputNeurons, hiddenNeurons); + dW0 = Mat_(hiddenNeurons, outputNeurons); + setValue(dV0, 0); + setValue(dW0, 0); +} // initializeBPN + +// Test of a BPN with all values defined explicitly +void testBPN(Mat & IT, Mat & OT, Mat & V0, Mat & dV0, Mat & W0, Mat & dW0) { + + // input of trainingset + // remark: number of columns == number of inputneurons of the BPN + IT = (Mat_(5, 2) << + 0.4, -0.7, + 0.3, -0.5, + 0.6, 0.1, + 0.2, 0.4, + 0.1, -0.2); + + // output of trainingset + // remark: nummber of columns == number of outputneurons of the BPN + OT = (Mat_(5, 1) << + 0.1, + 0.05, + 0.3, + 0.25, + 0.12); + + // STEP2: Initializing the weights + V0 = (Mat_(2, 2) << + 0.1, 0.4, + -0.2, 0.2); + + W0 = (Mat_(2, 1) << + 0.2, + -0.5); + + // Initiele aanpassing van de weegfactoren W + dW0 = (Mat_(2, 1) << + 0.0, + 0.0); + + // Initiele aanpassing van de weegfactoren V + dV0 = (Mat_(2, 2) << + 0.0, 0.0, + 0.0, 0.0); + +} // testBPN + + + + +// func: Given an inputvector of the inputlayer and a weightmatrix V calculates the outputvector of the hiddenlayer +// pre: II is input of the inputlayer. V = matrix with weightfactors between inputlayer and the hiddenlayer. +// post: OH is the outputvector of the hidden layer +void calculateOutputHiddenLayer(Mat II, Mat V, Mat & OH) { + + // STEP1: Output inputlayer := Input inputlayer + Mat OI; + II.copyTo(OI); + + // STEP2: Initializing the weights, already done, see input of this function + + // STEP3: Calculate input of the hiddenlayer, i.e. IH = V0transposed * OI + Mat Vtr = transpose(V); + Mat IH = multiply(Vtr, OI); + + // STEP4: Calculate output of the hiddenlayer, i.e. OH(i) = 1/(1+EXP(-IH(i))) + int hiddenNeurons = V.cols; + OH = Mat_(hiddenNeurons, 1); + for (int row = 0; row < hiddenNeurons; row++) + setEntry(OH, row, 0, 1 / (1 + exp(-getEntry(IH, row, 0)))); + +} // calculateOutputHiddenLayer + +// func: Given the outputvector of the hiddenlayer and a weigthmatrix W calculates the outputvector of the outputlayer +// pre: OH is the outputvector of the hiddenlayer. W = matrix with weightfactors between hiddenlayer and the outputlayer. +// post: OO is the outputvector of the output layer +void calculateOutputBPN(Mat OH, Mat W, Mat & OO) { + + // STEP5: Calculate input of the outputlayer, i.e. IO = W0transposed * OH + Mat Wtr = transpose(W); + Mat IO = multiply(Wtr, OH); + + // STEP6: Calculate output of the outputlayer, i.e. OO(i) = 1/(1+EXP(-IO(i))) + int outputNeurons = W.cols; + OO = Mat_(outputNeurons, 1); + for (int row = 0; row < outputNeurons; row++) + setEntry(OO, row, 0, 1 / (1 + exp(-getEntry(IO, row, 0)))); + +} // calculateOutputBPN + + +// func: Calculates the total error Error = 1/2*Sigma(OTi-OOi)^2. +// OTi is the expected output according to the trainingvector i +// OOi is the calculated output from the current neural network of the traininngvector i +// pre: OO is the outputvector of the outputlayer. OT is the expected outputvector from the trainingset +// post: OO is the outputvector of the output layer +void calculateOutputBPNError(Mat OO, Mat OT, double & outputError) { + + // STEP7: Calculate the error, i.e. Error = 1/2*Sigma(TOi-OOi)^2 + double sumSqrErr = 0, diff = 0; + for (int row = 0; row < OT.rows; row++) { + diff = getEntry(OT, row, 0) - getEntry(OO, row, 0); + sumSqrErr += (diff * diff); + } + outputError = 0.5 * sumSqrErr; + +} // calculateOutputBPNError + + +void adaptVW(Mat OT, Mat OO, Mat OH, Mat OI, Mat W0, Mat dW0, Mat V0, Mat dV0, Mat & W, Mat & V, + double ALPHA, double ETHA) { + + + /*BEGIN*** AANPASSING VAN DE WEEGFACTOREN W ****/ + + // STEP8: + // E = 1/2 Sigma(OOi - di)^2 ==> dE/dOO = Sigma(OOi - di) + // dE/dIO = dE/dOO * dOO/dIO = Sigma((OOi - Ti) * OOi * (1 - OOi)) + // Here: d = dE/dIO = (T-OO) * OO * (1 - OO) + Mat OOerror = Mat_(OT.rows, 1); + OOerror = OT - OO; + + Mat d = Mat_(OT.rows, 1); + double di; + for (int row = 0; row < OT.rows; row++) { + di = (getEntry(OT, row, 0) - getEntry(OO, row, 0)) * getEntry(OO, row, 0) * (1 - getEntry(OO, row, 0)); + setEntry(d, row, 0, di); + } + + // Y = OH * d + Mat dtr = transpose(d); + Mat Y = Mat_(OH.rows, OT.rows); + Y = multiply(OH, dtr); // OH = mx1 ; d = nx1 ; dtr = 1xn + + // STEP9: dW1 = alpha * dW0 + etha * Y // assume etha = 0.6 + Mat dW = Mat_(OH.rows, OT.rows); + dW = ALPHA * dW0 + ETHA * Y; + + /*END*** AANPASSING VAN DE WEEGFACTOREN W ****/ + + /*BEGIN*** AANPASSING VAN DE WEEGFACTOREN V ****/ + + // STEP10: OHerror = W0 * d + Mat OHerror = Mat_(OH.rows, 1); + OHerror = W0 * d; + + // STEP11: + // d = dE/dIO = OOerror * OO * (1 - OO) // OOError = TO - OO + // d*= dE/dIH = OHerror * OH * (1 - OH) // OHerror = W0 * d + Mat dstar = Mat_(OH.rows, 1); + double dstari; + for (int row = 0; row < OH.rows; row++) { + dstari = getEntry(OHerror, row, 0) * getEntry(OH, row, 0) * (1 - getEntry(OH, row, 0)); + setEntry(dstar, row, 0, dstari); + } + + // STEP12: + // X = OI * dstar + Mat dstartr = transpose(dstar); + Mat X = Mat_(OI.rows, OH.rows); + X = OI * dstartr; + + // STEP13: dV1 = ALPHA * dV0 + ETHA * X // assume etha = 0.6 + Mat dV; + dV = ALPHA * dV0 + ETHA * X; + /*END*** AANPASSING VAN DE WEEGFACTOREN V ****/ + + /* Update van de matrices met gewichtsfactoren */ + + // STEP14: + V = Mat_(V0.rows, V0.cols); + W = Mat_(W0.rows, W0.cols); + V = V0 + dV; + W = W0 + dW; + +}; // adaptVW + + +Mat BPN(Mat II, Mat V, Mat W) { + Mat OH, OO; + calculateOutputHiddenLayer(II, V, OH); + calculateOutputBPN(OH, W, OO); + return OO; +} // BPN + +/*END********************************************** BACK PROPAGATION NEURAL NETWORK ****************************************************************/ diff --git a/NeuralDetector/avansvisionlib20.h b/NeuralDetector/avansvisionlib20.h new file mode 100644 index 0000000..de23e5d --- /dev/null +++ b/NeuralDetector/avansvisionlib20.h @@ -0,0 +1,335 @@ +// avansvisionlib - Growing Visionlibrary of Avans based on OpenCV 2.4.10 +// Goal: deep understanding of vision algorithms by means of developing own (new) algorithms. +// deep understanding of neural networks +// +// Copyright Jan Oostindie, version 2.0 dd 5-12-2016 (= Neural Network (BPN) added to version 1.0 dd 5-11-2016.) +// Contains basic functions to perform calculations on matrices/images of class Mat. Including BLOB labeling functions +// Contains a BPN neural network. +// Note: Students of Avans are free to use this library in projects and for own vision competence development. Others may ask permission to use it by means +// of sending an email to Jan Oostindie, i.e. jac.oostindie@avans.nl +#pragma once +#include +#include +#include +#include +#include + +using namespace cv; +using namespace std; + +// remark: a function call with a Mat-object parameter is a call by reference + +/*********************** PROTOTYPES of the function library ************************/ + +// func: setup a specified entry (i,j) of a matrix m with a specific value +// pre: (i < m.rows) & (j < m.cols) +void setEntry(Mat m, int i, int j, double value); + +// func: get the value of a specified entry (i,j) of a matrix m +// pre: (i < m.rows) & (j < m.cols) +// return: == m(i,j) +double getEntry(Mat m, int i, int j); + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) & (row.rows == 1) & (col.cols == 1) +double inproduct(Mat row, Mat col); + +// func: prints matrix m in the console +// pre: true +void printMatrix(Mat m); + +// func: select and get a row of a matrix m. rowNr contains the row number +// pre: 0 < rowNr < m.rows +// return: contains the selected row +Mat getRow(Mat m, int rowNr); + +// func: get a column of a matrix m. colNr contains the column number +// pre: 0 < colNr < m.cols +// return: contains the selected column +Mat getCol(Mat m, int colNr); + +// func: multiply two matrices a and b +// pre: (a.cols == b.rows) +// return: .rows == b.rows & .cols == b.cols +Mat multiply(Mat a, Mat b); + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +// return: (i,j) == a(i,j) + b(i,j) for all (0,0) <= (i,j) < (a.rows,a.cols) +Mat add(Mat a, Mat b); + +// func: transposes a matrix +// return: (i,j) = m(j,i) & .rows = m.cols & .cols = m.rows +Mat transpose(Mat m); + +// func: sets all entries of a matrix to a certain value +// pre: true +void setValue(Mat m, double value); + +// func: generates a randomvalue between min and max +// pre: true +double generateRandomValue(double min, double max); + + +// func: sets all entries of a matrix to a random value +// pre: true +void setRandomValue(Mat m, double min, double max); + + + +/*********************************** Image operaties ****************************************/ +// NB images are supposed to have 1 channel (B/W image) and depth 16 bits signed (CV_16S) +/********************************************************************************************/ + +// func: setup a specified entry (i,j) of a matrix m with a specific value +// pre: (i < m.rows) & (j < m.cols) +void setEntryImage(Mat m, int i, int j, _int16 value); + +// func: get the value of a specified entry (i,j) of a matrix m +// pre: (i < m.rows) & (j < m.cols) +// return: == m(i,j) +_int16 getEntryImage(Mat m, int i, int j); + +// func: calculate product of a row and column of equal length +// pre: (row.cols == col.rows) & (row.rows == 1) & (col.cols == 1) +_int16 inproductImage(Mat row, Mat col); + +// func: select and get a row of a matrix m. rowNr contains the row number +// pre: 0 < rowNr < m.rows +// return: contains the selected row +Mat getRowImage(Mat m, int rowNr); + +// func: get a column of a matrix m. colNr contains the column number +// pre: 0 < colNr < m.cols +// return: contains the selected column +Mat getColImage(Mat m, int colNr); + +// func: multiply two matrices a and b +// pre: (a.cols == b.rows) +// return: .rows == b.rows & .cols == b.cols +Mat multiplyImage(Mat a, Mat b); + +// pre: matrices have equal dimensions i.e. (a.cols == b.cols) & (a.rows == b.rows) +// return: (i,j) == a(i,j) + b(i,j) for all (0,0) <= (i,j) < (a.rows,a.cols) +Mat addImage(Mat a, Mat b); + + +// func: searches the maximum pixel value in the image +// return: maximum pixel value +_int16 maxPixelImage(Mat m); + +// func: searches the minimum pixel value in the image +// return: minimum pixel value +_int16 minPixelImage(Mat m); + +// func: determines the range of the image, i.e. the minimum +// and maximum pixel value in the image +// post: range = minPixelValue, maxPixelValue +void getPixelRangeImage(Mat m, _int16 &minPixelValue, _int16 &maxPixelValue); + +// func: transform scale the image +// return: maximum pixel value +void stretchImage(Mat m, _int16 minPixelValue, _int16 maxPixelValue); + +// func: shows a 16S image on the screen. All values mapped on the interval 0-255 +/// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageStretch(Mat m, string windowTitle = "show16SImageStretch"); + + +// func: shows a 16S image on the screen. All values clipped to the interval 0-255 +// i.e. value < 0 => 0; 0 <= value <= 255 => value ; value > 255 => 255 +/// pre: m is a 16S image (depth 16 bits, signed) +void show16SImageClip(Mat m, string windowTitle = "show16SImageClip"); + + + +// func: histogram gamma correction +// pre: image has depth 8 bits unsigned and 1 or 3 channels +// post: entry(i,j) = 255*power(entry@pre(i,j)/255)^gamma +void gammaCorrection(Mat image, float gamma); + + +// func: makes a administration used for labeling blobs. +// the function adds a edge of 1 pixel wide tot a binary image, all with value 0. +// All 1's are made -1. The result is returned. +// This function is used by function labelBLOBs +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// return_matrix: All "1" are made "-1" meaning value 1 and unvisited. +Mat makeAdmin(Mat binaryImage); + + +// func: Searches the next blob after position (row,col) +// post: if return_value == 1 then (row,col) contains the position +// where the next blob starts. +// return_value: true => blob found ; starting position is (row,col) +// false => no blob found ; (row, col) == (-1, -1) +bool findNextBlob(Mat admin, int & row, int & col); + + +// func: searches the first 1 when rotating around the pixel (currX,currY), +// starting at position 0. Definition of relative positions: +// 7 0 1 +// 6 X 2 +// 5 4 3 +void findNext1(Mat admin, int & currX, int & currY, int & next1); + +// func: gets the entry of a neighbour pixel with relative position nr. +// Definition of relative positions nr: +// 7 0 1 +// 6 X 2 +// 5 4 3 +_int16 getEntryNeighbour(const Mat & admin, int x, int y, int nr); + + +// func: determines if there are more than 1 adjacent 1's +bool moreNext1(const Mat & admin, int x, int y); + + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// This function is used by function labelBLOB's which labels all blobs. +// return_value: area of the blob +// Evaluation: This function uses a iterative algorithm in which a special labeling technique is +// is used which gives the opportunity to trace all individiual pixels. This makes it +// possible for example to save only these pixels on disk or to translate the object in +// in the image. +// The disadvantagae however is that the algorithm is more complicated an maybe a little bit +// slower than the recursive variant. +int labelIter(Mat & admin, int row, int col, int blobNr); + + +// func: labels all pixels of one blob which starts at position (row,col) with blobNr. +// return_value: area of the blob +// Evaluation: This function uses a recursive algorithm which has the advantage that it is easy and trasparent. +// The disadvantagae however is that it claims a lot of spacee on the stack. I.e. every found +// pixel results in a function call which in case of large blobs causes a stack overflow. +int labelRecursive(Mat & admin, int row, int col, int blobNr); + +// func: retrieves a labeledImage from the labeling administration +// pre : admin is contains labeled pixels with neighbour number information. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +void retrieveLabeledImage(const Mat & admin, Mat & labeledImage); + +// func: labeling of all blobs in a binary image +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// return_value: the total number of objects. +int labelBLOBs(Mat binaryImage, Mat & labeledImage); + + +// func: labeling of all blobs in a binary image with a area in [threshAreaMin,threshAreaMax]. Default +// threshold is [1,INT_MAX]. Alle gathered data during the labeling proces is returned, +// i.e. the positions of the firstpixel of each blob, the position of the blobs (i.e. the +// centres of gravity) and the area's of all blobs. +// pre : binaryImage has depth 16 bits signed int. Contains only values 0 and 1. +// post: labeledImage: binary 8-connected pixels with value 1 in binaryImage are +// labeled with the number of the object they belong to. +// areaVec: contains all area's of the blobs. The index corresponds to the number +// of the blobs. Index 0 has no meaning. +// return_value: the total number of objects. +int labelBLOBsInfo(Mat binaryImage, Mat & labeledImage, + vector & firstpixelVec, vector & posVec, + vector & areaVec, + int threshAreaMin = 1, int threshAreaMax = INT_MAX); + + +/*****************************************************************************************************************************************************/ +/*BEGIN********************************************** BACK PROPAGATION NEURAL NETWORK ****************************************************************/ +/*****************************************************************************************************************************************************/ + +// func: loads an example of a training set +// pre: true +// post: ITset input training set. Each row contains a number of features. +// OTset output training set. Each row contains the expected output belonging to the corresponding row of features in the input training set. +// +// TRAININGSET: I0 because of bias V0 +// +// setnr I0 I1 I2 I3 I4 O1 O2 +// 1 1.0 0.4 -0.7 0.1 0.71 0.0 0.0 +// 2 1.0 0.3 -0.5 0.05 0.34 0.0 0.0 +// 3 1.0 0.6 0.1 0.3 0.12 0.0 1.0 +// 4 1.0 0.2 0.4 0.25 0.34 0.0 1.0 +// 5 1.0 -0.2 0.12 0.56 1.0 1.0 0.0 +// 6 1.0 0.1 -0.34 0.12 0.56 1.0 0.0 +// 7 1.0 -0.6 0.12 0.56 1.0 1.0 1.0 +// 8 1.0 0.56 -0.2 0.12 0.56 1.0 1.0 +void loadTrainingSet1(Mat & ITset, Mat & OTset); + + +// func: loads an example of a training set in which only binary numbers are used. +// pre: true +// post: ITset input training set. Each row contains a number of binary numbers. +// OTset output training set. Each row contains the expected output belonging to the corresponding row of binary numbers in the input training set. +// +// TRAININGSET binary function O1 = (I1 OR I2) AND I3 +// without bias +// setnr I1 I2 I3 O1 +// 1 0 0 0 0 +// 2 0 0 1 0 +// 3 0 1 0 0 +// 4 0 1 1 1 +// 5 1 0 0 0 +// 6 1 0 1 1 +// 7 1 1 0 0 +// 8 1 1 1 1 +void loadBinaryTrainingSet1(Mat & ITset, Mat & OTset); + + +// func: Initialization of the (1) weigthmatrices V0 and W0 and (2) of the delta matrices dV0 and dW0. +// pre: inputNeurons, hiddenNeurons and outputNeurons define the Neural Network. +// (from these numbers the dimensions of the weightmatrices can be determined) +// post: V0 and W0 have random values between 0.1 and 0.9 +void initializeBPN(int inputNeurons, int hiddenNeurons, int outputNeurons, + Mat & V0, Mat & dV0, Mat & W0, Mat & dW0); + + +// Test of a BPN with all values defined explicitly. +// pre: true +// post: IT is the input training set ; OT is the corresponding output training set. ; V0, W0 are the weight matrices of a BPN with 1 hidden layer; +// dV0, dW0 are the initial delta matrices of the weight factor matrices. +void testBPN(Mat & IT, Mat & OT, Mat & V0, Mat & dV0, Mat & W0, Mat & dW0); + +// func: Given an inputvector of the inputlayer and a weightmatrix V calculates the outputvector of the hiddenlayer +// pre: II is input of the inputlayer. V = matrix with weightfactors between inputlayer and the hiddenlayer. +// post: OH is the outputvector of the hidden layer +void calculateOutputHiddenLayer(Mat II, Mat V, Mat & OH); + + +// func: Given the outputvector of the hiddenlayer and a weigthmatrix W calculates the outputvector of the outputlayer +// pre: OH is the outputvector of the hiddenlayer. W = matrix with weightfactors between hiddenlayer and the outputlayer. +// post: OO is the outputvector of the output layer +void calculateOutputBPN(Mat OH, Mat W, Mat & OO); + + +// func: Calculates the total error Error = 1/2*Sigma(OTi-OOi)^2. +// OTi is the expected output according to the trainingvector i +// OOi is the calculated output from the current neural network of the traininngvector i +// pre: OO is the outputvector of the outputlayer. OT is the expected outputvector from the trainingset +// post: OO is the outputvector of the output layer +void calculateOutputBPNError(Mat OO, Mat OT, double & outputError); + + +// func: calculates the updates of the weight factor matrices V0 and W0 on basics of the calculated output matrix and the expected output matrix. +// A back propagation algorithm is used. +// pre: OT is the expected outputvector from the trainingset ; OO is the calculated outputvector of the outputlayer ; +// OH is the calculated output of the hiddenlayer ; OI is the output of the inputlayer (normaly equal to the input of the inputlayer) +// V0 is the weight matrix between the input layer and the hidden layer ; W0 is the weight matrix between the hiddenlayer and the output layer. +// dV0, dW0 are the correction matrices. +// post: V is the adapted weight matrix between the inputlayer and the hidden layer ; W is the weight matrix between the hiddenlayer and the output layer. +void adaptVW(Mat OT, Mat OO, Mat OH, Mat OI, Mat W0, Mat dW0, Mat V0, Mat dV0, Mat & W, Mat & V, + double ALPHA = 1.0, double ETHA = 0.6); + + +// func: given an inputvector calculates the output of a BPN with weigth matrices V and W. +// pre: II is the input vector of the BPN ; +// V is the weight factor matrix between the input layer and the hidden layer +// W is the weight factor matrix between the hidden layer and the output layer +// return: output vector +Mat BPN(Mat II, Mat V, Mat W); + + +/*****************************************************************************************************************************************************/ +/*END********************************************** BACK PROPAGATION NEURAL NETWORK ******************************************************************/ +/*****************************************************************************************************************************************************/ + diff --git a/NeuralDetector/calibration.yml b/NeuralDetector/calibration.yml new file mode 100644 index 0000000..905b231 --- /dev/null +++ b/NeuralDetector/calibration.yml @@ -0,0 +1,15 @@ +%YAML:1.0 +--- +intrinsic: !!opencv-matrix + rows: 3 + cols: 3 + dt: d + data: [ 7.7102786562030786e+04, 0., 3.2013752810898518e+02, 0., + 1.1313075108780187e+05, 2.4041984682542122e+02, 0., 0., 1. ] +distCoeffs: !!opencv-matrix + rows: 1 + cols: 5 + dt: d + data: [ -1.6033489811253014e+02, -3.6422783919263818e-02, + -2.9072693275266626e-02, -3.5312598551078556e-01, + -6.9187392701624002e-07 ] diff --git a/NeuralDetector/classes.yml b/NeuralDetector/classes.yml new file mode 100644 index 0000000..482918c --- /dev/null +++ b/NeuralDetector/classes.yml @@ -0,0 +1,4 @@ +%YAML:1.0 +--- +classes: { e0:weerstand, e1:irtrans, e2:switch, e3:reflsens, e4:irsens, + e5:reedsens, e6:card, e7:led, e8:button, e9:rgbled } diff --git a/NeuralDetector/factors.yml b/NeuralDetector/factors.yml new file mode 100644 index 0000000..cbe62c7 --- /dev/null +++ b/NeuralDetector/factors.yml @@ -0,0 +1,70 @@ +%YAML:1.0 +--- +W0: !!opencv-matrix + rows: 8 + cols: 10 + dt: d + data: [ -4.8813774957793505e+00, -1.4851964864258784e+01, + -4.5483958882918500e+00, 2.3423976029083846e+01, + -2.7036296416086123e+00, -5.9289881679629190e+01, + -3.6879635531940997e+00, -3.3153545804030564e+01, + -1.4020142561256883e+00, -7.0336731756450614e+00, + 8.8357037082684666e+00, 1.2314510070259121e+01, + -3.4472596296194356e+00, -1.1923745474347557e+01, + -4.4282540281508034e+00, 2.4457028473557347e+01, + 3.6136991577659492e+00, -2.5827572663987759e+01, + -1.3892967734397374e+01, -8.4284128215643772e-01, + -1.5656959650996116e+01, -4.7792720274921949e+00, + 2.2975802354552862e+01, -6.2055876498801723e+00, + -5.7482437173820735e+01, -4.6866402386216075e+00, + -3.0466706366866589e+01, -7.0842282146302944e+00, + -6.2597171792574171e+00, -7.2087129758066659e+00, + -1.5425205894698555e+01, 4.3120273767387673e+01, + -5.5453766803160338e+00, -3.9096843912958307e-01, + -1.0403409583426930e+01, 2.5070656273447195e+01, + -1.2109893602230631e+01, 2.9945425250036301e+01, + -5.6642091074608834e+00, -3.0840158943557448e+01, + 2.5513648309284322e+00, -1.7087631494600185e+01, + -1.4015650118577094e+01, -3.3031333903438806e+01, + -1.7294407183796434e+00, -3.2643739919895147e+01, + -1.9333188145064401e+01, -6.3934782960318515e+00, + -1.8871662520667233e+01, -1.5080559598577183e+01, + 5.2874934032701137e-01, 2.5826625216358101e+00, + 8.3597510472828951e+00, -2.0854574479392202e-01, + -1.0790385094292049e+01, -4.8203290529982112e+00, + 2.3059664039490269e+01, -1.5713643646359962e+01, + -2.1086899521790972e+01, -6.1737512017926734e+00, + -1.6040305572556772e+01, -3.1420416546297179e+01, + -9.6651877009273299e+00, -9.3255536054811716e-01, + -8.7417385800329424e+00, 1.4584107173942127e+00, + -1.9611038941263057e+01, -6.9351624096848574e-01, + -3.8496653692305358e+01, 3.1842200474091559e+01, + -1.2903254663541592e+01, -1.4547573929553105e+01, + -9.2829295697875889e+00, -1.0087144923614213e+01, + 2.0960410041424829e+01, -2.1442616606862913e+01, + 2.0254590030822840e+01, -2.9413976475212888e+00, + 3.4350620310034941e+01, -2.0392084844460520e+01 ] +V0: !!opencv-matrix + rows: 5 + cols: 8 + dt: d + data: [ -6.5636286541558171e+00, 4.5330404221912382e+01, + -1.1149842067895429e+01, 7.5086888359720900e+00, + 2.8132961939742511e+00, -3.2716268982804380e+01, + 2.4073267678846292e+01, -1.5426805055872450e+01, + -2.3447511567066414e+01, -7.1071961568313483e+01, + 2.4376431377296260e+01, -5.2835959692878383e+01, + 1.5962714728971601e+01, 3.5537070580189244e+01, + -2.9387489075397973e+01, 2.7081013867840458e+01, + 4.3302753434844213e+01, -1.0978817742962482e+02, + -4.2383027486121954e+01, 6.8440729304108856e+01, + -9.6243156066355802e+00, 2.9979769994501602e+01, + -3.7724179920359870e+00, 9.9776059105303023e+00, + 5.0426955715121640e+00, -5.7015329865766313e+00, + 7.6021476153135108e+00, 1.4119669046625256e+00, + -1.3832537537011591e+01, -7.8448492545467206e+00, + -1.8009846302065957e+00, 4.3426637435861783e+00, + 1.6086554490069808e+01, 4.4710323658171866e+01, + -8.9095095711932455e+00, -4.1369158011178691e+00, + -9.9794096446219829e+00, 2.2801143768856548e+01, + -4.2606068131615935e+01, -1.7282938175700217e+01 ] diff --git a/NeuralDetector/training/button_0.bmp b/NeuralDetector/training/button_0.bmp new file mode 100644 index 0000000..ee2ce93 Binary files /dev/null and b/NeuralDetector/training/button_0.bmp differ diff --git a/NeuralDetector/training/button_1.bmp b/NeuralDetector/training/button_1.bmp new file mode 100644 index 0000000..14b2a4b Binary files /dev/null and b/NeuralDetector/training/button_1.bmp differ diff --git a/NeuralDetector/training/button_10.bmp b/NeuralDetector/training/button_10.bmp new file mode 100644 index 0000000..be10900 Binary files /dev/null and b/NeuralDetector/training/button_10.bmp differ diff --git a/NeuralDetector/training/button_11.bmp b/NeuralDetector/training/button_11.bmp new file mode 100644 index 0000000..ef1ac3f Binary files /dev/null and b/NeuralDetector/training/button_11.bmp differ diff --git a/NeuralDetector/training/button_12.bmp b/NeuralDetector/training/button_12.bmp new file mode 100644 index 0000000..3b5a59c Binary files /dev/null and b/NeuralDetector/training/button_12.bmp differ diff --git a/NeuralDetector/training/button_13.bmp b/NeuralDetector/training/button_13.bmp new file mode 100644 index 0000000..00b6d1e Binary files /dev/null and b/NeuralDetector/training/button_13.bmp differ diff --git a/NeuralDetector/training/button_14.bmp b/NeuralDetector/training/button_14.bmp new file mode 100644 index 0000000..3239726 Binary files /dev/null and b/NeuralDetector/training/button_14.bmp differ diff --git a/NeuralDetector/training/button_15.bmp b/NeuralDetector/training/button_15.bmp new file mode 100644 index 0000000..96c2070 Binary files /dev/null and b/NeuralDetector/training/button_15.bmp differ diff --git a/NeuralDetector/training/button_2.bmp b/NeuralDetector/training/button_2.bmp new file mode 100644 index 0000000..9e624cc Binary files /dev/null and b/NeuralDetector/training/button_2.bmp differ diff --git a/NeuralDetector/training/button_3.bmp b/NeuralDetector/training/button_3.bmp new file mode 100644 index 0000000..528052e Binary files /dev/null and b/NeuralDetector/training/button_3.bmp differ diff --git a/NeuralDetector/training/button_4.bmp b/NeuralDetector/training/button_4.bmp new file mode 100644 index 0000000..50f4272 Binary files /dev/null and b/NeuralDetector/training/button_4.bmp differ diff --git a/NeuralDetector/training/button_5.bmp b/NeuralDetector/training/button_5.bmp new file mode 100644 index 0000000..6869cff Binary files /dev/null and b/NeuralDetector/training/button_5.bmp differ diff --git a/NeuralDetector/training/button_6.bmp b/NeuralDetector/training/button_6.bmp new file mode 100644 index 0000000..8d16f64 Binary files /dev/null and b/NeuralDetector/training/button_6.bmp differ diff --git a/NeuralDetector/training/button_7.bmp b/NeuralDetector/training/button_7.bmp new file mode 100644 index 0000000..0934503 Binary files /dev/null and b/NeuralDetector/training/button_7.bmp differ diff --git a/NeuralDetector/training/button_8.bmp b/NeuralDetector/training/button_8.bmp new file mode 100644 index 0000000..fc43ec5 Binary files /dev/null and b/NeuralDetector/training/button_8.bmp differ diff --git a/NeuralDetector/training/button_9.bmp b/NeuralDetector/training/button_9.bmp new file mode 100644 index 0000000..54b8923 Binary files /dev/null and b/NeuralDetector/training/button_9.bmp differ diff --git a/NeuralDetector/training/card_0.bmp b/NeuralDetector/training/card_0.bmp new file mode 100644 index 0000000..2a68e25 Binary files /dev/null and b/NeuralDetector/training/card_0.bmp differ diff --git a/NeuralDetector/training/card_1.bmp b/NeuralDetector/training/card_1.bmp new file mode 100644 index 0000000..89b9b28 Binary files /dev/null and b/NeuralDetector/training/card_1.bmp differ diff --git a/NeuralDetector/training/card_10.bmp b/NeuralDetector/training/card_10.bmp new file mode 100644 index 0000000..2e0bf96 Binary files /dev/null and b/NeuralDetector/training/card_10.bmp differ diff --git a/NeuralDetector/training/card_11.bmp b/NeuralDetector/training/card_11.bmp new file mode 100644 index 0000000..a540b2c Binary files /dev/null and b/NeuralDetector/training/card_11.bmp differ diff --git a/NeuralDetector/training/card_12.bmp b/NeuralDetector/training/card_12.bmp new file mode 100644 index 0000000..ec6bc24 Binary files /dev/null and b/NeuralDetector/training/card_12.bmp differ diff --git a/NeuralDetector/training/card_13.bmp b/NeuralDetector/training/card_13.bmp new file mode 100644 index 0000000..324f7dd Binary files /dev/null and b/NeuralDetector/training/card_13.bmp differ diff --git a/NeuralDetector/training/card_14.bmp b/NeuralDetector/training/card_14.bmp new file mode 100644 index 0000000..efd5894 Binary files /dev/null and b/NeuralDetector/training/card_14.bmp differ diff --git a/NeuralDetector/training/card_15.bmp b/NeuralDetector/training/card_15.bmp new file mode 100644 index 0000000..dec369e Binary files /dev/null and b/NeuralDetector/training/card_15.bmp differ diff --git a/NeuralDetector/training/card_2.bmp b/NeuralDetector/training/card_2.bmp new file mode 100644 index 0000000..f978809 Binary files /dev/null and b/NeuralDetector/training/card_2.bmp differ diff --git a/NeuralDetector/training/card_3.bmp b/NeuralDetector/training/card_3.bmp new file mode 100644 index 0000000..c6ec152 Binary files /dev/null and b/NeuralDetector/training/card_3.bmp differ diff --git a/NeuralDetector/training/card_4.bmp b/NeuralDetector/training/card_4.bmp new file mode 100644 index 0000000..f772a72 Binary files /dev/null and b/NeuralDetector/training/card_4.bmp differ diff --git a/NeuralDetector/training/card_5.bmp b/NeuralDetector/training/card_5.bmp new file mode 100644 index 0000000..c1877ef Binary files /dev/null and b/NeuralDetector/training/card_5.bmp differ diff --git a/NeuralDetector/training/card_6.bmp b/NeuralDetector/training/card_6.bmp new file mode 100644 index 0000000..c2bb394 Binary files /dev/null and b/NeuralDetector/training/card_6.bmp differ diff --git a/NeuralDetector/training/card_7.bmp b/NeuralDetector/training/card_7.bmp new file mode 100644 index 0000000..ace0647 Binary files /dev/null and b/NeuralDetector/training/card_7.bmp differ diff --git a/NeuralDetector/training/card_8.bmp b/NeuralDetector/training/card_8.bmp new file mode 100644 index 0000000..a808129 Binary files /dev/null and b/NeuralDetector/training/card_8.bmp differ diff --git a/NeuralDetector/training/card_9.bmp b/NeuralDetector/training/card_9.bmp new file mode 100644 index 0000000..d677545 Binary files /dev/null and b/NeuralDetector/training/card_9.bmp differ diff --git a/NeuralDetector/training/irsens_0.bmp b/NeuralDetector/training/irsens_0.bmp new file mode 100644 index 0000000..ba8ae08 Binary files /dev/null and b/NeuralDetector/training/irsens_0.bmp differ diff --git a/NeuralDetector/training/irsens_1.bmp b/NeuralDetector/training/irsens_1.bmp new file mode 100644 index 0000000..79bad66 Binary files /dev/null and b/NeuralDetector/training/irsens_1.bmp differ diff --git a/NeuralDetector/training/irsens_10.bmp b/NeuralDetector/training/irsens_10.bmp new file mode 100644 index 0000000..989fd8f Binary files /dev/null and b/NeuralDetector/training/irsens_10.bmp differ diff --git a/NeuralDetector/training/irsens_11.bmp b/NeuralDetector/training/irsens_11.bmp new file mode 100644 index 0000000..50ed0f0 Binary files /dev/null and b/NeuralDetector/training/irsens_11.bmp differ diff --git a/NeuralDetector/training/irsens_12.bmp b/NeuralDetector/training/irsens_12.bmp new file mode 100644 index 0000000..55612a3 Binary files /dev/null and b/NeuralDetector/training/irsens_12.bmp differ diff --git a/NeuralDetector/training/irsens_13.bmp b/NeuralDetector/training/irsens_13.bmp new file mode 100644 index 0000000..6993822 Binary files /dev/null and b/NeuralDetector/training/irsens_13.bmp differ diff --git a/NeuralDetector/training/irsens_14.bmp b/NeuralDetector/training/irsens_14.bmp new file mode 100644 index 0000000..7966d2c Binary files /dev/null and b/NeuralDetector/training/irsens_14.bmp differ diff --git a/NeuralDetector/training/irsens_15.bmp b/NeuralDetector/training/irsens_15.bmp new file mode 100644 index 0000000..dca0205 Binary files /dev/null and b/NeuralDetector/training/irsens_15.bmp differ diff --git a/NeuralDetector/training/irsens_2.bmp b/NeuralDetector/training/irsens_2.bmp new file mode 100644 index 0000000..ec176d7 Binary files /dev/null and b/NeuralDetector/training/irsens_2.bmp differ diff --git a/NeuralDetector/training/irsens_3.bmp b/NeuralDetector/training/irsens_3.bmp new file mode 100644 index 0000000..1fabc0f Binary files /dev/null and b/NeuralDetector/training/irsens_3.bmp differ diff --git a/NeuralDetector/training/irsens_4.bmp b/NeuralDetector/training/irsens_4.bmp new file mode 100644 index 0000000..7128a64 Binary files /dev/null and b/NeuralDetector/training/irsens_4.bmp differ diff --git a/NeuralDetector/training/irsens_5.bmp b/NeuralDetector/training/irsens_5.bmp new file mode 100644 index 0000000..70b3e83 Binary files /dev/null and b/NeuralDetector/training/irsens_5.bmp differ diff --git a/NeuralDetector/training/irsens_6.bmp b/NeuralDetector/training/irsens_6.bmp new file mode 100644 index 0000000..746a404 Binary files /dev/null and b/NeuralDetector/training/irsens_6.bmp differ diff --git a/NeuralDetector/training/irsens_7.bmp b/NeuralDetector/training/irsens_7.bmp new file mode 100644 index 0000000..dfd241c Binary files /dev/null and b/NeuralDetector/training/irsens_7.bmp differ diff --git a/NeuralDetector/training/irsens_8.bmp b/NeuralDetector/training/irsens_8.bmp new file mode 100644 index 0000000..4fa8a23 Binary files /dev/null and b/NeuralDetector/training/irsens_8.bmp differ diff --git a/NeuralDetector/training/irsens_9.bmp b/NeuralDetector/training/irsens_9.bmp new file mode 100644 index 0000000..0bd2fb6 Binary files /dev/null and b/NeuralDetector/training/irsens_9.bmp differ diff --git a/NeuralDetector/training/irtrans_0.bmp b/NeuralDetector/training/irtrans_0.bmp new file mode 100644 index 0000000..0575919 Binary files /dev/null and b/NeuralDetector/training/irtrans_0.bmp differ diff --git a/NeuralDetector/training/irtrans_1.bmp b/NeuralDetector/training/irtrans_1.bmp new file mode 100644 index 0000000..ed3d794 Binary files /dev/null and b/NeuralDetector/training/irtrans_1.bmp differ diff --git a/NeuralDetector/training/irtrans_10.bmp b/NeuralDetector/training/irtrans_10.bmp new file mode 100644 index 0000000..d4a1e75 Binary files /dev/null and b/NeuralDetector/training/irtrans_10.bmp differ diff --git a/NeuralDetector/training/irtrans_11.bmp b/NeuralDetector/training/irtrans_11.bmp new file mode 100644 index 0000000..611bb17 Binary files /dev/null and b/NeuralDetector/training/irtrans_11.bmp differ diff --git a/NeuralDetector/training/irtrans_12.bmp b/NeuralDetector/training/irtrans_12.bmp new file mode 100644 index 0000000..bdee08d Binary files /dev/null and b/NeuralDetector/training/irtrans_12.bmp differ diff --git a/NeuralDetector/training/irtrans_13.bmp b/NeuralDetector/training/irtrans_13.bmp new file mode 100644 index 0000000..1168451 Binary files /dev/null and b/NeuralDetector/training/irtrans_13.bmp differ diff --git a/NeuralDetector/training/irtrans_14.bmp b/NeuralDetector/training/irtrans_14.bmp new file mode 100644 index 0000000..1860ec2 Binary files /dev/null and b/NeuralDetector/training/irtrans_14.bmp differ diff --git a/NeuralDetector/training/irtrans_15.bmp b/NeuralDetector/training/irtrans_15.bmp new file mode 100644 index 0000000..d94a488 Binary files /dev/null and b/NeuralDetector/training/irtrans_15.bmp differ diff --git a/NeuralDetector/training/irtrans_2.bmp b/NeuralDetector/training/irtrans_2.bmp new file mode 100644 index 0000000..435a242 Binary files /dev/null and b/NeuralDetector/training/irtrans_2.bmp differ diff --git a/NeuralDetector/training/irtrans_3.bmp b/NeuralDetector/training/irtrans_3.bmp new file mode 100644 index 0000000..1349acf Binary files /dev/null and b/NeuralDetector/training/irtrans_3.bmp differ diff --git a/NeuralDetector/training/irtrans_4.bmp b/NeuralDetector/training/irtrans_4.bmp new file mode 100644 index 0000000..5ab99aa Binary files /dev/null and b/NeuralDetector/training/irtrans_4.bmp differ diff --git a/NeuralDetector/training/irtrans_5.bmp b/NeuralDetector/training/irtrans_5.bmp new file mode 100644 index 0000000..229dc7a Binary files /dev/null and b/NeuralDetector/training/irtrans_5.bmp differ diff --git a/NeuralDetector/training/irtrans_6.bmp b/NeuralDetector/training/irtrans_6.bmp new file mode 100644 index 0000000..68b34c6 Binary files /dev/null and b/NeuralDetector/training/irtrans_6.bmp differ diff --git a/NeuralDetector/training/irtrans_7.bmp b/NeuralDetector/training/irtrans_7.bmp new file mode 100644 index 0000000..876bef0 Binary files /dev/null and b/NeuralDetector/training/irtrans_7.bmp differ diff --git a/NeuralDetector/training/irtrans_8.bmp b/NeuralDetector/training/irtrans_8.bmp new file mode 100644 index 0000000..7bace4a Binary files /dev/null and b/NeuralDetector/training/irtrans_8.bmp differ diff --git a/NeuralDetector/training/irtrans_9.bmp b/NeuralDetector/training/irtrans_9.bmp new file mode 100644 index 0000000..d897025 Binary files /dev/null and b/NeuralDetector/training/irtrans_9.bmp differ diff --git a/NeuralDetector/training/led_0.bmp b/NeuralDetector/training/led_0.bmp new file mode 100644 index 0000000..062803e Binary files /dev/null and b/NeuralDetector/training/led_0.bmp differ diff --git a/NeuralDetector/training/led_1.bmp b/NeuralDetector/training/led_1.bmp new file mode 100644 index 0000000..d3db836 Binary files /dev/null and b/NeuralDetector/training/led_1.bmp differ diff --git a/NeuralDetector/training/led_10.bmp b/NeuralDetector/training/led_10.bmp new file mode 100644 index 0000000..7eb6f14 Binary files /dev/null and b/NeuralDetector/training/led_10.bmp differ diff --git a/NeuralDetector/training/led_11.bmp b/NeuralDetector/training/led_11.bmp new file mode 100644 index 0000000..ea8174a Binary files /dev/null and b/NeuralDetector/training/led_11.bmp differ diff --git a/NeuralDetector/training/led_12.bmp b/NeuralDetector/training/led_12.bmp new file mode 100644 index 0000000..68e0fcd Binary files /dev/null and b/NeuralDetector/training/led_12.bmp differ diff --git a/NeuralDetector/training/led_13.bmp b/NeuralDetector/training/led_13.bmp new file mode 100644 index 0000000..d6c6183 Binary files /dev/null and b/NeuralDetector/training/led_13.bmp differ diff --git a/NeuralDetector/training/led_14.bmp b/NeuralDetector/training/led_14.bmp new file mode 100644 index 0000000..2784d41 Binary files /dev/null and b/NeuralDetector/training/led_14.bmp differ diff --git a/NeuralDetector/training/led_15.bmp b/NeuralDetector/training/led_15.bmp new file mode 100644 index 0000000..c8a61c8 Binary files /dev/null and b/NeuralDetector/training/led_15.bmp differ diff --git a/NeuralDetector/training/led_2.bmp b/NeuralDetector/training/led_2.bmp new file mode 100644 index 0000000..702e31b Binary files /dev/null and b/NeuralDetector/training/led_2.bmp differ diff --git a/NeuralDetector/training/led_3.bmp b/NeuralDetector/training/led_3.bmp new file mode 100644 index 0000000..514e71f Binary files /dev/null and b/NeuralDetector/training/led_3.bmp differ diff --git a/NeuralDetector/training/led_4.bmp b/NeuralDetector/training/led_4.bmp new file mode 100644 index 0000000..85f5c3d Binary files /dev/null and b/NeuralDetector/training/led_4.bmp differ diff --git a/NeuralDetector/training/led_5.bmp b/NeuralDetector/training/led_5.bmp new file mode 100644 index 0000000..167c696 Binary files /dev/null and b/NeuralDetector/training/led_5.bmp differ diff --git a/NeuralDetector/training/led_6.bmp b/NeuralDetector/training/led_6.bmp new file mode 100644 index 0000000..d0d7615 Binary files /dev/null and b/NeuralDetector/training/led_6.bmp differ diff --git a/NeuralDetector/training/led_7.bmp b/NeuralDetector/training/led_7.bmp new file mode 100644 index 0000000..3558b88 Binary files /dev/null and b/NeuralDetector/training/led_7.bmp differ diff --git a/NeuralDetector/training/led_8.bmp b/NeuralDetector/training/led_8.bmp new file mode 100644 index 0000000..0100be7 Binary files /dev/null and b/NeuralDetector/training/led_8.bmp differ diff --git a/NeuralDetector/training/led_9.bmp b/NeuralDetector/training/led_9.bmp new file mode 100644 index 0000000..99e27eb Binary files /dev/null and b/NeuralDetector/training/led_9.bmp differ diff --git a/NeuralDetector/training/reedsens_0.bmp b/NeuralDetector/training/reedsens_0.bmp new file mode 100644 index 0000000..fd63013 Binary files /dev/null and b/NeuralDetector/training/reedsens_0.bmp differ diff --git a/NeuralDetector/training/reedsens_1.bmp b/NeuralDetector/training/reedsens_1.bmp new file mode 100644 index 0000000..1161930 Binary files /dev/null and b/NeuralDetector/training/reedsens_1.bmp differ diff --git a/NeuralDetector/training/reedsens_10.bmp b/NeuralDetector/training/reedsens_10.bmp new file mode 100644 index 0000000..180ea12 Binary files /dev/null and b/NeuralDetector/training/reedsens_10.bmp differ diff --git a/NeuralDetector/training/reedsens_11.bmp b/NeuralDetector/training/reedsens_11.bmp new file mode 100644 index 0000000..23c2c30 Binary files /dev/null and b/NeuralDetector/training/reedsens_11.bmp differ diff --git a/NeuralDetector/training/reedsens_12.bmp b/NeuralDetector/training/reedsens_12.bmp new file mode 100644 index 0000000..82acd92 Binary files /dev/null and b/NeuralDetector/training/reedsens_12.bmp differ diff --git a/NeuralDetector/training/reedsens_13.bmp b/NeuralDetector/training/reedsens_13.bmp new file mode 100644 index 0000000..aae5f3d Binary files /dev/null and b/NeuralDetector/training/reedsens_13.bmp differ diff --git a/NeuralDetector/training/reedsens_14.bmp b/NeuralDetector/training/reedsens_14.bmp new file mode 100644 index 0000000..91469a2 Binary files /dev/null and b/NeuralDetector/training/reedsens_14.bmp differ diff --git a/NeuralDetector/training/reedsens_15.bmp b/NeuralDetector/training/reedsens_15.bmp new file mode 100644 index 0000000..062a8e7 Binary files /dev/null and b/NeuralDetector/training/reedsens_15.bmp differ diff --git a/NeuralDetector/training/reedsens_2.bmp b/NeuralDetector/training/reedsens_2.bmp new file mode 100644 index 0000000..f0b942b Binary files /dev/null and b/NeuralDetector/training/reedsens_2.bmp differ diff --git a/NeuralDetector/training/reedsens_3.bmp b/NeuralDetector/training/reedsens_3.bmp new file mode 100644 index 0000000..b7678ce Binary files /dev/null and b/NeuralDetector/training/reedsens_3.bmp differ diff --git a/NeuralDetector/training/reedsens_4.bmp b/NeuralDetector/training/reedsens_4.bmp new file mode 100644 index 0000000..e1f522c Binary files /dev/null and b/NeuralDetector/training/reedsens_4.bmp differ diff --git a/NeuralDetector/training/reedsens_5.bmp b/NeuralDetector/training/reedsens_5.bmp new file mode 100644 index 0000000..1434fae Binary files /dev/null and b/NeuralDetector/training/reedsens_5.bmp differ diff --git a/NeuralDetector/training/reedsens_6.bmp b/NeuralDetector/training/reedsens_6.bmp new file mode 100644 index 0000000..0bc20c7 Binary files /dev/null and b/NeuralDetector/training/reedsens_6.bmp differ diff --git a/NeuralDetector/training/reedsens_7.bmp b/NeuralDetector/training/reedsens_7.bmp new file mode 100644 index 0000000..3890cb5 Binary files /dev/null and b/NeuralDetector/training/reedsens_7.bmp differ diff --git a/NeuralDetector/training/reedsens_8.bmp b/NeuralDetector/training/reedsens_8.bmp new file mode 100644 index 0000000..e09839c Binary files /dev/null and b/NeuralDetector/training/reedsens_8.bmp differ diff --git a/NeuralDetector/training/reedsens_9.bmp b/NeuralDetector/training/reedsens_9.bmp new file mode 100644 index 0000000..53b6588 Binary files /dev/null and b/NeuralDetector/training/reedsens_9.bmp differ diff --git a/NeuralDetector/training/reflsens_0.bmp b/NeuralDetector/training/reflsens_0.bmp new file mode 100644 index 0000000..c1d03f5 Binary files /dev/null and b/NeuralDetector/training/reflsens_0.bmp differ diff --git a/NeuralDetector/training/reflsens_1.bmp b/NeuralDetector/training/reflsens_1.bmp new file mode 100644 index 0000000..27064d2 Binary files /dev/null and b/NeuralDetector/training/reflsens_1.bmp differ diff --git a/NeuralDetector/training/reflsens_10.bmp b/NeuralDetector/training/reflsens_10.bmp new file mode 100644 index 0000000..a095472 Binary files /dev/null and b/NeuralDetector/training/reflsens_10.bmp differ diff --git a/NeuralDetector/training/reflsens_11.bmp b/NeuralDetector/training/reflsens_11.bmp new file mode 100644 index 0000000..869e361 Binary files /dev/null and b/NeuralDetector/training/reflsens_11.bmp differ diff --git a/NeuralDetector/training/reflsens_12.bmp b/NeuralDetector/training/reflsens_12.bmp new file mode 100644 index 0000000..5a69aa4 Binary files /dev/null and b/NeuralDetector/training/reflsens_12.bmp differ diff --git a/NeuralDetector/training/reflsens_13.bmp b/NeuralDetector/training/reflsens_13.bmp new file mode 100644 index 0000000..7dcdb7e Binary files /dev/null and b/NeuralDetector/training/reflsens_13.bmp differ diff --git a/NeuralDetector/training/reflsens_14.bmp b/NeuralDetector/training/reflsens_14.bmp new file mode 100644 index 0000000..7fbdfb2 Binary files /dev/null and b/NeuralDetector/training/reflsens_14.bmp differ diff --git a/NeuralDetector/training/reflsens_15.bmp b/NeuralDetector/training/reflsens_15.bmp new file mode 100644 index 0000000..b7ab025 Binary files /dev/null and b/NeuralDetector/training/reflsens_15.bmp differ diff --git a/NeuralDetector/training/reflsens_2.bmp b/NeuralDetector/training/reflsens_2.bmp new file mode 100644 index 0000000..c75cca5 Binary files /dev/null and b/NeuralDetector/training/reflsens_2.bmp differ diff --git a/NeuralDetector/training/reflsens_3.bmp b/NeuralDetector/training/reflsens_3.bmp new file mode 100644 index 0000000..c177d73 Binary files /dev/null and b/NeuralDetector/training/reflsens_3.bmp differ diff --git a/NeuralDetector/training/reflsens_4.bmp b/NeuralDetector/training/reflsens_4.bmp new file mode 100644 index 0000000..1ff5d65 Binary files /dev/null and b/NeuralDetector/training/reflsens_4.bmp differ diff --git a/NeuralDetector/training/reflsens_5.bmp b/NeuralDetector/training/reflsens_5.bmp new file mode 100644 index 0000000..5a87b5a Binary files /dev/null and b/NeuralDetector/training/reflsens_5.bmp differ diff --git a/NeuralDetector/training/reflsens_6.bmp b/NeuralDetector/training/reflsens_6.bmp new file mode 100644 index 0000000..edeca8e Binary files /dev/null and b/NeuralDetector/training/reflsens_6.bmp differ diff --git a/NeuralDetector/training/reflsens_7.bmp b/NeuralDetector/training/reflsens_7.bmp new file mode 100644 index 0000000..6e48d12 Binary files /dev/null and b/NeuralDetector/training/reflsens_7.bmp differ diff --git a/NeuralDetector/training/reflsens_8.bmp b/NeuralDetector/training/reflsens_8.bmp new file mode 100644 index 0000000..18d30fd Binary files /dev/null and b/NeuralDetector/training/reflsens_8.bmp differ diff --git a/NeuralDetector/training/reflsens_9.bmp b/NeuralDetector/training/reflsens_9.bmp new file mode 100644 index 0000000..b278c20 Binary files /dev/null and b/NeuralDetector/training/reflsens_9.bmp differ diff --git a/NeuralDetector/training/rgbled_0.bmp b/NeuralDetector/training/rgbled_0.bmp new file mode 100644 index 0000000..a3097a1 Binary files /dev/null and b/NeuralDetector/training/rgbled_0.bmp differ diff --git a/NeuralDetector/training/rgbled_1.bmp b/NeuralDetector/training/rgbled_1.bmp new file mode 100644 index 0000000..368d59d Binary files /dev/null and b/NeuralDetector/training/rgbled_1.bmp differ diff --git a/NeuralDetector/training/rgbled_10.bmp b/NeuralDetector/training/rgbled_10.bmp new file mode 100644 index 0000000..ff4bfeb Binary files /dev/null and b/NeuralDetector/training/rgbled_10.bmp differ diff --git a/NeuralDetector/training/rgbled_11.bmp b/NeuralDetector/training/rgbled_11.bmp new file mode 100644 index 0000000..69a9bd1 Binary files /dev/null and b/NeuralDetector/training/rgbled_11.bmp differ diff --git a/NeuralDetector/training/rgbled_12.bmp b/NeuralDetector/training/rgbled_12.bmp new file mode 100644 index 0000000..d077ecf Binary files /dev/null and b/NeuralDetector/training/rgbled_12.bmp differ diff --git a/NeuralDetector/training/rgbled_13.bmp b/NeuralDetector/training/rgbled_13.bmp new file mode 100644 index 0000000..9e34de0 Binary files /dev/null and b/NeuralDetector/training/rgbled_13.bmp differ diff --git a/NeuralDetector/training/rgbled_14.bmp b/NeuralDetector/training/rgbled_14.bmp new file mode 100644 index 0000000..3fe210a Binary files /dev/null and b/NeuralDetector/training/rgbled_14.bmp differ diff --git a/NeuralDetector/training/rgbled_15.bmp b/NeuralDetector/training/rgbled_15.bmp new file mode 100644 index 0000000..4272896 Binary files /dev/null and b/NeuralDetector/training/rgbled_15.bmp differ diff --git a/NeuralDetector/training/rgbled_2.bmp b/NeuralDetector/training/rgbled_2.bmp new file mode 100644 index 0000000..81c3499 Binary files /dev/null and b/NeuralDetector/training/rgbled_2.bmp differ diff --git a/NeuralDetector/training/rgbled_3.bmp b/NeuralDetector/training/rgbled_3.bmp new file mode 100644 index 0000000..e674094 Binary files /dev/null and b/NeuralDetector/training/rgbled_3.bmp differ diff --git a/NeuralDetector/training/rgbled_4.bmp b/NeuralDetector/training/rgbled_4.bmp new file mode 100644 index 0000000..a923088 Binary files /dev/null and b/NeuralDetector/training/rgbled_4.bmp differ diff --git a/NeuralDetector/training/rgbled_5.bmp b/NeuralDetector/training/rgbled_5.bmp new file mode 100644 index 0000000..bc35fcf Binary files /dev/null and b/NeuralDetector/training/rgbled_5.bmp differ diff --git a/NeuralDetector/training/rgbled_6.bmp b/NeuralDetector/training/rgbled_6.bmp new file mode 100644 index 0000000..9f7ab7f Binary files /dev/null and b/NeuralDetector/training/rgbled_6.bmp differ diff --git a/NeuralDetector/training/rgbled_7.bmp b/NeuralDetector/training/rgbled_7.bmp new file mode 100644 index 0000000..812b7a9 Binary files /dev/null and b/NeuralDetector/training/rgbled_7.bmp differ diff --git a/NeuralDetector/training/rgbled_8.bmp b/NeuralDetector/training/rgbled_8.bmp new file mode 100644 index 0000000..c2d5678 Binary files /dev/null and b/NeuralDetector/training/rgbled_8.bmp differ diff --git a/NeuralDetector/training/rgbled_9.bmp b/NeuralDetector/training/rgbled_9.bmp new file mode 100644 index 0000000..a33cac2 Binary files /dev/null and b/NeuralDetector/training/rgbled_9.bmp differ diff --git a/NeuralDetector/training/switch_0.bmp b/NeuralDetector/training/switch_0.bmp new file mode 100644 index 0000000..4ba4121 Binary files /dev/null and b/NeuralDetector/training/switch_0.bmp differ diff --git a/NeuralDetector/training/switch_1.bmp b/NeuralDetector/training/switch_1.bmp new file mode 100644 index 0000000..9257494 Binary files /dev/null and b/NeuralDetector/training/switch_1.bmp differ diff --git a/NeuralDetector/training/switch_10.bmp b/NeuralDetector/training/switch_10.bmp new file mode 100644 index 0000000..722e2ba Binary files /dev/null and b/NeuralDetector/training/switch_10.bmp differ diff --git a/NeuralDetector/training/switch_11.bmp b/NeuralDetector/training/switch_11.bmp new file mode 100644 index 0000000..e608bc0 Binary files /dev/null and b/NeuralDetector/training/switch_11.bmp differ diff --git a/NeuralDetector/training/switch_12.bmp b/NeuralDetector/training/switch_12.bmp new file mode 100644 index 0000000..e5e68d1 Binary files /dev/null and b/NeuralDetector/training/switch_12.bmp differ diff --git a/NeuralDetector/training/switch_13.bmp b/NeuralDetector/training/switch_13.bmp new file mode 100644 index 0000000..671a197 Binary files /dev/null and b/NeuralDetector/training/switch_13.bmp differ diff --git a/NeuralDetector/training/switch_14.bmp b/NeuralDetector/training/switch_14.bmp new file mode 100644 index 0000000..0ee7824 Binary files /dev/null and b/NeuralDetector/training/switch_14.bmp differ diff --git a/NeuralDetector/training/switch_15.bmp b/NeuralDetector/training/switch_15.bmp new file mode 100644 index 0000000..e12966b Binary files /dev/null and b/NeuralDetector/training/switch_15.bmp differ diff --git a/NeuralDetector/training/switch_2.bmp b/NeuralDetector/training/switch_2.bmp new file mode 100644 index 0000000..addbdc5 Binary files /dev/null and b/NeuralDetector/training/switch_2.bmp differ diff --git a/NeuralDetector/training/switch_3.bmp b/NeuralDetector/training/switch_3.bmp new file mode 100644 index 0000000..0d7eefa Binary files /dev/null and b/NeuralDetector/training/switch_3.bmp differ diff --git a/NeuralDetector/training/switch_4.bmp b/NeuralDetector/training/switch_4.bmp new file mode 100644 index 0000000..01cd795 Binary files /dev/null and b/NeuralDetector/training/switch_4.bmp differ diff --git a/NeuralDetector/training/switch_5.bmp b/NeuralDetector/training/switch_5.bmp new file mode 100644 index 0000000..3b50a86 Binary files /dev/null and b/NeuralDetector/training/switch_5.bmp differ diff --git a/NeuralDetector/training/switch_6.bmp b/NeuralDetector/training/switch_6.bmp new file mode 100644 index 0000000..317f784 Binary files /dev/null and b/NeuralDetector/training/switch_6.bmp differ diff --git a/NeuralDetector/training/switch_7.bmp b/NeuralDetector/training/switch_7.bmp new file mode 100644 index 0000000..6fded5e Binary files /dev/null and b/NeuralDetector/training/switch_7.bmp differ diff --git a/NeuralDetector/training/switch_8.bmp b/NeuralDetector/training/switch_8.bmp new file mode 100644 index 0000000..7ce52e3 Binary files /dev/null and b/NeuralDetector/training/switch_8.bmp differ diff --git a/NeuralDetector/training/switch_9.bmp b/NeuralDetector/training/switch_9.bmp new file mode 100644 index 0000000..8fb52a8 Binary files /dev/null and b/NeuralDetector/training/switch_9.bmp differ diff --git a/NeuralDetector/training/weerstand_0.bmp b/NeuralDetector/training/weerstand_0.bmp new file mode 100644 index 0000000..24823cb Binary files /dev/null and b/NeuralDetector/training/weerstand_0.bmp differ diff --git a/NeuralDetector/training/weerstand_1.bmp b/NeuralDetector/training/weerstand_1.bmp new file mode 100644 index 0000000..5d7c9be Binary files /dev/null and b/NeuralDetector/training/weerstand_1.bmp differ diff --git a/NeuralDetector/training/weerstand_10.bmp b/NeuralDetector/training/weerstand_10.bmp new file mode 100644 index 0000000..869afd6 Binary files /dev/null and b/NeuralDetector/training/weerstand_10.bmp differ diff --git a/NeuralDetector/training/weerstand_11.bmp b/NeuralDetector/training/weerstand_11.bmp new file mode 100644 index 0000000..50eeb79 Binary files /dev/null and b/NeuralDetector/training/weerstand_11.bmp differ diff --git a/NeuralDetector/training/weerstand_12.bmp b/NeuralDetector/training/weerstand_12.bmp new file mode 100644 index 0000000..86bece8 Binary files /dev/null and b/NeuralDetector/training/weerstand_12.bmp differ diff --git a/NeuralDetector/training/weerstand_13.bmp b/NeuralDetector/training/weerstand_13.bmp new file mode 100644 index 0000000..0591ad7 Binary files /dev/null and b/NeuralDetector/training/weerstand_13.bmp differ diff --git a/NeuralDetector/training/weerstand_14.bmp b/NeuralDetector/training/weerstand_14.bmp new file mode 100644 index 0000000..19a2d98 Binary files /dev/null and b/NeuralDetector/training/weerstand_14.bmp differ diff --git a/NeuralDetector/training/weerstand_15.bmp b/NeuralDetector/training/weerstand_15.bmp new file mode 100644 index 0000000..45ad90b Binary files /dev/null and b/NeuralDetector/training/weerstand_15.bmp differ diff --git a/NeuralDetector/training/weerstand_2.bmp b/NeuralDetector/training/weerstand_2.bmp new file mode 100644 index 0000000..127fa82 Binary files /dev/null and b/NeuralDetector/training/weerstand_2.bmp differ diff --git a/NeuralDetector/training/weerstand_3.bmp b/NeuralDetector/training/weerstand_3.bmp new file mode 100644 index 0000000..af781b4 Binary files /dev/null and b/NeuralDetector/training/weerstand_3.bmp differ diff --git a/NeuralDetector/training/weerstand_4.bmp b/NeuralDetector/training/weerstand_4.bmp new file mode 100644 index 0000000..fbe35b5 Binary files /dev/null and b/NeuralDetector/training/weerstand_4.bmp differ diff --git a/NeuralDetector/training/weerstand_5.bmp b/NeuralDetector/training/weerstand_5.bmp new file mode 100644 index 0000000..b9d6046 Binary files /dev/null and b/NeuralDetector/training/weerstand_5.bmp differ diff --git a/NeuralDetector/training/weerstand_6.bmp b/NeuralDetector/training/weerstand_6.bmp new file mode 100644 index 0000000..5d1e7d6 Binary files /dev/null and b/NeuralDetector/training/weerstand_6.bmp differ diff --git a/NeuralDetector/training/weerstand_7.bmp b/NeuralDetector/training/weerstand_7.bmp new file mode 100644 index 0000000..241f4ee Binary files /dev/null and b/NeuralDetector/training/weerstand_7.bmp differ diff --git a/NeuralDetector/training/weerstand_8.bmp b/NeuralDetector/training/weerstand_8.bmp new file mode 100644 index 0000000..a7974bf Binary files /dev/null and b/NeuralDetector/training/weerstand_8.bmp differ diff --git a/NeuralDetector/training/weerstand_9.bmp b/NeuralDetector/training/weerstand_9.bmp new file mode 100644 index 0000000..8e00430 Binary files /dev/null and b/NeuralDetector/training/weerstand_9.bmp differ