The Canny Edge algorithm\cite{OpenCV_Canny} determines which pixels are ``edge'' pixels through a series of steps. The algorithm applies the Sobel operator in the x and y directions using \var{KERNELSIZE} for the size of the kernel. The result of this gives the gradient strength and direction. The direction is rounded to 0, 45, 90 or 135 degrees. Non-maximum suppression is then used to remove any pixels not considered to be part of an edge. The pixels left are then put through the hysteresis step. If the gradient of the pixel is higher than the upper threshold (in our algorithm denoted by \var{LOWTHRESHOLD*RATIO}) then the pixel is accepted as an edge. If it is below the lower threshold (i.e. \var{LOWTHRESHOLD}) then the pixel is disregarded. The remaining pixels are removed unless that is connected to a pixel above the upper threshold (Canny Edge Detector). The defined values in the header file can be altered to improve accuracy.
-The \funct{CannyThreshold} function fills the \type{CvMat} \var{g_edges} structure with the current image edge (i.e. an image containing only pixels considering to be edges, see Appendix \ref{appendix_imageedge} ). The code then finds the location of the line. It does this by sampling a number of rows, determined by the number of samples and the height of the image, finding the pixel/s in the row considered to be an edge. The algorithm then takes the average position of these pixels. The average position over all rows sampled then determines the actual edge position. The rows sampled are evenly spaced over the height of the image. If a row does not contain an edge, then it will not be included in the average. If a blank image goes through, or the algorithm has a low number of samples and does not pick up an edge, then the function will return false and the data point will not be recorded.
+The \funct{CannyThreshold} function fills the \type{CvMat} \var{g_edges} structure with the current image edge (i.e. an image containing only pixels considering to be edges, see Figure \ref{canny_demo} (C-F)). The code then finds the location of the line. It does this by sampling a number of rows, determined by the number of samples and the height of the image, finding the pixel/s in the row considered to be an edge. The algorithm then takes the average position of these pixels. The average position over all rows sampled then determines the actual edge position. The rows sampled are evenly spaced over the height of the image. If a row does not contain an edge, then it will not be included in the average. If a blank image goes through, or the algorithm has a low number of samples and does not pick up an edge, then the function will return false and the data point will not be recorded.
Once the edge is found, we will either return the position of the edge, if the \var{DIL_POS} ID is set. It needs to be noted that this will only show the change in position of one side of the can. If the \var{DIL_DIFF} ID is set then the value will be set to the difference between the current position and the last position, multiplied by \var{SCALE} and 2. We need to multiply by 2 as we are only measuring the change in width to one side of the can, however we must assume that the expansion is symmetrical. The scale will be used to convert from pixels to $\mu$m (or a more suitable scale). Currently the scale is set to 1, as the dilatometer has not been calibrated, thus we are only measuring the rate of change of pixels (which is arbitrary). The static variable, \var{lastPosition}, is then set to determine the next change in size. If the difference is negative, then the can is being compressed or is being depressurized.
The rate of expansion can then be determined from the data set. As the system does not have a fixed refresh rate, however each data point is time-stamped. If the data is the edge position, then plotting the derivative of the time graph will show the rate of expansion over time.
Originally I designed the algorithm to find the edge of the can via the pixel thresholds. By finding the average position of the pixels below a certain threshold (as ideally you would have a dark can on a light background to create a contrast for the edge). This would already give a fairly inaccurate result, as it assumes a relatively sharp intensity gradient. Even with little noise the system would have accuracy issues.
-To increase the accuracy in finding the edge, I considered the Canny Edge theorem. I wrote my algorithm to find all points above a certain threshold and take the average of these, considering this as an edge. I then scanned through the rest of the image until the next edge was found and do the same. The width of the can is found by taking the difference of the two locations. I also wrote an algorithm to generate these edges so I can test the algorithm. The function (\funct{Dilatometer_TestImage}/, which is still located within \gitref{server}{sensors/dilatometer.c}) generated two edges, with an amount of noise. The edges were created by taking an exponential decay around the edge and adding (and subtracting) a random noise from the expected decay. The edges where then moved outwards using a for loop. The results can be seen in Figure \ref{canny_edges.png}. From the graphs (Figure \ref{}) it can be seen how effective the algorithm was for a system with negligible noise, as it gave negligible percentage error. However with increasing levels of noise we notice a considerable increase in inaccuracy (Figure \ref{canny_edges_noise.png}).
+To increase the accuracy in finding the edge, I considered the Canny Edge theorem. I wrote my algorithm to find all points above a certain threshold and take the average of these, considering this as an edge. I then scanned through the rest of the image until the next edge was found and do the same. The width of the can is found by taking the difference of the two locations. I also wrote an algorithm to generate these edges so I can test the algorithm. The function (\funct{Dilatometer_TestImage}/, which is still located within \gitref{server}{sensors/dilatometer.c}) generated two edges, with an amount of noise. The edges were created by taking an exponential decay around the edge and adding (and subtracting) a random noise from the expected decay. The edges where then moved outwards using a for loop. From Figure \ref{canny_edges.png}, it can be seen how effective the algorithm was for a system with negligible noise, as it gave negligible percentage error. However with increasing levels of noise we notice a considerable increase in inaccuracy (Figure \ref{canny_edges_noise.png}).
\label{canny_edges_noise.png}
\end{figure}
-After the Sensors Team relayed that they were now attaching something to the can in order to measure the change position, I decided to simply stick with the Canny Edge algorithm and implement something similar to what I had in my previous testing. The images in Figure \ref{canny_demo} shows the progression of the image through the algorithm. Figure \ref{canny_demo} A shows the original image, whereas \ref{canny_demo}B shows the blurred (with a BLUR value of 5) gray scale image. Whereas figure \ref{canny_demo}C shows the image after going through the Canny Edge algorithm with a low threshold of 35. Figures \ref{canny_demo}D and \ref{canny_demo}E both have the same input image, however different input values. It can be seen how tweaking the values can remove outliers, as figure \ref{canny_demo}E is skewed to the right due to the outliers. From figure \ref{canny_demo}F it can be seen that despite there being no points in the edge in the top half of the image, the edge has still been accurately determined.
+After the Sensors Team relayed that they were now attaching something to the can in order to measure the change position, I decided to simply stick with the Canny Edge algorithm and implement something similar to what I had in my previous testing. The images in Figure \ref{canny_demo} shows the progression of the image through the algorithm. Figure \ref{canny_demo} A shows the original image, whereas \ref{canny_demo}B shows the blurred (with a BLUR value of 5) gray scale image. Whereas Figure \ref{canny_demo}C shows the image after going through the Canny Edge algorithm with a low threshold of 35. Figures \ref{canny_demo}D and \ref{canny_demo}E both have the same input image, however different input values. It can be seen how tweaking the values can remove outliers, as Figure \ref{canny_demo}E is skewed to the right due to the outliers. From Figure \ref{canny_demo}F it can be seen that despite there being no points in the edge in the top half of the image, the edge has still been accurately determined.
The testing done shows that given a rough edge with few outliers an edge can be determined, however there is an obvious degree of inaccuracy the greater the variance of the edge. The best solution to this however does not lie in software. If an edge was used that was straight even at that magnification with a good contrast then the results would be much more accurate (i.e. the accuracy of the dilatometer is currently more dependent on the object used than the software).
\begin{tabular}{cc}
\includegraphics[width=0.4\textwidth]{figures/dilatometer_test.jpg} A &
- \includegraphics[width=0.4\textwidth]{figures/dilatometer_test.jpg} B \\
+ \includegraphics[width=0.4\textwidth]{figures/dilatometer_test2.jpg} B \\
\includegraphics[width=0.4\textwidth]{figures/dila_blur7thresh36.png} C &
\includegraphics[width=0.4\textwidth]{figures/dila_blur5thresh30.png} D \\
\includegraphics[width=0.4\textwidth]{figures/dila_blur9thresh35.png} E &