├── .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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
174 |
175 | 4. Select Complier for the project as **GNU Compiler Collection* (GCC)**. Click **Finish**.
176 |
177 | 
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 | 
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 | 
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 | 
205 |
206 | ### Build the Project
207 | 1. Select **Project -> Build Project**.
208 |
209 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
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 | 
315 |
316 | * Run the C++ code again to visualize data on grafana.
317 |
318 | 
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 | 
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 |
--------------------------------------------------------------------------------