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.
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))
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!
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
Note that you can simply pass the inverse image to your blob detector by putting a tilde in front:
blobs = BlobDetector(~classified)