[total, min, min x, min y, max, max x, max y, mean, sigma]
+
+
+
FindObjectCentroids
5
@@ -174,6 +198,9 @@
gaussian_blur
Next, the image is blurred using a gaussian kernel to emphasize edges. Then a laplacian kernel runs over
the images assigning a 'sharpness' value to each pixel. The sharpest values are hard edges from black to white.
+
Sharpen
+
Sharpens image by sutracting Laplacian from blurred image
+
CannyEdgeDetector
Function for canny-based edge detection. First, we ensure that the image is grayscale. Then, the image is blurred, so that only
strong edges remain. Then, a threshold is applied to the image in order to further reinforce strong edges. Finally, the canny
@@ -187,6 +214,9 @@
gaussian_blur
in pairs. Reads first image into memory, then waits for second one, when it receives the second one,
subtract them.
+
compute_image_stats
+
OpenCV accelerated computation of Image statistics
+
FindObjectCentroids
Function for finding centroids of objects in an image. Useful for alignment of objects
First, blur the object based on a certain blur degree (kernel size). Then threshold the image
From 46ae186db75393b11f0fdd1720bae5e4a86101c6 Mon Sep 17 00:00:00 2001
From: jwlodek
Date: Wed, 10 Apr 2019 20:10:14 -0400
Subject: [PATCH 21/83] minor fixes
---
adcvApp/adcvSrc/NDPluginCV.cpp | 12 ++++++------
adcvApp/adcvSrc/NDPluginCVHelper.cpp | 1 +
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/adcvApp/adcvSrc/NDPluginCV.cpp b/adcvApp/adcvSrc/NDPluginCV.cpp
index b35e5c3..fa77f0e 100644
--- a/adcvApp/adcvSrc/NDPluginCV.cpp
+++ b/adcvApp/adcvSrc/NDPluginCV.cpp
@@ -79,13 +79,13 @@ ADCVFrameFormat_t NDPluginCV::getCurrentImageFormat(NDDataType_t dataType, NDCol
case NDUInt8:
return ADCV_Mono_U8;
case NDInt8:
- return ADCV_Mono_S8;
+ return ADCV_Mono_U8;
case NDUInt16:
return ADCV_Mono_U16;
case NDInt16:
- return ADCV_Mono_S16;
+ return ADCV_Mono_U16;
case NDInt32:
- return ADCV_Mono_S32;
+ return ADCV_Mono_F32;
case NDFloat32:
return ADCV_Mono_F32;
case NDFloat64:
@@ -100,13 +100,13 @@ ADCVFrameFormat_t NDPluginCV::getCurrentImageFormat(NDDataType_t dataType, NDCol
case NDUInt8:
return ADCV_RGB_U8;
case NDInt8:
- return ADCV_RGB_S8;
+ return ADCV_RGB_U8;
case NDUInt16:
return ADCV_RGB_U16;
case NDInt16:
- return ADCV_RGB_S16;
+ return ADCV_RGB_U16;
case NDInt32:
- return ADCV_RGB_S32;
+ return ADCV_RGB_F32;
case NDFloat32:
return ADCV_RGB_F32;
case NDFloat64:
diff --git a/adcvApp/adcvSrc/NDPluginCVHelper.cpp b/adcvApp/adcvSrc/NDPluginCVHelper.cpp
index dac01e0..d445e71 100644
--- a/adcvApp/adcvSrc/NDPluginCVHelper.cpp
+++ b/adcvApp/adcvSrc/NDPluginCVHelper.cpp
@@ -1087,6 +1087,7 @@ ADCVStatus_t NDPluginCVHelper::processImage(Mat &image, ADCVFunction_t function,
status = laplacian_edge_detection(image, inputs, outputs);
break;
case ADCV_Sharpen:
+ status = downscale_image_8bit(image, camera_depth);
status = sharpen_images(image, inputs, outputs);
break;
From 30f02f501bc27701fae82953ccc75bc8e3684112 Mon Sep 17 00:00:00 2001
From: jwlodek
Date: Wed, 17 Apr 2019 14:18:34 -0400
Subject: [PATCH 22/83] added PV for distance computation function
---
adcvApp/Db/NDCV.template | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/adcvApp/Db/NDCV.template b/adcvApp/Db/NDCV.template
index 0534c61..459ffc1 100644
--- a/adcvApp/Db/NDCV.template
+++ b/adcvApp/Db/NDCV.template
@@ -104,7 +104,9 @@ record(mbbo, "$(P)$(R)CompVisionFunction3")
field(ONST, "User Function")
field(ONVL, "1")
field(TWST, "Image Stats")
- field(TWVL, "2")
+ field(TWVL, "2")
+ field(THST, "Dist. Check")
+ field(THVL, "3")
field(VAL, "0")
info(autosaveFields, "VAL")
}
@@ -119,6 +121,8 @@ record(mbbi, "$(P)$(R)CompVisionFunction3_RBV")
field(ONVL, "1")
field(TWST, "Image Stats")
field(TWVL, "2")
+ field(THST, "Dist. Check")
+ field(THVL, "3")
field(VAL, "0")
field(SCAN, "I/O Intr")
}
From 37994a61518fdc302885f7115fa2e60485d47b3d Mon Sep 17 00:00:00 2001
From: jwlodek
Date: Wed, 17 Apr 2019 14:19:00 -0400
Subject: [PATCH 23/83] added distance functions to header file
---
adcvApp/adcvSrc/NDPluginCVHelper.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/adcvApp/adcvSrc/NDPluginCVHelper.h b/adcvApp/adcvSrc/NDPluginCVHelper.h
index 027155e..242110b 100644
--- a/adcvApp/adcvSrc/NDPluginCVHelper.h
+++ b/adcvApp/adcvSrc/NDPluginCVHelper.h
@@ -47,7 +47,7 @@ using namespace std;
*/
#define N_FUNC_1 6
#define N_FUNC_2 3
-#define N_FUNC_3 3
+#define N_FUNC_3 4
@@ -70,6 +70,7 @@ typedef enum {
//ADCV_ObjIdentification = 7,
ADCV_UserDefined = 8,
ADCV_ImageStats = 9,
+ ADCV_DistanceCheck = 10,
} ADCVFunction_t;
@@ -121,6 +122,9 @@ class NDPluginCVHelper {
// Function that downscales image into 8 bit for functions that require it
ADCVStatus_t downscale_image_8bit(Mat &img, ADCVCameraDepth_t camera_depth);
+
+ // Additional processing functions (used to clean up wrapper functions)
+ double compute_rect_distance(Rect r1, Rect r2);
// OpenCV Wrapper functions
@@ -132,6 +136,7 @@ class NDPluginCVHelper {
ADCVStatus_t subtract_consecutive_images(Mat &img, double* inputs, double* outputs);
ADCVStatus_t compute_image_stats(Mat &img, double* inputs, double* outputs);
ADCVStatus_t sharpen_images(Mat &img, double* inputs, double* outputs);
+ ADCVStatus_t distance_between_ctrs(Mat &img, double* inputs, double* outputs);
// under development
ADCVStatus_t movement_vectors(Mat &img, double* inputs, double* outputs);
@@ -152,6 +157,7 @@ class NDPluginCVHelper {
ADCVStatus_t get_subtract_description(string* inputDesc, string* outputDesc, string* description);
ADCVStatus_t get_image_stats_description(string* inputDesc, string* outputDesc, string* description);
ADCVStatus_t get_sharpen_description(string* inputDesc, string* outputDesc, string* description);
+ ADCVStatus_t get_dist_between_description(string* inputDesc, string* outputDesc, string* description);
// Under development
ADCVStatus_t get_movement_vectors_description(string* inputDesc, string* outputDesc, string* description);
From 22bf8fb17e1400807800d811b52439a393541517 Mon Sep 17 00:00:00 2001
From: jwlodek
Date: Wed, 17 Apr 2019 14:19:18 -0400
Subject: [PATCH 24/83] implemented distance check function
---
adcvApp/adcvSrc/NDPluginCVHelper.cpp | 121 ++++++++++++++++++++++++++-
1 file changed, 118 insertions(+), 3 deletions(-)
diff --git a/adcvApp/adcvSrc/NDPluginCVHelper.cpp b/adcvApp/adcvSrc/NDPluginCVHelper.cpp
index d445e71..cecbaa2 100644
--- a/adcvApp/adcvSrc/NDPluginCVHelper.cpp
+++ b/adcvApp/adcvSrc/NDPluginCVHelper.cpp
@@ -51,6 +51,8 @@ using namespace std;
const char* libraryName = "NDPluginCVHelper";
+// ------------------------ General Utility functions ---------------
+
/**
* Simple function that prints OpenCV error information.
* Used in try/catch blocks
@@ -136,6 +138,20 @@ ADCVStatus_t NDPluginCVHelper::downscale_image_8bit(Mat &img, ADCVCameraDepth_t
}
+double NDPluginCVHelper::compute_rect_distance(Rect r1, Rect r2){
+ double xDist= -1, yDist = -1;
+ if(r1.x > r2.x + r2.width) xDist = r1.x - (r2.x + r2.width);
+ else if(r2.x > r1.x + r1.width) xDist = r2.x - (r1.x + r1.width);
+
+ if(r1.y > r2.y + r2.height) yDist = r1.y - (r2.y + r2.height);
+ else if(r2.y > r1.y + r1.height) yDist = r2.y - (r1.y + r1.height);
+
+ if(xDist != -1 && yDist != -1) return xDist > yDist ? yDist : xDist;
+ else if(xDist != -1) return xDist;
+ else return yDist;
+}
+
+
/*
#############################################################################
# #
@@ -435,6 +451,10 @@ ADCVStatus_t NDPluginCVHelper::compute_image_stats(Mat &img, double* inputs, dou
const char* functionName = "compute_image_stats";
ADCVStatus_t status = cvHelperSuccess;
try{
+ //int roiX = inputs[0];
+ //int roiY = inputs[1];
+ //int width = inputs[2];
+ //int height = inputs[3];
img.copyTo(this->temporaryImg);
if(this->temporaryImg.channels() == 3) cvtColor(this->temporaryImg, this->temporaryImg, COLOR_BGR2GRAY);
Scalar im_sum, mean, sigma;
@@ -680,6 +700,70 @@ ADCVStatus_t NDPluginCVHelper::user_function(Mat &img, double* inputs, double* o
return status;
}
+
+/**
+ * WRAPPER -> Distance between contours
+ * Function that computes bounding boxes between the two largest computed contours in the image,
+ * checks the distance between them and sends an alarm if they are within a distance threshold.
+ *
+ * @inCount -> 1
+ * @inFormat -> [[Distance Threshold (Int)]
+ *
+ * @outCount -> 1
+ * @outFormat -> [Is Within Threshold (Binary Int)]
+ */
+ADCVStatus_t NDPluginCVHelper::distance_between_ctrs(Mat &img, double* inputs, double* outputs){
+ const char* functionName = "distance_between_ctrs";
+ ADCVStatus_t status = cvHelperSuccess;
+ int distance_threshold = inputs[0];
+ int blurDegree = inputs[1];
+ int thresholdVal = inputs[2];
+ int applyBlur = inputs[3];
+ int contour_size_thresh = inputs[4];
+
+ try{
+ int largest_area = 0;
+ int second_area = 0;
+ Rect lbounding_rect, sbounding_rect;
+ if(applyBlur > 0) GaussianBlur(img, this->temporaryImg, Size(blurDegree, blurDegree), 0);
+ if(img.channels() == 3) cvtColor(this->temporaryImg, this->temporaryImg, COLOR_BGR2GRAY);
+ threshold(this->temporaryImg, this->temporaryImg, thresholdVal, 255, THRESH_BINARY);
+ vector > contours;
+ findContours(this->temporaryImg, contours, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0,0));
+ if(contours.size() > 1){
+ for(unsigned int i = 0; i< contours.size(); i++){
+ double area = contourArea(contours[i]);
+ if(area < contour_size_thresh){
+ if(area > largest_area){
+ if(largest_area > second_area){
+ second_area = largest_area;
+ sbounding_rect = lbounding_rect;
+ }
+ largest_area = area;
+ lbounding_rect = boundingRect(contours[i]);
+ }
+ else if( area > second_area){
+ second_area = area;
+ sbounding_rect = boundingRect(contours[i]);
+ }
+ }
+ }
+ rectangle(img, lbounding_rect, Scalar(0, 255, 0), 3);
+ rectangle(img, sbounding_rect, Scalar(0, 255, 0), 3);
+ outputs[1] = compute_rect_distance(lbounding_rect, sbounding_rect);
+ if(outputs[1] < distance_threshold) outputs[0] = 1;
+ else outputs[0] = 0;
+ cvHelperStatus = "Finished processing distance between contours";
+ }
+ else cvHelperStatus = "Couldn't identify two or more contours";
+ this->temporaryImg.release();
+ }catch(Exception &e){
+ print_cv_error(e, functionName);
+ status = cvHelperError;
+ }
+ return status;
+}
+
//------------------------ End of OpenCV wrapper functions -------------------------------------------------
/*
@@ -812,7 +896,32 @@ ADCVStatus_t NDPluginCVHelper::get_laplacian_description(string* inputDesc, stri
return status;
}
-//------------- Template for wrapper I/O description function -------------------
+
+/**
+ * Function that sets the I/O descriptions for Distance between check
+ *
+ * @params[out]: inputDesc -> array of input descriptions
+ * @params[out]: outputDesc -> array of output descriptions
+ * @params[out]: description -> overall function usage description
+ * @return: void
+ */
+ADCVStatus_t NDPluginCVHelper::get_dist_between_description(string* inputDesc, string* outputDesc, string* description){
+ ADCVStatus_t status = cvHelperSuccess;
+ int numInput = 5;
+ int numOutput = 2;
+ inputDesc[0] = "Distance Threshold [int]";
+ inputDesc[1] = "Blur Kernel Size [Odd int]";
+ inputDesc[2] = "Threshold Value [int < 255]";
+ inputDesc[3] = "Apply Blur [1 = yes, 0 = no]";
+ inputDesc[4] = "Size Threshold [int]";
+ outputDesc[0] = "Within Threshold Alarm";
+ outputDesc[1] = "Detected Min Pixel dist";
+ *description = "Description of Computes distance between contours";
+ populate_remaining_descriptions(inputDesc, outputDesc, numInput, numOutput);
+ return status;
+}
+
+
/*
@@ -830,7 +939,7 @@ ADCVStatus_t NDPluginCVHelper::get_sharpen_description(string* inputDesc, string
inputDesc[0] = "Gauss Blurr degree [int]";
inputDesc[1] = "Laplace kernel size [int]";
inputDesc[2] = "Laplace scale [int]";
- inputDesc[3] = "Laplace delat [int]";
+ inputDesc[3] = "Laplace delta [int]";
// outputDesc[0] = "Output 1 Description";
// outputDesc[1] = "Output 2 Description";
@@ -1105,6 +1214,10 @@ ADCVStatus_t NDPluginCVHelper::processImage(Mat &image, ADCVFunction_t function,
case ADCV_UserDefined:
status = user_function(image, inputs, outputs);
break;
+ case ADCV_DistanceCheck:
+ //status = downscale_image_8bit(image, camera_depth);
+ status = distance_between_ctrs(image, inputs, outputs);
+ break;
default:
status = cvHelperError;
break;
@@ -1114,7 +1227,6 @@ ADCVStatus_t NDPluginCVHelper::processImage(Mat &image, ADCVFunction_t function,
if(status == cvHelperError){
printf("%s::%s Error in helper library\n", libraryName, functionName);
- cvHelperStatus = "Error processing image";
}
return status;
}
@@ -1168,6 +1280,9 @@ ADCVStatus_t NDPluginCVHelper::getFunctionDescription(ADCVFunction_t function, s
case ADCV_UserDefined:
status = get_user_function_description(inputDesc, outputDesc, description);
break;
+ case ADCV_DistanceCheck:
+ status = get_dist_between_description(inputDesc, outputDesc, description);
+ break;
default:
status = get_default_description(inputDesc, outputDesc, description);
break;
From 622786938f15d61dc1c6954db8d749cbd92220c8 Mon Sep 17 00:00:00 2001
From: jwlodek
Date: Wed, 17 Apr 2019 14:36:48 -0400
Subject: [PATCH 25/83] update docs for R1-1
---
CONTRIBUTING.md | 23 +++++++++++++----------
RELEASE.md | 6 ++++--
adcvApp/adcvSrc/NDPluginCVHelper.cpp | 8 ++++----
docs/index.html | 6 ++++--
docs/manual.html | 16 ++++++++++++++++
5 files changed, 41 insertions(+), 18 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f838dc2..0643e5a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -32,30 +32,33 @@ To add a new CV function there are several files you will need to edit. First, i
Decide which of these sets your new function falls under, and add it to the Input and Output records.
-**Note that for the easiest implementation, it is recommended to only add your function to the last position in function set 3.**
-Next, in the NDPluginCVHelper.h file, change the N_FUNC_3 value to take into account the new number of functions in the CompVisionFunction3 PV, or replace the value for the set you inputted your function into.
-Next, you will need to edit the NDPluginCVHelper.cpp and NDPluginCVHelper.h files. In NDPluginCVHelper.h, find the definition of ADCVFunction_t and add:
+Next, in the `NDPluginCVHelper.h` file, change the `N_FUNC_#` value to take into account the new number of functions in the `CompVisionFunction#` PV you add your function to.
+Next, you will need to edit the `NDPluginCVHelper.cpp` and `NDPluginCVHelper.h` files. In `NDPluginCVHelper.h`, find the definition of `ADCVFunction_t` and add:
```
// Some basic flag types
typedef enum {
ADCV_NoFunction = 0,
- ADCV_EdgeDetectionCanny = 1,
+ ADCV_GaussianBlur = 1,
ADCV_Threshold = 2,
.
.
.
- ADCV_YOURFUNCTION = n,
+ ADCV_YOURFUNCTION = n, <- Your function should be added in the appropriate location
+ .
+ .
+ .
+ ADCV_LastFunction = 15,
} ADCVFunction_t;
```
-where n is the next integer. If you added your function to any PV other than the last position in function set 3, you will need to find which value it should be assigned. NoFunction represents the first PV value in function set 1, and the rest count in order, going through set 1 -> set 2 -> set 3, disregarding the PVs for no function in set 2 and 3. Once you found the correct number add it to the enum, and fix any numbers that have changed. This will add the function to the list of possible functions handled by ADCompVision. Then, add the lines:
+Make sure to add your function type in the appropriate position, this is important for the conversion from PV value to function type. You will need to find which value it should be assigned. `ADCV_NoFunction` represents the first PV value in function set 1, and the rest count in order, going through set 1 -> set 2 -> set 3, disregarding the PVs for no function in set 2 and 3. Once you found the correct number add it to the enum, and fix any numbers that have changed. This will add the function to the list of possible functions handled by ADCompVision. Then, add the lines:
```
ADCVStatus_t YOURFUNCTION(Mat &img, double* inputs, double* outputs);
ADCVStatus_t get_YOURFUNCTION_description(string* inputDesc, string* outputDesc, string* description);
```
in the 'public' portion of the class declaration. You may follow the standard set by the other functions.
-Next, in the NDPluginCVHelper.cpp file, add your new function definitions. They should take the following form:
+Next, in the `NDPluginCVHelper.cpp` file, add your new function definitions. They should take the following form:
**The Wrapper**
```
@@ -121,13 +124,13 @@ ADCVStatus_t NDPluginCVHelper::get_YOURFUNCTION_description(string* inputDesc, s
return status
}
```
-**NOTE** The commenting standard for these helper functions should be followed strictly, as it will allow for the provided python script to generate a manual for operation easily. Once you add the function and write the comment above it appropriately, you may run the createIOmanual.py script in the scripts/ directory with:
+**NOTE** The commenting standard for these helper functions should be followed strictly, as it will allow for the provided python script to generate a manual for operation easily. Once you add the function and write the comment above it appropriately, you may run the `createIOmanual.py` script in the scripts/ directory with:
```
python3 createIOmanual.py
```
This will create a manual (in docs/manual.html) describing the inputs and outputs of each of the functions including your new custom function along with a description of each function as provided in the comments.
-Next, you must edit the 'getFunctionDescription' function in NDPluginCVHelper.cpp. Add a case to the switch statement as follows:
+Next, you must edit the `getFunctionDescription` function in `NDPluginCVHelper.cpp`. Add a case to the switch statement as follows:
```
case ADCV_YOURFUNCTION:
status = get_YOURFUNCTION_description(inputDesc, outputDesc, description);
@@ -135,7 +138,7 @@ case ADCV_YOURFUNCTION:
```
This will allow NDPluginCV to update descriptions for each input and output in real time when you select your function.
-Finally, you need to edit the 'processImage' function in NDPluginCVHelper.cpp. In the switch statement, add a case as follows:
+Finally, you need to edit the `processImage` function in `NDPluginCVHelper.cpp`. In the switch statement, add a case as follows:
```
case ADCV_YOURFUNCTION:
diff --git a/RELEASE.md b/RELEASE.md
index dd28a18..7f50abb 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -9,11 +9,13 @@ Dependencies: ADCompVision requires opencv core, highgui, image processing, and
-## R1-1 (???-March-2019)
+## R1-1 (17-April-2019)
* Computer Vision functions implemented:
* Sharpening filter
* Image subtraction
+ * Image statistics
+ * Distance between objects
* Additional Feature changes
* File saving temporarily removed due to crashing issues over ssh and additional dependency
@@ -26,7 +28,7 @@ Dependencies: ADCompVision requires opencv core, highgui, image processing, and
* Bug where certain PV would cause error at IOC startup
* Fixed Image passthrough to work with any bit depth
* Fixed colorspace of color images passed through
- * Removed code that caused certain compiler warnings
+ * Removed code that caused certain compiler warnings - Cleaner compile
## R1-0 (14-January-2019)
diff --git a/adcvApp/adcvSrc/NDPluginCVHelper.cpp b/adcvApp/adcvSrc/NDPluginCVHelper.cpp
index cecbaa2..1260b48 100644
--- a/adcvApp/adcvSrc/NDPluginCVHelper.cpp
+++ b/adcvApp/adcvSrc/NDPluginCVHelper.cpp
@@ -706,11 +706,11 @@ ADCVStatus_t NDPluginCVHelper::user_function(Mat &img, double* inputs, double* o
* Function that computes bounding boxes between the two largest computed contours in the image,
* checks the distance between them and sends an alarm if they are within a distance threshold.
*
- * @inCount -> 1
- * @inFormat -> [[Distance Threshold (Int)]
+ * @inCount -> 5
+ * @inFormat -> [[Distance Threshold (Int), Blur Kernel Size (Int), Threshold (Int), Apply Blur (Toggle), Pixel Size Threshold (Int)]
*
- * @outCount -> 1
- * @outFormat -> [Is Within Threshold (Binary Int)]
+ * @outCount -> 2
+ * @outFormat -> [Is Within Threshold (Binary Int), Distance in Pixels (Int)]
*/
ADCVStatus_t NDPluginCVHelper::distance_between_ctrs(Mat &img, double* inputs, double* outputs){
const char* functionName = "distance_between_ctrs";
diff --git a/docs/index.html b/docs/index.html
index ef068b7..356da23 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -37,13 +37,15 @@
Release Notes
-
R1-1 (???-March-2019)
+
R1-1 (17-April-2019)
Computer Vision functions implemented:
Sharpening filter
Image subtraction
+
Image statistics
+
Distance between objects
@@ -62,7 +64,7 @@
R1-1 (???-March-2019)
Bug where certain PV would cause error at IOC startup
Fixed Image passthrough to work with any bit depth
Fixed colorspace of color images passed through
-
Removed code that caused certain compiler warnings
+
Removed code that caused certain compiler warnings - Cleaner compile
[Is Within Threshold (Binary Int), Distance in Pixels (Int)]
+
+
@@ -242,6 +254,10 @@
gaussian_blur
simplify creating user defined functions. Simply implement this function and its description function,
and then select 'User Function' in function set 3.
+
Distancebetweencontours
+
Function that computes bounding boxes between the two largest computed contours in the image,
+ checks the distance between them and sends an alarm if they are within a distance threshold.
+