<jupyter_start><jupyter_text>Detect ships in Planet dataThis notebook demonstrates how to detect and count objects in satellite imagery using algorithms from Python's scikit-image library. In this example, we'll look for ships in a small area in the San Francisco Bay and generate a PNG of each ship with an outline around it.  Input ParametersThis is a sample image that was generated using the Clip and Ship API. To test this with your own image, replace the parameters below.<jupyter_code>sample_data_file_name = 'data/1056417_2017-03-08_RE3_3A_Visual_clip.tif'<jupyter_output><empty_output><jupyter_text>Original imageBelow is a predefined image that has been clipped from the Planet API using [Clip and Ship](https://www.planet.com/docs/reference/clips-api/). This is the image that we are going to detect ships in.<jupyter_code>import skimage.io
from IPython.display import Image

# Read image into scimage package
img = skimage.io.imread(sample_data_file_name)
skimage.io.imsave('output/original.png', img)

# Display original image
display(Image(filename='output/original.png'))<jupyter_output><empty_output><jupyter_text>Run the ship detection algorithm<jupyter_code>import json
from osgeo import gdal, osr
import numpy
from skimage.segmentation import felzenszwalb
from skimage.segmentation import mark_boundaries
from skimage.measure import regionprops

# Prepare result structure
result = {
    "ship_count": 0,
    "ships": []
}

# Open image with gdal
ds = gdal.Open(sample_data_file_name)
xoff, a, b, yoff, d, e = ds.GetGeoTransform()

# Get projection information from source image
ds_proj = ds.GetProjectionRef()
ds_srs = osr.SpatialReference(ds_proj)

# Get the source image's geographic coordinate system (the 'GEOGCS' node of ds_srs)
geogcs = ds_srs.CloneGeogCS()

# Set up a transformation between projected coordinates (x, y) & geographic coordinates (lat, lon)
transform = osr.CoordinateTransformation(ds_srs, geogcs)

# Convert multi-channel image it into red, green and blueb[, alpha] channels 
red, green, blue, alpha = numpy.rollaxis(numpy.array(img), axis=-1)

# Mask: threshold + stops canny detecting image boundary edges
mask = red > 75

# Create mask for edge detection
skimage.io.imsave('output/mask.png', mask * 255)

# Use Felzenszwalb algo to find segements
segments_fz = felzenszwalb(numpy.dstack((mask, mask, mask)),
                               scale=5000,
                               sigma=3.1,
                               min_size=25) 

# Build labeled mask to show where ships were dectected
segmented_img = mark_boundaries(mask, segments_fz)
skimage.io.imsave('output/mask_labeled.png', segmented_img)

# Count ships and save image of each boat clipped from masked image
for idx, ship in enumerate(regionprops(segments_fz)):
    
    # If area matches that of a stanard ship, count it
    if (ship.area >= 300 and ship.area <= 10000):
        
        # Incrment count
        result['ship_count'] += 1
        
        # Create ship thumbnail
        x, y = (int(numpy.average([ship.bbox[0],
                                ship.bbox[2]])),
                                int(numpy.average([ship.bbox[1],
                                ship.bbox[3]])))
        sx, ex = max(x - 35, 0), min(x + 35, img.shape[0] - 1)
        sy, ey = max(y - 35, 0), min(y + 35, img.shape[1] - 1)
        img_ship = img[sx:ex, sy:ey]
        skimage.io.imsave('output/ship-%s.png' % str(idx + 1), img_ship)

        # Get global coordinates from pixel x, y coords
        projected_x = a * y + b * x + xoff
        projected_y = d * y + e * x + yoff
        
        # Transform from projected x, y to geographic lat, lng
        (lat, lng, elev) = transform.TransformPoint(projected_x, projected_y)
        
        # Add ship to results cluster
        result["ships"].append({
            "id": idx + 1,
            "lat": lat,
            "lng": lng
        })

# Display results
print(json.dumps(result, indent=2))

#Display mask used for ship detection.
display(Image(filename='output/mask.png'))

# Display labled mask where we detected ships
display(Image(filename='output/mask_labeled.png'))

# Display each individual ship cropped out of the original image
for idx,ship in enumerate(result['ships']):
    print("Ship "+ str(idx + 1)) 
    display(Image(filename='output/ship-' + str(idx + 1) + '.png'))<jupyter_output>{
  "ship_count": 4,
  "ships": [
    {
      "id": 1,
      "lat": -122.34490450858347,
      "lng": 37.73152684385154
    },
    {
      "id": 2,
      "lat": -122.33509827951244,
      "lng": 37.730390360282136
    },
    {
      "id": 3,
      "lat": -122.32727531892921,
      "lng": 37.72957985708844
    },
    {
      "id": 4,
      "lat": -122.33201645440774,
      "lng": 37.71973740040979
    }
  ]
}
{'fraction_non_alphanumeric': 0.1068062827225131, 'fraction_numerical': 0.04230366492146597, 'mean_word_length': 3.0235888795282224, 'pattern_counts': {'":': 19, '<': 13, '<?xml version=': 0, '>': 14, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '287368', 'license': 'Apache-2.0', 'n_tokens_mistral': 1677, 'n_tokens_neox': 1516, 'n_words': 456, 'path': 'jupyter-notebooks/ship-detector/01_ship_detector.ipynb', 'repo_name': 'gitter-badger/notebooks-2', 'size': '4775'}