pythonopencvblobarcgisresampling

open cv cv2.imread a grayscale image pixel values


I am attempting to load a grayscale image using cv2.imread for further blob extraction. To start I have an image (as seen below) for which black pixels have values (typically between 0 and 1) and white pixels have value of 0.

enter image description here

I would like to resample this image to binary 0 (white pixels) and 1(black pixels) in order to perform blob extraction on it using cv2. My resultant blob extraction returns 0 instances of blobs however, even when I generalize the search parameters.

Upon looking into the image histograms, I found that I did not in fact have a binary image. Below I will include the code used to read in, reclassify, set blob parameters, and attempt to detect blobs.

link to image: tif_file

reclassification:

import cv2
import numpy as np
import os
from osgeo import gdal
import matplotlib.pyplot as plt
from rasterio.plot import show
import skimage.io

driver = gdal.GetDriverByName('GTiff')
file = gdal.Open("tif_folder/Clip_depth_sink.tif")
band = file.GetRasterBand(1)
lista = band.ReadAsArray()

# reclassification
for j in  range(file.RasterXSize):
    for i in  range(file.RasterYSize):
        if lista[i,j] == 0:
            lista[i,j] = 0
        elif lista[i,j] != 0:
            lista[i,j] = 1
        else:
            lista[i,j] = 2

## create new file
binary_sinks = driver.Create('tif_folder\\clipped_binary_sinks.tif', file.RasterXSize , file.RasterYSize , 1)
binary_sinks.GetRasterBand(1).WriteArray(lista)

# spatial ref system
proj = file.GetProjection()
georef = file.GetGeoTransform()
binary_sinks.SetProjection(proj)
binary_sinks.SetGeoTransform(georef)
binary_sinks.FlushCache()

Reclassified Image Histogram:

image = cv2.imread('tif_folder\\clipped_binary_sinks.tif', -1)

plt.hist(image, bins=10, range=(-1,3))

enter image description here

Blob Detection:

image = cv2.imread('tif_folder\\clipped_binary_sinks.tif',-1)

plt.hist(image, bins=10, range=(-1,3))

#set blob parameters to look for
params = cv2.SimpleBlobDetector_Params()

params.filterByArea = True
params.minArea = 9
params.maxArea = 1000

params.filterByCircularity = True
params.minCircularity = 0.5

#create the detector out of the parameters
detector = cv2.SimpleBlobDetector_create(params)

#extract the blobs from the image
keypoints = detector.detect(image)
print(len(keypoints))

A few things confuse me about this. For instance, though the image pixel values to fall around values of 0 and 1 as they should after the reclassification, they seem to fall into bins which are not exactly equal to 0 and 1 as we can see in the histogram. As I said earlier, no blobs were detected by open cv, this might make sense because although adjacent pixels are close in value, they are slightly off according to the histogram.

Are there better ways of reclassifying an image to be binary that would solve this issue? Is there another issue that I am missing which is causing blob detection not to be feasible?

Thanks in advance!


Solution

  • You can classify your image more simply like this:

    import numpy as np
    import cv2
    
    # Load float image
    im = cv2.imread('Clip_depth_sink.tif', cv2.IMREAD_UNCHANGED)
    
    # Make solid black classified image, uint8 is plenty for 3 values
    classified = np.zeros(im.shape, np.uint8)
    
    # Set everything above a low threshold to 127
    classified[im>0.001] = 127
    
    # Set everything above a high threshold to 255
    classified[im>0.999] = 255
    
    # Count pixels in each class
    print(np.unique(classified, return_counts=True))
    
    # Save result
    cv2.imwrite('result.png', classified)
    

    Output

    (array([  0, 127, 255], dtype=uint8), array([3647448,  131186,    1878]))
    

    meaning there are 3647448 black pixels (0), 131186 mid-grey (127) and 1878 white (255) pixels

    enter image description here


    Note that you can simply pass the inverse image to your blob detector by putting a tilde in front:

    blobs = BlobDetector(~classified)