EVERYTHING IS BROKEN (but that's okay)
Having been fighting with the demons of machine learning and statistics for over a week, I'm coming to the definite conclusion that Lalonde & co.'s shadow detection methods do not work on my images. Whatsoever.
Any algorithm I train, be it a Multilayer Neural Net, a Support Vector Machine, a Random Forest, or just simple Logistic Regression, comes out with a high error rate (in the 90th percentile in all tests) and a slightly-better-than-chance rate of classifying edges correctly.
So, I concede defeat. For now...
But that's okay, because I at least know of plenty of reasons why I'm conceding defeat:
Noisy Images: This is the biggest problem, I think. The grain from the webcam images is quite large, and even when applying bilateral filtering and gaussian blur to the images, creates lots of false edges.
Bad Features: Whilst I've tried to generate edge features like Lalonde & co. are doing, there is the possibility that I have misinterpreted their paper. Looking at their source code offers no real help on this, because it's in Matlab and pretty obfuscated. I don't have a good way of detecting whether features are useful or not, bad the attribute selection and other tests in Weka. Weka doesn't think any of the features I try are significant. Again, I think my images have a lot of noise and that plays a major factor.
Too many false examples: 99% of my detected edges are labelled as background. This means any learning algorithm I put the features through is going to be pretty biased towards misclassifying everything as background. To counter this, I've enforced a ratio of 3 times as many background examples as there are shadow, penumbra and object examples. That improved the true positive rates for those classes, but they are still far too low. If I lower the ratio any more, it's going to create more false positives for the other classes.
Too many features / instances: I have, at time of writing, 36 features -- differences and mean values for both sides of an edge, plus the same for the edge normal as a whole, for each of the Hue, Saturation, Value, Red, Green and Blue channels of my images. I have roughly 4,000 edges per image, and over 20,000 edges in total (so 20,000 instances). This gives me huge files (my biggest was 150MB uncompressed, my smallest is 9MB gzipped) which are just comma separated values. My laptop does not like loading these, let alone doing anything with them..! And it's my understanding that too many useless features/statistically irrelevant instances could introduce a bunch of bias into my learning algorithms.
Bad ground truth data -- labelling these images by hand is hard. It's especially difficult to estimate visually where penumbra ends and shadow begins. The penumbra/shadow distinction in my images is probably inaccurate.
Edges are sampled wrong -- One more thing I'm going to try is counting penumbra as shadow, and ignoring object edges; only detecting shadow edges. I also need to ignore all the edges inside a shadow. Right now I'm classifying edges based on where their center point is, but I should be checking either end of the edge as well. If the center point OR one end point is in shadow, the edge could be counted as shadow edge, but if they're ALL in shadow, they're ignored. Same applies to background edges. I will try missing out the object class, but using object edges to classify things as background edges.
Lalonde & co's approach does not suit my data -- They do state in their paper that their approach works for outdoors scenes and only for shadows on the ground. They make the assumption that the images are from high-quality consumer digital cameras which have a lot higher resolution, less ISO noise and less artifacting than frames grabbed from a webcam feed. Their trained data all has shadows that are slightly bluer than their surroundings, due to outdoors lighting and sky colour. They also generate ground probabilities; which I can't do for mine -- my Kondo dataset has the camera angled downwards. Technically, everything is ground. There's no distant horizon or anything. They also are happy to spend several minutes processing a single, static image, which I don't want to do. I want a method that's vaguely realtime (maybe process an image every few seconds) -- which means taking shortcuts. My shadows are all softer, despite having much closer light sources, due to the angle of the lights. The penumbras create lots of wavy edges inside the actual penumbra, and there's also an absence of contours detected on the actual penumbra edge.
I'm still working on this approach, but my deadline for everything is Sunday. Then I'm only allowed to do a little bit of analysis to get some pretty graphs (of things failing), and then write up my report.
I think edges features are probably pretty good for shadows (when they're hard without too much penumbra) -- but there's a fine balance between too many edges and too few edges, for both training and classification. Edge features are good because they can be computed quickly as there's a lot less of them than, say, using sliding windows of pixels for generating features.
I'm also experimenting with a really simple grid-based approach which divides the image into NxN cells. It might be possible to get better features from that... And get at least an approximation of shadow shape. But it will be a lot more granular than if I could get good edges.
It is unfortunate that I haven't got any results worth training a classifier for and testing "in the wild" (so in OpenCV, outside of Weka, using unlabelled new examples from video frames I haven't extracted or ground truthed yet) so far. I think I could speed up my edges approach by coupling it with a simpler approach -- the simple thresholding approaches I wrote at the beginning of my project actually show better results than these networks are currently reporting -- higher accuracy, less false positives. They could be good for filtering out the majority of useless edges in an image / filtering out image regions that definitely aren't shadow.
If I do get something vaguely workable by Sunday, I will test combining a "weak" thresholding classifier with a "strong" (although actually probably weaker, right now) edge/cell classifier.
End of rambling. This is me writing notes to myself.