Template matching is a useful technique. Some common uses include manufacturing as a part of quality control, a way to navigate a mobile robot, or as a way to detect edges in images. But can techniques such as these be useful for data captured from satellites? I am especially interested here in Optical data, but I don’t see why it couldn’t work on active sensors such as Radar datasets.
In its simplest form you will need an image to search and a template image to try and find. Where’s Wally for space data in other words. You tell the computer what to look for and it tries to find it in the image and reports back to you (within the thresholds that you have defined) the matches. Think about looking for a needle in a haystack, or a face in the crowd; this is where template matching is very useful.
Fortunately, OpenCV (hooray) makes this (like edge detection) available to us.
Detecting artificial islands in south eastern Bahrain, using Sentinel-2
This is Bahrain and in the box highlighted in red are some artificial islands. You can read more about them here
I set my self the task of counting these “C shaped islands” using image matching
You can easily see that there are 6 of these “c” shaped islands, so that is my target number. I used the image above as my ‘canvas’ and I clipped out one of the islands as my ‘template’
This is my template image. I had to set the pixels in the bottom right of the image to black so I just had my ‘c’ shaped island. That might be lesson one: get a good template, or as I will suggest later, get good templates!
Use OpenCV, of course!
I adapted the code from here please have a look – it is great, and will save me explaining some of the code below.
Basically, I am just parsing in my canvas (img_rgb), converting it to gray (img_gray), loading in my template (template), running a matchTemplate function, setting a threshold and then drawing a bounding box around the match.
I get this result:
Apparently only one island (remember I am also looking for the other 5). The obvious place to start is to change the threshold. A bit of experimenting and I settle upon a threshold of 0.45 (you have to ‘learn’ your data). My result?
First glance seems quite nice; all the matches have been found. As I want a count of islands I add a counter like this
It returns me the number of islands matched = 339. I had a hunch about the thickness of these yellow bounding boxes! I want that number to be six.
Ultimately I decided one way to address this (and perhaps not the neatest or most efficient solution?) was to append to a list the bounding box cords and then check to see if this already existed and if so skip to next match. I had to add a tolerance (in my case +- 9 pixels – it will be different for each search; I think this variable is best set with the thresholding variable).
My result? 6 islands found!
I did all of this work outside a GIS and bespoke image processing software. It is very nice that OpenCV has these inbuilt functions such as image matching and is certainly useful that I don’t have to be concerned about rotating my ‘template’ to fit my ‘canvas’.
I think it is important with image matching to get a good template that is at an appropriate resolution to the canvas that you plan to use. If you are using Landsat or Sentinel data then the image you are trying to identify needs to be able to be seen, (for example image matching a house will not be a good candidate for this – though I’d be delighted to be proved wrong). I haven’t tried on high resolution satellite imagery, so I don’t know how fast or scalable this code is (a loop within a loop… hmm) – but I think it would be a decent starting point.
Oh, how long did it take this to run?
That seems ok.
Code is on my Github page