├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── application ├── include │ └── influxdb.h └── src │ ├── influxdb.cpp │ └── main.cpp ├── docs └── images │ ├── Color.png │ ├── Crack.png │ ├── Grafana1.png │ ├── Grafana2.png │ ├── Grafana3.png │ ├── Grafana4.png │ ├── Grafana5.png │ ├── Grafana6.png │ ├── Grafana7.png │ ├── Orientation.png │ ├── dataFlow.png │ ├── figure1.png │ ├── figure2.png │ ├── figure3.png │ ├── figure4.png │ ├── figure5.png │ ├── figure6.png │ ├── figure7.png │ ├── figure8.png │ └── figure9.png ├── resources ├── config.json └── productFlawDetector.json └── setup.sh /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | json 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018 Intel Corporation. 2 | # 3 | # Permission is hereby granted, free of charge, to any person obtaining 4 | # a copy of this software and associated documentation files (the 5 | # "Software"), to deal in the Software without restriction, including 6 | # without limitation the rights to use, copy, modify, merge, publish, 7 | # distribute, sublicense, and/or sell copies of the Software, and to 8 | # permit persons to whom the Software is furnished to do so, subject to 9 | # the following conditions: 10 | # 11 | # The above copyright notice and this permission notice shall be 12 | # included in all copies or substantial portions of the Software. 13 | # 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | cmake_minimum_required(VERSION 2.8) 23 | project( product-flaw-detector ) 24 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 25 | find_package( OpenCV REQUIRED ) 26 | include_directories( ${OpenCV_INCLUDE_DIRS} ) 27 | include_directories( application/include ) 28 | include_directories(json/single_include) 29 | add_executable( product-flaw-detector application/src/main.cpp application/src/influxdb.cpp ) 30 | target_link_libraries( product-flaw-detector ${OpenCV_LIBS} -lcurl) 31 | 32 | 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Intel Corporation 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DISCONTINUATION OF PROJECT # 2 | This project will no longer be maintained by Intel. 3 | Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project. 4 | Intel no longer accepts patches to this project. 5 | # Object Flaw Detector 6 | 7 | | Details | | 8 | |-----------------------|------------------| 9 | | Target OS: | Ubuntu\* 18.04 LTS | 10 | | Programming Language: | C++ | 11 | | Time to complete: | 30 min | 12 | 13 | ![intoduction](./docs/images/Color.png) 14 | ## Introduction 15 | 16 | Object flaw detector application detects anomalies such as color, crack and the orientation of an object moving on a conveyor belt. Anomalies are marked as defective and saved in the color, crack, orientation folders respectively. Also objects with no defects are saved in no_defect folder. These anomalies data are sent to InfluxDB* database and visualized on Grafana*. This application also measures length and width of the object in millimeters. 17 | 18 | ## Requirements 19 | ### Hardware 20 | * [IEI Tank* AIoT Developer Kit](https://software.intel.com/en-us/iot/hardware/iei-tank-dev-kit) 21 | 22 | ### Software 23 | * [Ubuntu* 18.04 LTS](http://releases.ubuntu.com/18.04/) 24 | * Intel® Distribution of OpenVINO™ toolkit 2020 R3 Release 25 | * Intel® System Studio 2019 26 | 27 | ## How It Works 28 | 29 | * This application accepts input from a video camera or a video file for processing. 30 | 31 | ![Data Flow Diagram](./docs/images/dataFlow.png) 32 | 33 | * **Orientation defect detection**: Obtain the frame and change the color space to HSV format. Threshold the image based on the color of the object using [inRange](https://docs.opencv.org/3.4.0/da/d97/tutorial_threshold_inRange.html) function to create a mask. Perform morphological opening and closing on the mask and find the contours using [findContours](https://docs.opencv.org/3.4.0/d4/d73/tutorial_py_contours_begin.html) function. Filter the contours based on the area. Perform [PCA](https://docs.opencv.org/3.4/d1/dee/tutorial_introduction_to_pca.html) on the contours to get the orientation of the object. 34 | 35 | ![Figure 9](./docs/images/Orientation.png) 36 | 37 | * **Color defect detection**: Threshold the image based on the defective color of the object using [inRange](https://docs.opencv.org/3.4.0/da/d97/tutorial_threshold_inRange.html) function. Use the mask obtained from the [inRange](https://docs.opencv.org/3.4.0/da/d97/tutorial_threshold_inRange.html) function to find the defective area. 38 | 39 | ![Figure 10](./docs/images/Color.png) 40 | 41 | * **Crack detection**: Transform the image from BGR to Grayscale format using [cvtColor](https://docs.opencv.org/3.4.3/d7/d1b/group__imgproc__misc.html#ga397ae87e1288a81d2363b61574eb8cab) function. Blur the image using [blur](https://docs.opencv.org/3.4.0/dc/dd3/tutorial_gausian_median_blur_bilateral_filter.html) function to remove the noises. Use the contours found on the blurred image to detect the cracks. 42 | 43 | ![Figure 11](./docs/images/Crack.png) 44 | 45 | * Save the images of defective objects in their respective folders. For example, objects with color defect are saved in **color** folder, objects containing cracks are saved in **crack** folder, objects with orientation defect are saved in **orientation** folder and objects with no defect are stored in **no_defect** folder. 46 | 47 | ## Setup 48 | ### Get the code 49 | Clone the reference implementation
50 | ``` 51 | sudo apt-get update && sudo apt-get install git 52 | git clone https://github.com/intel-iot-devkit/object-flaw-detector-cpp.git 53 | ``` 54 | ### Install Intel® Distribution of OpenVINO™ toolkit 55 | 56 | Refer to [Install Intel® Distribution of OpenVINO™ toolkit on Linux*](https://software.intel.com/en-us/articles/OpenVINO-Install-Linux) for more information on how to install and setup the toolkit. 57 | 58 | ## Install Intel® System Studio 2019 59 | 60 | 1. Download [Intel® System Studio 2019](https://software.intel.com/en-us/system-studio/choose-download) and extract the downloaded zip file. 61 | 2. Open a new terminal and navigate to the directory where the contents are extracted in the previous step. 62 | 3. Run ./install.sh script and follow the instructions provided there to install Intel® System Studio 2019. 63 | 64 | ### Other dependencies 65 | **InfluxDB***
66 | InfluxDB is a time series database designed to handle high write and query loads. InfluxDB is meant to be used as a backing store for any use case involving large amounts of timestamped data, including DevOps monitoring, application metrics, IoT sensor data, and real-time analytics. 67 | 68 | **Grafana***
69 | Grafana is an open-source, general purpose dashboard and graph composer, which runs as a web application. It supports Graphite, InfluxDB, Prometheus, OpenTSDB etc., as backends. Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored.
70 | 71 | ### Install the dependencies 72 | To download the video and install the dependencies of the application, run the below command in the `object-flaw-detector-cpp` directory: 73 | ``` 74 | ./setup.sh 75 | ``` 76 | ### The config file 77 | The _resources/config.json_ contains the path of video that will be used by the application as input. 78 | 79 | For example: 80 | ``` 81 | { 82 | "inputs": [ 83 | { 84 | "video":"path_to_video/video1.mp4" 85 | } 86 | ] 87 | } 88 | ``` 89 | 90 | The `path/to/video` is the path to an input video file. 91 | 92 | 93 | ### Which Input Video to use 94 | 95 | We recommend using [bolt-detection](https://github.com/intel-iot-devkit/sample-videos/blob/master/bolt-detection.mp4). 96 | For example: 97 | ``` 98 | { 99 | "inputs": [ 100 | { 101 | "video":"sample-videos/bolt-detection.mp4 102 | } 103 | ] 104 | } 105 | ``` 106 | If the user wants to use any other video, it can be used by providing the path in the config.json file. 107 | 108 | ### Using the Camera instead of video 109 | Replace `path/to/video` with the camera ID in the **config.json** file, where the ID is taken from the video device (the number **X** in /dev/video**X**). 110 | 111 | On Ubuntu, to list all available video devices use the following command: 112 | 113 | ``` 114 | ls /dev/video* 115 | ``` 116 | 117 | For example, if the output of above command is __/dev/video0__, then config.json would be: 118 | 119 | ``` 120 | { 121 | "inputs": [ 122 | { 123 | "video":"0" 124 | } 125 | ] 126 | } 127 | ``` 128 | ### Setup the environment 129 | 130 | Configure the environment to use the Intel® Distribution of OpenVINO™ toolkit one time per session by exporting environment variables: 131 | 132 | ``` 133 | source /opt/intel/openvino/bin/setupvars.sh 134 | ``` 135 | **Note:** This command needs to be executed only once in the terminal where the application will be executed. If the terminal is closed, the command needs to be executed again. 136 | 137 | ### Build the application 138 | To build, go to intruder-detector-cpp directory and run the following commands: 139 | 140 | ``` 141 | mkdir -p build && cd build 142 | cmake .. 143 | make 144 | ``` 145 | 146 | ## Run the application 147 | ### Run the Application from the Terminal 148 | 149 | To run the application, use the following command: 150 | ``` 151 | ./product-flaw-detector 152 | ``` 153 | 154 | **Optional:** If field of view and distance between the object and camera are available, use -f and -d command line arguments respectively. Otherwise a camera of 96 pixels per inch is considered by default. For example: 155 | 156 | ``` 157 | ./product-flaw-detector -f 60 -d 50 158 | ``` 159 | 160 | **Note:** User can get field of view from camera specifications. The values for -f and -d should be in **degrees** and **millimeters** respectively. 161 | 162 | 163 | ### Run the Application on Intel® System Studio 2019 164 | 165 | On the system, open Intel® System Studio 2019 and choose your workspace. 166 | 1. Click **File -> New -> Project -> Intel Application Development**. 167 | 2. Select **C++ project**. Click **Next**. 168 | 169 | ![Figure 1](./docs/images/figure1.png) 170 | 171 | 3. Select **Tool Samples** tab and click on **Intel® C++ Complier -> Hello World** example and change the name of the project to **object-flaw-detector**. Click **Next**. 172 | 173 | ![Figure 2](./docs/images/figure2.png) 174 | 175 | 4. Select Complier for the project as **GNU Compiler Collection* (GCC)**. Click **Finish**. 176 | 177 | ![Figure 3](./docs/images/figure3.png) 178 | 179 | 5. Delete the file named **hello_world.cpp** (example code) from the Project Explorer. 180 | 6. Click **File -> New -> File**. Select the parent folder and name the new file as **product-flaw-detector.cpp**. Click **Finish**. 181 | 7. Copy the code from **main.cpp** located in **application/src** to the newly created file. 182 | 8. Copy the **config.json** from the */resources* to the */resources* directory. 183 | 9. Open the **config.json** in the current-workspace directory and provide the path of the video. 184 | 10. Copy the **influxdb.cpp** from the */application/src* to the current working directory. 185 | 186 | ### Add Include Path 187 | 1. Select **Project -> Properties -> C/C++ General -> Paths and Symbols**. 188 | 2. Select **Includes -> GNU C++** and Click on **Add...** 189 | 3. Click on **File system...** and add *opt/intel/openvino/opencv/include*, */application/src*, */json/single_include* and */application/include* to include the path of OpenVINO™ toolkit. Click **Apply and Close**. 190 | 191 | ![Figure 4](./docs/images/figure4.png) 192 | 193 | 194 | ### Add Libraries 195 | 1. Select **Project -> Properties -> C/C++ Build -> Settings -> GCC C++ Linker -> Libraries.** 196 | 2. Click on **File system...** and add *opt/intel/openvino/opencv/lib* to ```Library Search Path (-L)```. 197 | 3. Add **opencv_core, curl, opencv_highgui, opencv_imgproc, opencv_imgcodecs, opencv_videoio** to the ```Libraries (-l)``` and click **Apply and Close**. 198 | 199 | ![Figure 5](./docs/images/figure5.png) 200 | 201 | Select **Project -> Properties -> C/C++ Build -> Settings -> GCC C++ Compiler -> Dialect**. 202 | Select the Language standard as ISO **C++ 11(-std=c++0x)** and click **Apply and Close**. 203 | 204 | ![Figure 6](./docs/images/figure6.png) 205 | 206 | ### Build the Project 207 | 1. Select **Project -> Build Project**. 208 | 209 | ![Figure 7](./docs/images/figure7.png) 210 | 211 | ### Run the Project 212 | 1. Select **Run -> Run Configuration.. -> C/C++ Application ->**. Choose the project **object-flaw-detector**. 213 | 2. Click **Run**. 214 | 215 | ![Figure 8](./docs/images/figure8.png) 216 | 217 | **Optional**- If field of view and distance between the object and camera are available, use -f and -d arguments respectively. Otherwise camera of 96 pixels per inch is considered by default. 218 | 219 | ![Figure 9](./docs/images/figure9.png) 220 | 221 | 4. To run the program using camera as input, replace the video path in step 2 with cam. 222 | 223 | **Note**- If you are running the application on **Intel® System Studio**, the defect images are stored in the directory in **Intel® System Studio** workspace. 224 | 225 | ## Troubleshooting 226 | 227 | If this error occurs while running the code on Intel® System Studio: 228 | **error while loading shared libraries: libopencv_core.so.4.1: cannot open shared object file: No such file or directory** 229 | 230 | Execute these steps: 231 | 232 | * Create a file opencv.conf in /etc/ld.so.conf.d/. 233 | * Write the path of the particular library in the opencv.conf file. 234 | * Run sudo ldconfig -v. 235 | 236 | 237 | * To check the data on InfluxDB, run the following commands. 238 | 239 | ``` 240 | influx 241 | show databases 242 | use Defect 243 | select * from Defect 244 | ``` 245 | 246 | * To visualize data on Grafana, follow below steps. 247 | 248 | 1. On the terminal, run the given command. 249 | 250 | ``` 251 | sudo service grafana-server start 252 | ``` 253 | 254 | 2. In your browser, go to localhost:3000. 255 | 256 | 3. Log in with user as **admin** and password as **admin**. 257 | 258 | 4. Click on the **Configuration** on left side of the panel. 259 | 260 | 5. Select **“Data Sources”**. 261 | 262 | 6. Click on **“+ Add data source”** and provide below inputs 263 | * *Name*: Defect. 264 | * *Type*: InfluxDB. 265 | * *URL*: http://localhost:8086. 266 | * *Database*: Defect. 267 | * Click on “Save and Test”. 268 | 269 | ![Grafana1](./docs/images/Grafana1.png) 270 | 271 | 7. To add graph to the created Dashboard, follow the below steps 272 | * Click on Add(**+**) on left side of panel. 273 | * Select **“Dashboard”**. 274 | * Select **“Graph”**. Click on **Panel Title**, select **Edit** and then select **Metrics** tab. 275 | * On the **Metrics** tab 276 | 1. From **Datasource** choose **Defect**. 277 | 2. Click on the row just below the tab, starting with **“A”**. 278 | 3. Click on **“select measurement”** and select **“Defect”**. 279 | 4. From **SELECT** row, click on **“fields”** and select **“objectNumber”**. Also click on **+** in the same row, select **Aggregations** and click on **distinct()**. Again click on **+** in the same row, select **Aliasing** and click on **alias** to provide alias for the respective field. From **GROUP BY** row, click on time and select **1s** also click on fill and select **null**. Name the query as **objectNumber** in the **ALIAS BY** row. 280 | 5. Similarly, do it for **“crackDefect”**, **“orientationDefect”** and **“colorDefect”** by clicking **Add Query**. 281 | 282 | * On the **Time range** tab, change the **override relative time** to 100s. 283 | * Save the dashboard by clicking on top panel with name **productFlawDetector**. 284 | 285 | ![Grafana2](./docs/images/Grafana2.png) 286 | 287 | 8. To add table to the created Dashboard, follow the below steps 288 | * Click on the **add panel** icon on the top menu. 289 | * Select **Table**, click on **Panel Title**, select **Edit** and then select **Metrics** tab. Follow the steps mentioned in the previous step for configuring **Metrics** and **Time range** tab except for **Aggregations** and select **none** in fill. 290 | * Select **Selectors** and click on **last** from select row. 291 | * From the **Column Styles** tab, click on **+Add** in the **Apply to columns named** give the name **objectNumber**, and change the value to **0** in the **Decimals** under **Type** option. 292 | * In the same row click on **+Add** and select other fields (**“crackDefect”**, **“orientationDefect”** and **“colorDefect”**). 293 | * Save the dashboard and click on **Back to dashboard** icon which is on right corner of the top menu. 294 | ![Grafana3](./docs/images/Grafana3.png) 295 | 296 | 9. To add gauge to the created Dashboard, follow the below steps 297 | * Click on the **add panel** icon on the top menu. 298 | * Select **Singlestat**. Click on **Panel Title**, select **Edit** and then select **Metrics** tab menu and follow the steps mentioned in the previous steps for configuring **Metrics** tab except for aggregations and fill. 299 | * Select **Selectors** and click on **last** from select row. Do the following only for **objectNumber**.Name the query as **objectNumber** in the **ALIAS BY** row. 300 | * On the **Options** tab, select **show** under **Gauge** option and change the value of **decimals** to **0** under **Value** option. 301 | * Save the dashboard and click on **Back to dashboard** icon. 302 | ![Grafana4](./docs/images/Grafana4.png) 303 | 304 | 10. Mark the current directory as favorite by clicking on **Mark as favorite** icon on the top menu. 305 | 306 | 11. Select **Time picker** from the top menu of dashboard. Under **Custom range** change the **From** value to **now-10s** and **Refreshing every:** to **5s**. 307 | 308 | 12. For re-testing, follow the below steps 309 | * In a new browser tab or window, go to http://localhost:3000/. 310 | * Log in with user as **admin** and password as **admin**. 311 | * The **“New dashboard”** will now show up in the list of starred dashboards (and probably also under “Recently viewed dashboards”). 312 | * Click on “New dashboard” to see the chart. 313 | 314 | ![Grafana5](./docs/images/Grafana5.png) 315 | 316 | * Run the C++ code again to visualize data on grafana. 317 | 318 | ![Grafana6](./docs/images/Grafana6.png) 319 | 320 | ​ 321 | 322 | * Alternatively, visualization on Grafana can be done by following below steps 323 | 324 | 1. In your browser, go to localhost:3000. 325 | 2. Log in with user as **admin** and password as **admin**. 326 | 3. Click on **Configuration**. 327 | 4. Select **“Data Sources”**. 328 | 5. Click on **“+ Add data source”** and provide below inputs. 329 | * *Name*: Defect 330 | * *Type*: InfluxDB 331 | * *URL*: http://localhost:8086 332 | * *Database*: Defect 333 | * Click on “Save and Test” 334 | 335 | ![Grafana7](./docs/images/Grafana7.png) 336 | 337 | 6. Click on **+** icon present on the left side of the browser, select **import**. 338 | 7. Click on **Upload.json File**. 339 | 8. Select the file name "productFlawDetector.json" from _object-flaw-detector/resources_ directory. 340 | 9. Select "Defect" in **Select a influxDB data source**. 341 | 10. Click on import. 342 | 11. Run the application to see the data on the dashboard. 343 | 344 | ## (Optional) Save Data to the Cloud 345 | As an optional step, send data results to an Amazon Web Services (AWS)* instance for graphing. 346 | 347 | 1\. Make an EC2 Linux* instance on AWS 348 | ([*https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2\_GetStarted.html*](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EC2_GetStarted.html)) 349 | 350 | 2\. Install InfluxDB on EC2 Linux instance 351 | ([*https://github.com/influxdata/influxdb*](https://github.com/influxdata/influxdb)) 352 | 353 | 3\. Install Grafana on EC2 Linux instance 354 | ([*https://grafana.com/get*](https://grafana.com/get)) 355 | 356 | -------------------------------------------------------------------------------- /application/include/influxdb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 Intel Corporation. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /** 25 | * @brief Header file to create database and write the data to InfluxDB 26 | */ 27 | 28 | # pragma once 29 | # include 30 | # include 31 | # include 32 | # include 33 | 34 | /** 35 | * @brief namespace for InfluxDB class and data structure 36 | */ 37 | namespace influx 38 | { 39 | 40 | /** 41 | * @brief Structure data for managing and querying the data to be written in InfluxDB 42 | */ 43 | static struct Data 44 | { 45 | private: 46 | bool is_measure = false; 47 | bool is_time = false; 48 | bool is_field = false; 49 | long long int time = 0; 50 | std::string measure; 51 | std::vector field_data; 52 | std::string tag_data; 53 | 54 | public: 55 | 56 | /** 57 | * @brief Takes the measurement name from the user 58 | * @param value - Name of the measurement 59 | */ 60 | void add_measure(const std::string& value); 61 | 62 | /** 63 | * @brief Takes the tag key and value and add to the query string 64 | * @param key - Tag Key 65 | * @param value - Tag value 66 | */ 67 | 68 | void add_tag(const std::string& key, const std::string& value); 69 | 70 | void add_tag(const std::string& key, short value); 71 | 72 | void add_tag(const std::string& key, int value); 73 | 74 | void add_tag(const std::string& key, double value); 75 | 76 | void add_tag(const std::string& key, long value); 77 | 78 | void add_tag(const std::string& key, long long value); 79 | 80 | 81 | /** 82 | * @brief Takes the field key and value and add to the query string 83 | * @param key - field Key 84 | * @param value - field value 85 | */ 86 | 87 | void add_field(const std::string& key, const std::string& value); 88 | 89 | void add_field(const std::string& key, short value); 90 | 91 | void add_field(const std::string& key, int value); 92 | 93 | void add_field(const std::string& key, double value); 94 | 95 | void add_field(const std::string& key, long value); 96 | 97 | void add_field(const std::string& key, long long value); 98 | 99 | void add_timestamp(long long _time); 100 | 101 | /** 102 | * @brief Build the data string (data to be written to influxDB) that will be sent as data using InfluxDB Rest API 103 | * @return data string 104 | */ 105 | 106 | std::string build_query(); 107 | 108 | /** 109 | * @brief Add an escape character '\' in case on " ", "," and "=" in string values of key 110 | * Reference - InfluxDB write protocol 111 | * @param data - data to be formatted 112 | * @param measure - True if it is a measurement value 113 | * @return - formatted string 114 | */ 115 | 116 | std::string add_escape_seq(std::string data, bool measure); 117 | 118 | 119 | } data; 120 | 121 | /** 122 | * @brief InfluxDB class to manage and write the data to the database 123 | */ 124 | class InfluxDB 125 | { 126 | private: 127 | std::string host; 128 | int port; 129 | std::string url; 130 | FILE* file = fopen("../influx-logs.txt", "w"); 131 | 132 | public: 133 | 134 | /** 135 | * @brief Default constructor. If host and port are not given, initial it by default to localhost:8086 136 | */ 137 | InfluxDB(); 138 | 139 | /** 140 | * @brief Paramaterised constructor 141 | * @param host - InfluxDB hostname 142 | * @param port - InfluxDB port 143 | */ 144 | 145 | InfluxDB(std::string host, int port); 146 | 147 | /** 148 | * @brief Post the query using InfluxDB Rest API 149 | * @param _url - url on which request has to be posted 150 | * @param data - data to be sent 151 | * @return - Request status 152 | */ 153 | 154 | CURLcode http_post(std::string _url, std::string data); 155 | 156 | /** 157 | * @brief Creates the database in InfluxDB 158 | * @param db_name - Name of the database to be created 159 | * @return -1 in case of error else 0 160 | */ 161 | 162 | int create_database(const std::string& db_name); 163 | 164 | /** 165 | * @brief Preprocess the data to be written to the database 166 | * @param db_name - Name of the database in which data has to written 167 | * @param data - Data to be written to the database 168 | * @return -1 in case of error else 0 169 | */ 170 | int write_point(std::string db_name, influx::Data data); 171 | }; 172 | }; 173 | -------------------------------------------------------------------------------- /application/src/influxdb.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2019 Intel Corporation. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | # include "influxdb.h" 25 | 26 | influx::InfluxDB::InfluxDB() 27 | { 28 | host = "localhost"; 29 | port = 8086; 30 | url = "http://localhost:8086"; 31 | } 32 | 33 | influx::InfluxDB::InfluxDB(std::string host, int port) 34 | { 35 | this->host = host; 36 | this->port = port; 37 | url = "http://" + host + ":" + std::to_string(port); 38 | } 39 | 40 | 41 | CURLcode influx::InfluxDB::http_post(std::string _url, std::string data) 42 | { 43 | CURL *handle; 44 | CURLcode status; 45 | handle = curl_easy_init(); 46 | curl_easy_setopt(handle, CURLOPT_URL, _url.c_str()); 47 | curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, fwrite); 48 | curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)file); 49 | if (handle) 50 | { 51 | curl_easy_setopt(handle, CURLOPT_POSTFIELDS, data.c_str()); 52 | 53 | // Send the HTTP POST request 54 | status = curl_easy_perform(handle); 55 | curl_easy_cleanup(handle); 56 | handle = NULL; 57 | } 58 | return status; 59 | } 60 | 61 | 62 | int influx::InfluxDB::create_database(const std::string& db_name) 63 | { 64 | CURLcode status; 65 | std::string _url = url + "/query"; 66 | std::string _query = "q=CREATE DATABASE \"" + db_name + "\""; 67 | status = http_post(_url, _query); 68 | if (status != CURLE_OK) 69 | { 70 | printf("Curl failed with code %d (%s)n", status, curl_easy_strerror(status)); 71 | return -1; 72 | } 73 | return 0; 74 | } 75 | 76 | int influx::InfluxDB::write_point(std::string db_name, influx::Data data) 77 | { 78 | CURLcode status; 79 | std::string _url = url + "/write?db=" + db_name; 80 | std::string _data = data.build_query(); 81 | 82 | if (_data == "") 83 | { 84 | std::cout<<"ERROR:: Error occured while writing the data. Please check the Format of the data\n"; 85 | return -1; 86 | } 87 | status = http_post(_url, _data.c_str()); 88 | if (status != CURLE_OK) 89 | { 90 | printf("Curl failed with code %d (%s)n", status, curl_easy_strerror(status)); 91 | return -1; 92 | } 93 | return 0; 94 | } 95 | 96 | 97 | void influx::Data::add_measure(const std::string& value) 98 | { 99 | if (is_measure) 100 | { 101 | std::cout<<"WARNING:: Measurement has been added more than once. Taking the first value!"< 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "influxdb.h" 35 | #include 36 | #include 37 | 38 | using namespace cv; 39 | using namespace std; 40 | using json = nlohmann::json; 41 | json jsonobj; 42 | 43 | #define OBJECT_AREA_MIN 9000 44 | #define OBJECT_AREA_MAX 50000 45 | #define MAX_DEFECT_TYPES 3 46 | 47 | // Lower and Upper value of color range of the object 48 | #define LOW_H 0 49 | #define LOW_S 0 50 | #define LOW_V 47 51 | #define HIGH_H 179 52 | #define HIGH_S 255 53 | #define HIGH_V 255 54 | 55 | int KeyPressed; // Ascii value for the key pressed 56 | int count_object = 0; 57 | float one_pixel_length = 0.0; 58 | char object_count[200]; 59 | char object_height[100]; // Length of the object 60 | char object_width[100]; // Width of the object 61 | std::string output_string; 62 | std::vector measurement; 63 | 64 | // Create dataset for PCA Analysis 65 | Mat createBuffer(const vector &contour_points) 66 | { 67 | Mat data_points = Mat(contour_points.size(), 2, CV_64FC1); 68 | for (int row = 0; row < data_points.rows; row++) 69 | { 70 | data_points.at(row, 0) = contour_points[row].x; 71 | data_points.at(row, 1) = contour_points[row].y; 72 | } 73 | 74 | return data_points; 75 | } 76 | 77 | // Get the orientation of the object 78 | double getOrientation(Mat data_points) 79 | { 80 | // Perform PCA Analysis on the data points 81 | PCA pca(data_points, Mat(), PCA::DATA_AS_ROW); 82 | Point2d eigen_vector; 83 | eigen_vector = Point2d(pca.eigenvectors.at(0, 0), 84 | pca.eigenvectors.at(0, 1)); 85 | 86 | // Get the orientation in radians 87 | double angle = atan2(eigen_vector.y, eigen_vector.x); 88 | return angle; 89 | } 90 | 91 | /*********************************************** Orientation detection ************************************************** 92 | ** Step 1: Filter the contours based on the area to get the object of interest 93 | ** Step 2: Invoke getOrientation() and pass the contour of the object as an argument 94 | ** getOrientation() function performs the PCA analysis 95 | ** Step 3: Save the image of the object in "orientation" folder if orientation defect is present 96 | *************************************************************************************************************************/ 97 | 98 | std::vector detectOrientation(Mat &frame, const vector> contours, Rect object) 99 | { 100 | std::vector defects; 101 | std::string defect_flag; 102 | double area = 0, angle = 0; 103 | static int orientation_num = 0; 104 | Mat img = frame.clone(); 105 | for (size_t i = 0; i < contours.size(); ++i) 106 | { 107 | // Calculate the area of each contour 108 | area = contourArea(contours[i]); 109 | 110 | // Ignore contours that are too small to be the object of interest 111 | if (area < OBJECT_AREA_MIN) 112 | continue; 113 | 114 | Mat data_points = createBuffer(contours[i]); 115 | 116 | // Find the orientation of each contour 117 | angle = getOrientation(data_points); 118 | 119 | // If angle is less than 0.5 then we conclude that no orientation defect is present 120 | if (angle < 0.5) 121 | { 122 | // Set defect_flag to true when the object does not contain orientation defect 123 | defect_flag = "true"; 124 | } 125 | else 126 | { 127 | cout << "Orientation defect detected in object " << count_object << endl; 128 | output_string = output_string + "Orientation" + " "; 129 | sprintf(object_count, "Object Number : %d", count_object); 130 | putText(img, object_height, Point(5, 80), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 131 | putText(img, object_width, Point(5, 110), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 132 | putText(img, object_count, Point(5, 50), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 133 | putText(img, output_string, Point(5, 140), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 134 | orientation_num += 1; 135 | imwrite(format("orientation/object_%d.png", count_object), img(Rect(object.tl(), object.br()))); 136 | imshow("Out", img); 137 | KeyPressed = waitKey(2000); 138 | if (KeyPressed == 113 || KeyPressed == 81) // Ascii value of Q = 81 and q = 113 139 | exit(0); 140 | } 141 | break; 142 | } 143 | defects.push_back(defect_flag); 144 | return defects; 145 | } 146 | 147 | /*********************************************** Color defect detection ************************************************** 148 | ** Step 1: Increase the brightness of the image 149 | ** Step 2: Convert the image to HSV Format. 150 | ** HSV color space gives more information about the colors of the image. It helps to identify distinct colors in the image. 151 | ** Step 3: Threshold the image based on the color using "inRange" function. 152 | ** Pass range of the color, which is considered as a defect for the object, as one of the argument to inRange function, 153 | ** to create a mask 154 | ** Step 4: Morphological opening and closing is done on the mask to remove noises and fill the gaps 155 | ** Step 5: Find the contours on the mask image. Contours are filtered based on the area to get the contours of defective area. 156 | ** Contour of the defective area is then drawn on the original image to visualize 157 | ** Step 6: Save the image of the object in "color" folder if color defect is present 158 | *************************************************************************************************************************/ 159 | 160 | std::vector detectColor(Mat &frame, Rect object) 161 | { 162 | std::vector defects; 163 | std::string defect_flag; 164 | bool color_flag; 165 | double area = 0; 166 | static int color_num = 0; 167 | Mat imgHSV, img_thresholded, img; 168 | vector hierarchy; 169 | vector> contours; 170 | 171 | img = frame.clone(); 172 | 173 | // Increase the brightness of the image 174 | frame.convertTo(imgHSV, -1, 1, 20); 175 | 176 | // Convert the captured frame from BGR to HSV 177 | cvtColor(imgHSV, imgHSV, COLOR_BGR2HSV); 178 | 179 | // Threshold the image 180 | inRange(imgHSV, Scalar(0, 0, 0), Scalar(174, 73, 255), img_thresholded); 181 | 182 | // Morphological opening (remove small objects from the foreground) 183 | erode(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 184 | dilate(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 185 | 186 | // Morphological closing (fill small holes in the foreground) 187 | dilate(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 188 | erode(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 189 | findContours(img_thresholded, contours, hierarchy, RETR_LIST, CHAIN_APPROX_NONE); 190 | 191 | for (size_t i = 0; i < contours.size(); ++i) 192 | { 193 | area = contourArea(contours[i]); 194 | if (area > 2000 && area < 10000) 195 | { 196 | drawContours(img, contours, i, Scalar(0, 0, 255), 2, 8, hierarchy, 0); 197 | sprintf(object_count, "Object Number : %d", count_object); 198 | // putText(frame, object_width, Point(5, 110), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 199 | color_num += 1; 200 | defect_flag = "false"; 201 | color_flag = "true"; 202 | } 203 | else if (color_flag != true) 204 | { 205 | defect_flag = "true"; 206 | } 207 | } 208 | 209 | if (color_flag == true) 210 | { 211 | output_string = output_string + "Color" + " "; 212 | cout << "Color defect detected in object " << count_object << endl; 213 | putText(img, object_count, Point(5, 50), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 214 | putText(img, output_string, Point(5, 140), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 215 | putText(img, object_height, Point(5, 80), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 216 | putText(img, object_width, Point(5, 110), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 217 | imwrite(format("color/object_%d.png", count_object), img(Rect(object.tl(), object.br()))); 218 | imshow("Out", img); 219 | KeyPressed = waitKey(2000); 220 | if (KeyPressed == 113 || KeyPressed == 81) // Ascii value of Q = 81 and q = 113 221 | exit(0); 222 | } 223 | defects.push_back(defect_flag); 224 | return defects; 225 | } 226 | 227 | /**************************************************** Crack detection ************************************************** 228 | ** Step 1: Convert the image to gray scale 229 | ** Step 2: Blur the gray image to remove the noises 230 | ** Step 3: Find the edges on the blurred image to get the contours of possible cracks 231 | ** Step 4: Filter the contours to get the contour of the crack 232 | ** Step 5: Draw the contour on the original image for visualization 233 | ** Step 6: Save the image of the object in "crack" folder if crack defect is present 234 | *************************************************************************************************************************/ 235 | 236 | std::vector detectCrack(Mat &frame, Rect object) 237 | { 238 | std::vector defects; 239 | std::string defect_flag= "false"; 240 | char object_count[200]; 241 | double area = 0; 242 | Mat detected_edges, img; 243 | static int crack_num = 0; 244 | int low_threshold = 130, kernel_size = 3, ratio = 3; 245 | vector hierarchy; 246 | vector> contours; 247 | 248 | // Convert the captured frame from BGR to GRAY 249 | cvtColor(frame, img, COLOR_BGR2GRAY); 250 | blur(img, img, Size(7, 7)); 251 | 252 | // Find the edges 253 | Canny(img, detected_edges, low_threshold, low_threshold * ratio, kernel_size); 254 | 255 | // Find the contours 256 | findContours(detected_edges, contours, hierarchy, RETR_LIST, CHAIN_APPROX_SIMPLE); 257 | 258 | // Draw contours 259 | if (contours.size() != 0) 260 | { 261 | for (size_t i = 0; i < contours.size(); i++) 262 | { 263 | area = contourArea(contours[i]); 264 | if (area > 20 || area < 9) 265 | { 266 | sprintf(object_count, "Object Number : %d", count_object); 267 | putText(frame, object_height, Point(5, 80), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 268 | putText(frame, object_width, Point(5, 110), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 269 | putText(frame, object_count, Point(5, 50), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 270 | drawContours(frame, contours, i, Scalar(0, 255, 0), 2, 8, hierarchy, 0); 271 | } 272 | else 273 | { 274 | // Set defect_flag to true when the object does not contain any cracks 275 | defect_flag = "true"; 276 | } 277 | } 278 | if (defect_flag == "false") 279 | { 280 | cout << "Crack detected in object " << count_object << endl; 281 | output_string = output_string + "Crack" + " "; 282 | crack_num += 1; 283 | imwrite(format("crack/object_%d.png", count_object), frame(Rect(object.tl(), object.br()))); 284 | putText(frame, output_string, Point(5, 140), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 285 | imshow("Out", frame); 286 | KeyPressed = waitKey(2000); 287 | if (KeyPressed == 113 || KeyPressed == 81) // Ascii value of Q = 81 and q = 113 288 | exit(0); 289 | } 290 | } 291 | else 292 | { 293 | defect_flag = "true"; 294 | } 295 | defects.push_back(defect_flag); 296 | return defects; 297 | } 298 | 299 | /** Write the data to influxDB **/ 300 | int writeToInfluxDB(int count_object, int is_crack_defect, int is_orientation_defect, int is_color_defect) 301 | { 302 | string server_response; 303 | influx::InfluxDB db; 304 | influx::Data data; 305 | data.add_measure("Defect"); 306 | data.add_field("objectNumber", count_object); 307 | data.add_field("crackDefect", is_crack_defect); 308 | data.add_field("orientationDefect", is_orientation_defect); 309 | data.add_field("colorDefect", is_color_defect); 310 | int status = db.write_point("Defect", data); 311 | 312 | return EXIT_SUCCESS; 313 | } 314 | 315 | /** Calculate euclidean distance between two points **/ 316 | double calculate_distance(Point pts1, Point pts2) 317 | { 318 | double dist; 319 | 320 | double x = pts1.x - pts2.x; 321 | double y = pts1.y - pts2.y; 322 | 323 | // Calculating euclidean distance 324 | dist = pow(x, 2) + pow(y, 2); 325 | dist = sqrt(dist); 326 | 327 | return dist; 328 | } 329 | 330 | // Returns the rounded value 331 | double round(double value, int place) 332 | { 333 | return floor(value * pow(10, place) + 0.5) / pow(10, place); 334 | } 335 | 336 | // Return the Length and Width of the object 337 | std::vector find_dimensions(vector pts) 338 | { 339 | std::vector dimension; 340 | double length, width, length1, width1; 341 | Point tltr, blbr, tlbl, trbr; 342 | 343 | // Calculate Euclidean ditance 344 | length = int(calculate_distance(pts[0], pts[1])); 345 | width = int(calculate_distance(pts[1], pts[2])); 346 | 347 | // Rounding the values to two decimal place 348 | length1 = round(length * one_pixel_length * 10, 2); 349 | width1 = round(width * one_pixel_length * 10, 2); 350 | 351 | if (length1 > width1) 352 | { 353 | dimension.push_back(length1); 354 | dimension.push_back(width1); 355 | } 356 | else 357 | { 358 | dimension.push_back(width1); 359 | dimension.push_back(length1); 360 | } 361 | return dimension; 362 | } 363 | 364 | int main(int argc, char *argv[]) 365 | { 366 | bool is_orientation_defect, is_color_defect, is_crack_defect; 367 | char object_count[200], filepath[50]; 368 | const char *dir_names[] = {"crack", "color", "orientation", "no_defect"}; 369 | int frame_count = 0, num_of_dir = 4, status = 0; 370 | Mat frame, dst, detected_edges, img_hsv, img_thresholded, frame_color, frame_orientation, frame_crack, frame_nodefect; 371 | int width_of_video = 0, height_of_video = 0, opt = 0, field = 0, dist = 0; 372 | vector hierarchy; 373 | vector> contours; 374 | std::vector orientation_defect, color_defect, crack_defect; 375 | float diagonal_length_of_image_plane = 0.0, diagonal_length_in_pixel = 0.0, radians = 0.0; 376 | 377 | measurement.push_back(0.0); 378 | measurement.push_back(0.0); 379 | 380 | Rect object; 381 | DIR *dir; 382 | struct dirent *ent; 383 | struct stat st = {0}; 384 | string server_response; 385 | VideoCapture capture; 386 | std::string conf_file2 = "resources/config.json"; 387 | std::string conf_file = "../resources/config.json"; 388 | std::ifstream confFile(conf_file); 389 | if (!confFile.is_open()) 390 | { 391 | std::ifstream confFile2(conf_file2); 392 | if (!confFile2.is_open()) 393 | { 394 | cout << "Could not open config file" << endl; 395 | return 2; 396 | } 397 | confFile2>>jsonobj; 398 | } 399 | else 400 | confFile>>jsonobj; 401 | auto obj = jsonobj["inputs"]; 402 | std::string input = obj[0]["video"]; 403 | if (input.size() == 1 && *(input.c_str()) >= '0' && *(input.c_str()) <= '9') 404 | { 405 | capture.open(std::stoi(input)); 406 | } 407 | else 408 | { 409 | capture.open(input); 410 | } 411 | 412 | // Create directories to save images of objects 413 | for (int num = 0; num < num_of_dir; num++) 414 | { 415 | // Check if the directory exists, clean the directory if it does 416 | if (stat(dir_names[num], &st) == 0) 417 | { 418 | if ((dir = opendir(dir_names[num])) != NULL) 419 | { 420 | while ((ent = readdir(dir)) != NULL) 421 | { 422 | if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) 423 | continue; 424 | 425 | sprintf(filepath, "%s/%s", dir_names[num], ent->d_name); 426 | status = remove(filepath); 427 | if (status != 0) 428 | { 429 | cout << "Unable to delete the file " << ent->d_name << std::endl; 430 | perror("\n\tError"); 431 | return EXIT_FAILURE; 432 | } 433 | } 434 | closedir(dir); 435 | } 436 | else 437 | cout << "Error opening the directory" << endl; 438 | } 439 | // Create the directory if it does not exist 440 | else if ((mkdir(dir_names[num], 00777)) == -1) 441 | { 442 | cout << "Error in creating " << dir_names[num] << "directory" << endl; 443 | return EXIT_FAILURE; 444 | } 445 | } 446 | 447 | // Parsing Command Line arguments 448 | while ((opt = getopt(argc, argv, ":f:d:i:")) != -1) 449 | { 450 | switch (opt) 451 | { 452 | case 'f': 453 | field = atoi(optarg); 454 | break; 455 | case 'd': 456 | dist = atoi(optarg); 457 | break; 458 | } 459 | } 460 | 461 | if (field > 0 and dist > 0) 462 | { 463 | width_of_video = capture.get(3); 464 | height_of_video = capture.get(4); 465 | // Convert degrees to radians 466 | radians = (field / 2) * 0.0174533; 467 | //Calculate the diagonal length of image in millimeters using field of view of camera and distance between object and camera. 468 | diagonal_length_of_image_plane = (abs(2 * (dist / 10) * tan(radians))); 469 | // Calculate diagonal length of image in pixel 470 | diagonal_length_in_pixel = sqrt(pow(width_of_video, 2) + pow(height_of_video, 2)); 471 | // Convert one pixel value in millimeters 472 | one_pixel_length = (diagonal_length_of_image_plane / diagonal_length_in_pixel); 473 | } 474 | /* If distance between camera and object and field of view of camera 475 | are not provided, then 96 pixels per inch is considered. 476 | pixel_lengh = 2.54 cm (1 inch) / 96 pixels */ 477 | if (one_pixel_length == 0) 478 | one_pixel_length = 0.0264583333; 479 | 480 | // Check if video is loaded successfully 481 | if (!capture.isOpened()) 482 | { 483 | cout << "Problem loading the video!!!" << endl; 484 | return EXIT_FAILURE; 485 | } 486 | 487 | // Create the database in influxDB named "Defect" 488 | influx::InfluxDB db; 489 | db.create_database("Defect"); 490 | 491 | sprintf(object_count, "Object Number : %d", count_object); 492 | for (;;) 493 | { 494 | Rect maxArea = Rect(Point(0, 0), Point(1, 1)); 495 | 496 | // Read the frame from the stream 497 | capture >> frame; 498 | 499 | if (frame.empty()) 500 | { 501 | cout << "Video stream ended" << endl; 502 | break; 503 | } 504 | frame_count++; 505 | 506 | // Check every 40th frame (Number chosen based on the frequency of object on conveyor belt) 507 | if (frame_count % 40 == 0) 508 | { 509 | measurement[0] = 0; 510 | measurement[1] = 0; 511 | is_orientation_defect = true; 512 | is_color_defect = true; 513 | is_crack_defect = true; 514 | 515 | // Convert RGB image to HSV color space 516 | cvtColor(frame, img_hsv, COLOR_RGB2HSV); 517 | 518 | // Thresholding of an Image in a color range 519 | inRange(img_hsv, Scalar(LOW_H, LOW_S, LOW_V), Scalar(HIGH_H, HIGH_S, HIGH_V), img_thresholded); 520 | 521 | // Morphological opening (remove small objects from the foreground) 522 | erode(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 523 | dilate(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 524 | 525 | // Morphological closing (fill small holes in the foreground) 526 | dilate(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 527 | erode(img_thresholded, img_thresholded, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); 528 | 529 | // Find the contours on the image 530 | findContours(img_thresholded, contours, hierarchy, RETR_LIST, CHAIN_APPROX_NONE); 531 | vector minRect(contours.size()); 532 | 533 | // Find the contour with maximum area 534 | for (size_t contour = 0; contour < contours.size(); contour++) 535 | { 536 | object = boundingRect(contours[contour]); 537 | Point2f rect_points[4]; 538 | std::vector pts; 539 | if (object.width * object.height > OBJECT_AREA_MIN && OBJECT_AREA_MAX > object.width * object.height) 540 | { 541 | minRect[contour] = minAreaRect(contours[contour]); 542 | 543 | minRect[contour].points(rect_points); 544 | for (int point = 0; point < 4; point++) 545 | { 546 | int x = ceil(rect_points[point].x); // Coordinate of x 547 | int y = ceil(rect_points[point].y); // Coordinate of y 548 | pts.push_back(Point(x, y)); 549 | } 550 | 551 | measurement = find_dimensions(pts); 552 | sprintf(object_height, "Length (mm) = %.2f", measurement[0]); 553 | sprintf(object_width, "Width (mm) = %.2f", measurement[1]); 554 | frame_crack = frame.clone(); 555 | frame_orientation = frame.clone(); 556 | frame_color = frame.clone(); 557 | frame_nodefect = frame.clone(); 558 | 559 | // Save only the object instead of the complete frame 560 | count_object++; 561 | sprintf(object_count, "Object Number : %d", count_object); 562 | 563 | // Check the occurence of defects in object, if the function returns true, corresponding defect is not present in the object 564 | output_string.clear(); 565 | output_string = "Defect : "; 566 | 567 | orientation_defect = detectOrientation(frame_orientation, contours, object); 568 | if (strncmp(orientation_defect[0].c_str(), "true", 4) == 0) 569 | { 570 | is_orientation_defect = false; 571 | } 572 | 573 | color_defect = detectColor(frame_color, object); 574 | if (strncmp(color_defect[0].c_str(), "true", 4) == 0) 575 | { 576 | is_color_defect = false; 577 | } 578 | 579 | crack_defect = detectCrack(frame_crack, object); 580 | if (strcmp(crack_defect[0].c_str(), "true") == 0) 581 | { 582 | is_crack_defect = false; 583 | } 584 | 585 | // Display and save the object with no defect 586 | if (is_orientation_defect == false && is_color_defect == false && is_crack_defect == false) 587 | { 588 | output_string = output_string + "No Defect" + " "; 589 | cout << "No defect detected in object " << count_object << endl; 590 | sprintf(object_count, "Object Number : %d", count_object); 591 | putText(frame_nodefect, object_height, Point(5, 80), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 592 | putText(frame_nodefect, object_width, Point(5, 110), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 593 | putText(frame_nodefect, object_count, Point(5, 50), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 594 | putText(frame_nodefect, output_string, Point(5, 140), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 595 | imwrite(format("no_defect/object_%d.png", count_object), frame(Rect(object.tl(), object.br()))); 596 | imshow("Out", frame_nodefect); 597 | KeyPressed = waitKey(2000); 598 | if (KeyPressed == 113 || KeyPressed == 81) // Ascii value of Q = 81 and q = 113 599 | exit(0); 600 | } 601 | 602 | status = writeToInfluxDB(count_object, is_crack_defect, is_orientation_defect, is_color_defect); 603 | if (status == EXIT_FAILURE) 604 | { 605 | return EXIT_FAILURE; 606 | } 607 | cout << object_height << " " << object_width << endl; 608 | KeyPressed = waitKey(25); 609 | if (KeyPressed == 113 || KeyPressed == 81) // Ascii value of Q = 81 and q = 113 610 | exit(0); 611 | } 612 | } 613 | } 614 | sprintf(object_height, "Length (mm) = %.2f", measurement[0]); 615 | sprintf(object_width, "Width (mm) = %.2f", measurement[1]); 616 | putText(frame, "Press q to quit", Point(410, 50), FONT_HERSHEY_DUPLEX, 1, Scalar(255, 255, 255), 2); 617 | putText(frame, object_count, Point(5, 50), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 618 | putText(frame, object_height, Point(5, 80), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 619 | putText(frame, object_width, Point(5, 110), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 620 | putText(frame, "Defect : ", Point(5, 140), FONT_HERSHEY_DUPLEX, 0.75, Scalar(255, 255, 255), 2); 621 | imshow("Out", frame); 622 | KeyPressed = waitKey(25); 623 | if (KeyPressed == 113 || KeyPressed == 81) // Ascii value of Q = 81 and q = 113 624 | exit(0); 625 | hierarchy.clear(); 626 | contours.clear(); 627 | } 628 | return EXIT_SUCCESS; 629 | } 630 | 631 | -------------------------------------------------------------------------------- /docs/images/Color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Color.png -------------------------------------------------------------------------------- /docs/images/Crack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Crack.png -------------------------------------------------------------------------------- /docs/images/Grafana1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Grafana1.png -------------------------------------------------------------------------------- /docs/images/Grafana2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Grafana2.png -------------------------------------------------------------------------------- /docs/images/Grafana3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Grafana3.png -------------------------------------------------------------------------------- /docs/images/Grafana4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Grafana4.png -------------------------------------------------------------------------------- /docs/images/Grafana5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Grafana5.png -------------------------------------------------------------------------------- /docs/images/Grafana6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Grafana6.png -------------------------------------------------------------------------------- /docs/images/Grafana7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Grafana7.png -------------------------------------------------------------------------------- /docs/images/Orientation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/Orientation.png -------------------------------------------------------------------------------- /docs/images/dataFlow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/dataFlow.png -------------------------------------------------------------------------------- /docs/images/figure1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure1.png -------------------------------------------------------------------------------- /docs/images/figure2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure2.png -------------------------------------------------------------------------------- /docs/images/figure3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure3.png -------------------------------------------------------------------------------- /docs/images/figure4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure4.png -------------------------------------------------------------------------------- /docs/images/figure5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure5.png -------------------------------------------------------------------------------- /docs/images/figure6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure6.png -------------------------------------------------------------------------------- /docs/images/figure7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure7.png -------------------------------------------------------------------------------- /docs/images/figure8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure8.png -------------------------------------------------------------------------------- /docs/images/figure9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel-iot-devkit/object-flaw-detector-cpp/cc319b60b30fda626843a04d95a35c9f6b28e6b4/docs/images/figure9.png -------------------------------------------------------------------------------- /resources/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputs":[ 3 | { 4 | "video":"../resources/bolt-detection.mp4" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /resources/productFlawDetector.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_DEFECT", 5 | "label": "Defect", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "influxdb", 9 | "pluginName": "InfluxDB" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "5.2.4" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "5.0.0" 24 | }, 25 | { 26 | "type": "datasource", 27 | "id": "influxdb", 28 | "name": "InfluxDB", 29 | "version": "5.0.0" 30 | }, 31 | { 32 | "type": "panel", 33 | "id": "singlestat", 34 | "name": "Singlestat", 35 | "version": "5.0.0" 36 | }, 37 | { 38 | "type": "panel", 39 | "id": "table", 40 | "name": "Table", 41 | "version": "5.0.0" 42 | } 43 | ], 44 | "annotations": { 45 | "list": [ 46 | { 47 | "builtIn": 1, 48 | "datasource": "-- Grafana --", 49 | "enable": true, 50 | "hide": true, 51 | "iconColor": "rgba(0, 211, 255, 1)", 52 | "name": "Annotations & Alerts", 53 | "type": "dashboard" 54 | } 55 | ] 56 | }, 57 | "editable": true, 58 | "gnetId": null, 59 | "graphTooltip": 0, 60 | "id": null, 61 | "links": [], 62 | "panels": [ 63 | { 64 | "cacheTimeout": null, 65 | "colorBackground": false, 66 | "colorValue": false, 67 | "colors": [ 68 | "#d44a3a", 69 | "rgba(237, 129, 40, 0.89)", 70 | "#299c46" 71 | ], 72 | "datasource": "${DS_DEFECT}", 73 | "format": "none", 74 | "gauge": { 75 | "maxValue": 100, 76 | "minValue": 0, 77 | "show": true, 78 | "thresholdLabels": false, 79 | "thresholdMarkers": true 80 | }, 81 | "gridPos": { 82 | "h": 5, 83 | "w": 12, 84 | "x": 0, 85 | "y": 0 86 | }, 87 | "id": 4, 88 | "interval": null, 89 | "links": [], 90 | "mappingType": 1, 91 | "mappingTypes": [ 92 | { 93 | "name": "value to text", 94 | "value": 1 95 | }, 96 | { 97 | "name": "range to text", 98 | "value": 2 99 | } 100 | ], 101 | "maxDataPoints": 100, 102 | "nullPointMode": "connected", 103 | "nullText": null, 104 | "postfix": "", 105 | "postfixFontSize": "50%", 106 | "prefix": "", 107 | "prefixFontSize": "50%", 108 | "rangeMaps": [ 109 | { 110 | "from": "null", 111 | "text": "N/A", 112 | "to": "null" 113 | } 114 | ], 115 | "sparkline": { 116 | "fillColor": "rgba(31, 118, 189, 0.18)", 117 | "full": false, 118 | "lineColor": "rgb(31, 120, 193)", 119 | "show": false 120 | }, 121 | "tableColumn": "", 122 | "targets": [ 123 | { 124 | "groupBy": [ 125 | { 126 | "params": [ 127 | "1s" 128 | ], 129 | "type": "time" 130 | }, 131 | { 132 | "params": [ 133 | "null" 134 | ], 135 | "type": "fill" 136 | } 137 | ], 138 | "measurement": "Defect", 139 | "orderByTime": "ASC", 140 | "policy": "default", 141 | "refId": "A", 142 | "resultFormat": "time_series", 143 | "select": [ 144 | [ 145 | { 146 | "params": [ 147 | "objectNumber" 148 | ], 149 | "type": "field" 150 | }, 151 | { 152 | "params": [], 153 | "type": "last" 154 | } 155 | ] 156 | ], 157 | "tags": [] 158 | } 159 | ], 160 | "thresholds": "", 161 | "title": "ObjectNumber", 162 | "type": "singlestat", 163 | "valueFontSize": "80%", 164 | "valueMaps": [ 165 | { 166 | "op": "=", 167 | "text": "N/A", 168 | "value": "null" 169 | } 170 | ], 171 | "valueName": "current" 172 | }, 173 | { 174 | "columns": [], 175 | "datasource": "${DS_DEFECT}", 176 | "fontSize": "100%", 177 | "gridPos": { 178 | "h": 14, 179 | "w": 12, 180 | "x": 12, 181 | "y": 0 182 | }, 183 | "id": 12, 184 | "links": [], 185 | "pageSize": null, 186 | "scroll": true, 187 | "showHeader": true, 188 | "sort": { 189 | "col": 0, 190 | "desc": false 191 | }, 192 | "styles": [ 193 | { 194 | "alias": "Time", 195 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 196 | "pattern": "Time", 197 | "type": "date" 198 | }, 199 | { 200 | "alias": "", 201 | "colorMode": null, 202 | "colors": [ 203 | "rgba(245, 54, 54, 0.9)", 204 | "rgba(237, 129, 40, 0.89)", 205 | "rgba(50, 172, 45, 0.97)" 206 | ], 207 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 208 | "decimals": 0, 209 | "mappingType": 1, 210 | "pattern": "objectNumber", 211 | "thresholds": [], 212 | "type": "number", 213 | "unit": "short" 214 | }, 215 | { 216 | "alias": "objectNumber", 217 | "colorMode": null, 218 | "colors": [ 219 | "rgba(245, 54, 54, 0.9)", 220 | "rgba(237, 129, 40, 0.89)", 221 | "rgba(50, 172, 45, 0.97)" 222 | ], 223 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 224 | "decimals": 0, 225 | "mappingType": 1, 226 | "pattern": "Defect.objectNumber", 227 | "thresholds": [], 228 | "type": "number", 229 | "unit": "short" 230 | }, 231 | { 232 | "alias": "crackDefect", 233 | "colorMode": null, 234 | "colors": [ 235 | "rgba(245, 54, 54, 0.9)", 236 | "rgba(237, 129, 40, 0.89)", 237 | "rgba(50, 172, 45, 0.97)" 238 | ], 239 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 240 | "decimals": 0, 241 | "mappingType": 1, 242 | "pattern": "Defect.crackDefect", 243 | "thresholds": [], 244 | "type": "number", 245 | "unit": "short" 246 | }, 247 | { 248 | "alias": "orientationDefect", 249 | "colorMode": null, 250 | "colors": [ 251 | "rgba(245, 54, 54, 0.9)", 252 | "rgba(237, 129, 40, 0.89)", 253 | "rgba(50, 172, 45, 0.97)" 254 | ], 255 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 256 | "decimals": 0, 257 | "mappingType": 1, 258 | "pattern": "Defect.orientationDefect", 259 | "thresholds": [], 260 | "type": "number", 261 | "unit": "short" 262 | }, 263 | { 264 | "alias": "colorDefect", 265 | "colorMode": null, 266 | "colors": [ 267 | "rgba(245, 54, 54, 0.9)", 268 | "rgba(237, 129, 40, 0.89)", 269 | "rgba(50, 172, 45, 0.97)" 270 | ], 271 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 272 | "decimals": 0, 273 | "mappingType": 1, 274 | "pattern": "Defect.colorDefect", 275 | "thresholds": [], 276 | "type": "number", 277 | "unit": "short" 278 | }, 279 | { 280 | "alias": "", 281 | "colorMode": null, 282 | "colors": [ 283 | "rgba(245, 54, 54, 0.9)", 284 | "rgba(237, 129, 40, 0.89)", 285 | "rgba(50, 172, 45, 0.97)" 286 | ], 287 | "decimals": 2, 288 | "pattern": "/.*/", 289 | "thresholds": [], 290 | "type": "number", 291 | "unit": "short" 292 | } 293 | ], 294 | "targets": [ 295 | { 296 | "alias": "", 297 | "groupBy": [ 298 | { 299 | "params": [ 300 | "1s" 301 | ], 302 | "type": "time" 303 | }, 304 | { 305 | "params": [ 306 | "none" 307 | ], 308 | "type": "fill" 309 | } 310 | ], 311 | "hide": false, 312 | "measurement": "Defect", 313 | "orderByTime": "ASC", 314 | "policy": "default", 315 | "refId": "A", 316 | "resultFormat": "time_series", 317 | "select": [ 318 | [ 319 | { 320 | "params": [ 321 | "objectNumber" 322 | ], 323 | "type": "field" 324 | }, 325 | { 326 | "params": [], 327 | "type": "last" 328 | }, 329 | { 330 | "params": [ 331 | "objectNumber" 332 | ], 333 | "type": "alias" 334 | } 335 | ], 336 | [ 337 | { 338 | "params": [ 339 | "crackDefect" 340 | ], 341 | "type": "field" 342 | }, 343 | { 344 | "params": [], 345 | "type": "last" 346 | }, 347 | { 348 | "params": [ 349 | "crackDefect" 350 | ], 351 | "type": "alias" 352 | } 353 | ], 354 | [ 355 | { 356 | "params": [ 357 | "orientationDefect" 358 | ], 359 | "type": "field" 360 | }, 361 | { 362 | "params": [], 363 | "type": "last" 364 | }, 365 | { 366 | "params": [ 367 | "orientationDefect" 368 | ], 369 | "type": "alias" 370 | } 371 | ], 372 | [ 373 | { 374 | "params": [ 375 | "colorDefect" 376 | ], 377 | "type": "field" 378 | }, 379 | { 380 | "params": [], 381 | "type": "last" 382 | }, 383 | { 384 | "params": [ 385 | "colorDefect" 386 | ], 387 | "type": "alias" 388 | } 389 | ] 390 | ], 391 | "tags": [] 392 | } 393 | ], 394 | "timeFrom": "100s", 395 | "title": "", 396 | "transform": "timeseries_to_columns", 397 | "type": "table" 398 | }, 399 | { 400 | "aliasColors": {}, 401 | "bars": false, 402 | "dashLength": 10, 403 | "dashes": false, 404 | "datasource": "${DS_DEFECT}", 405 | "fill": 0, 406 | "gridPos": { 407 | "h": 9, 408 | "w": 12, 409 | "x": 0, 410 | "y": 5 411 | }, 412 | "hideTimeOverride": false, 413 | "id": 2, 414 | "legend": { 415 | "alignAsTable": false, 416 | "avg": false, 417 | "current": false, 418 | "hideEmpty": false, 419 | "hideZero": false, 420 | "max": false, 421 | "min": false, 422 | "rightSide": false, 423 | "show": true, 424 | "total": false, 425 | "values": false 426 | }, 427 | "lines": true, 428 | "linewidth": 2, 429 | "links": [], 430 | "nullPointMode": "null", 431 | "percentage": false, 432 | "pointradius": 2, 433 | "points": true, 434 | "renderer": "flot", 435 | "seriesOverrides": [], 436 | "spaceLength": 10, 437 | "stack": false, 438 | "steppedLine": false, 439 | "targets": [ 440 | { 441 | "alias": "objectNumber", 442 | "groupBy": [ 443 | { 444 | "params": [ 445 | "1s" 446 | ], 447 | "type": "time" 448 | }, 449 | { 450 | "params": [ 451 | "null" 452 | ], 453 | "type": "fill" 454 | } 455 | ], 456 | "measurement": "Defect", 457 | "orderByTime": "ASC", 458 | "policy": "default", 459 | "refId": "A", 460 | "resultFormat": "time_series", 461 | "select": [ 462 | [ 463 | { 464 | "params": [ 465 | "objectNumber" 466 | ], 467 | "type": "field" 468 | }, 469 | { 470 | "params": [], 471 | "type": "distinct" 472 | } 473 | ] 474 | ], 475 | "tags": [] 476 | }, 477 | { 478 | "alias": "colorDefect", 479 | "groupBy": [ 480 | { 481 | "params": [ 482 | "1s" 483 | ], 484 | "type": "time" 485 | }, 486 | { 487 | "params": [ 488 | "null" 489 | ], 490 | "type": "fill" 491 | } 492 | ], 493 | "measurement": "Defect", 494 | "orderByTime": "ASC", 495 | "policy": "default", 496 | "refId": "B", 497 | "resultFormat": "time_series", 498 | "select": [ 499 | [ 500 | { 501 | "params": [ 502 | "colorDefect" 503 | ], 504 | "type": "field" 505 | }, 506 | { 507 | "params": [], 508 | "type": "distinct" 509 | } 510 | ] 511 | ], 512 | "tags": [] 513 | }, 514 | { 515 | "alias": "crackDefect", 516 | "groupBy": [ 517 | { 518 | "params": [ 519 | "1s" 520 | ], 521 | "type": "time" 522 | }, 523 | { 524 | "params": [ 525 | "null" 526 | ], 527 | "type": "fill" 528 | } 529 | ], 530 | "measurement": "Defect", 531 | "orderByTime": "ASC", 532 | "policy": "default", 533 | "refId": "C", 534 | "resultFormat": "time_series", 535 | "select": [ 536 | [ 537 | { 538 | "params": [ 539 | "crackDefect" 540 | ], 541 | "type": "field" 542 | }, 543 | { 544 | "params": [], 545 | "type": "distinct" 546 | } 547 | ] 548 | ], 549 | "tags": [] 550 | }, 551 | { 552 | "alias": "orientationDefect", 553 | "groupBy": [ 554 | { 555 | "params": [ 556 | "1s" 557 | ], 558 | "type": "time" 559 | }, 560 | { 561 | "params": [ 562 | "null" 563 | ], 564 | "type": "fill" 565 | } 566 | ], 567 | "measurement": "Defect", 568 | "orderByTime": "ASC", 569 | "policy": "default", 570 | "refId": "D", 571 | "resultFormat": "time_series", 572 | "select": [ 573 | [ 574 | { 575 | "params": [ 576 | "orientationDefect" 577 | ], 578 | "type": "field" 579 | }, 580 | { 581 | "params": [], 582 | "type": "distinct" 583 | } 584 | ] 585 | ], 586 | "tags": [] 587 | } 588 | ], 589 | "thresholds": [ 590 | { 591 | "colorMode": "critical", 592 | "fill": true, 593 | "line": true, 594 | "op": "gt", 595 | "yaxis": "left" 596 | } 597 | ], 598 | "timeFrom": "100s", 599 | "timeShift": null, 600 | "title": "productFlawDetector", 601 | "tooltip": { 602 | "shared": true, 603 | "sort": 0, 604 | "value_type": "individual" 605 | }, 606 | "type": "graph", 607 | "xaxis": { 608 | "buckets": null, 609 | "mode": "time", 610 | "name": null, 611 | "show": true, 612 | "values": [] 613 | }, 614 | "yaxes": [ 615 | { 616 | "decimals": null, 617 | "format": "short", 618 | "label": "", 619 | "logBase": 1, 620 | "max": null, 621 | "min": null, 622 | "show": true 623 | }, 624 | { 625 | "format": "short", 626 | "label": null, 627 | "logBase": 1, 628 | "max": null, 629 | "min": null, 630 | "show": false 631 | } 632 | ], 633 | "yaxis": { 634 | "align": false, 635 | "alignLevel": null 636 | } 637 | } 638 | ], 639 | "refresh": "5s", 640 | "schemaVersion": 16, 641 | "style": "dark", 642 | "tags": [], 643 | "templating": { 644 | "list": [] 645 | }, 646 | "time": { 647 | "from": "now-5m", 648 | "to": "now" 649 | }, 650 | "timepicker": { 651 | "refresh_intervals": [ 652 | "5s", 653 | "10s", 654 | "30s", 655 | "1m", 656 | "5m", 657 | "15m", 658 | "30m", 659 | "1h", 660 | "2h", 661 | "1d" 662 | ], 663 | "time_options": [ 664 | "5m", 665 | "15m", 666 | "1h", 667 | "6h", 668 | "12h", 669 | "24h", 670 | "2d", 671 | "7d", 672 | "30d" 673 | ] 674 | }, 675 | "timezone": "", 676 | "title": "productFlawDetector", 677 | "uid": "4qMJbQ2iz", 678 | "version": 89 679 | } -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | : ' 2 | Copyright (c) 2018 Intel Corporation. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | ' 24 | sudo apt-get update 25 | # InfluxDB 26 | sudo apt install curl 27 | sudo curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add - 28 | source /etc/lsb-release 29 | echo "deb https://repos.influxdata.com/${DISTRIB_ID,,} ${DISTRIB_CODENAME} stable" | sudo tee /etc/apt/sources.list.d/influxdb.list 30 | sudo apt-get update && sudo apt-get install influxdb 31 | sudo service influxdb start 32 | 33 | # Grafana 34 | wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.3.2_amd64.deb 35 | sudo apt-get install -y adduser libfontconfig 36 | sudo dpkg -i grafana_5.3.2_amd64.deb 37 | sudo /bin/systemctl start grafana-server 38 | 39 | sudo apt-get install libcurl4-openssl-dev # Installing libcurl library 40 | 41 | if [ -d "json" ]; then 42 | echo "json repository already exists" 43 | else 44 | git clone https://github.com/nlohmann/json # Cloning json parser from github 45 | fi 46 | 47 | cd resources 48 | wget -O bolt-detection.mp4 https://github.com/intel-iot-devkit/sample-videos/raw/master/bolt-detection.mp4 49 | --------------------------------------------------------------------------------