pythonopencvthresholdimage-thresholdingadaptive-threshold

How to clean (delete) a black frame/boundaries/countour at the edges of the image after adaptive thresholding


I applied adaptive gaussian thresholding to my .tif image, but the black frame (contour) on the edges was created. Can't understand why and how to delete.

I would be very grateful for your help! p.s. After cv2.threshold(img,127,255,cv2.THRESH_BINARY) there is no frame.

This is my original image:

https://drive.google.com/file/d/1DfdmQQ9AS-U2SXtyJzU94oYsLLSUmV7N/view?usp=share_link

This is fragment of my image (colored) and after gaussian thresholding (white and black). The black countour on the edge of the image is clearly visible. enter image description here

My code:

img = cv2.imread(" My.tiff", 0)

th = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY,115,2)

Tried this (found on the Stack overflow), but no results:

img = cv2.imread(file_path, 0)

rows, cols = img.shape

cv2.floodFill(img, None, seedPoint=(0, 0), newVal=255, loDiff=1, upDiff=1)  # Fill the top left corner.
cv2.floodFill(img, None, seedPoint=(cols-1, 0), newVal=255, loDiff=1, upDiff=1)  # Fill the top right corner.
cv2.floodFill(img, None, seedPoint=(0, rows-1), newVal=255, loDiff=1, upDiff=1)  # Fill the bottop left corner.
cv2.floodFill(img, None, seedPoint=(cols-1, rows-1), newVal=255, loDiff=1, upDiff=1)  # Fill the bottom right corner.

My image after adaptive gaussian thresholding (thresholding is ok..but why the black border was created and how to remove it, unfortunately, can't understand): enter image description here


Solution

  • The black edge is a result of the steep change in gray levels between the image data, and the white margins.

    For fixing the issue, we may fill the margins with values that are closer to the pixels of the image, apply adaptiveThreshold, and restore the margins.

    Filling the margins with values that are closer to the pixels is not so simple.
    Assuming the image is relatively homogeneous we may apply the following stages for covering the white margins:

    After covering the margins, execute adaptiveThreshold, and fill the margins with zeros.


    Code sample:

    import cv2
    import numpy as np
    
    img = cv2.imread('ndsi.tiff')
    
    # Assume the margins are white, and there are very few white pixels in the other parts of the image.
    # Create a mask with True where pixel are white and False otherwise.
    mask = np.all(img != 255, axis=-1).astype(np.uint8)*255
    
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # Convert to grayscale.
    
    # Apply morphological closing for removing small white parts inside the image.
    # Note for getting a better mask, we may find minAreaRect as suggested by Micka
    #mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8))
    
    
    #mask = cv2.erode(mask, np.ones((5, 5), np.uint8))  # Erode the mask, because there are too many artifacts
    
    # Resize the image by a factor of 1.5 in each axis
    resized_img = cv2.resize(img, (img.shape[1]*3//2, img.shape[0]*3//2))
    
    # Blur with large kernel
    resized_img_blurred = cv2.GaussianBlur(resized_img, (51, 51), 50)
    
    # Crop the center that is the same size as the original image.
    center_img_blurred = resized_img_blurred[(resized_img.shape[0] - img.shape[0])//2:(resized_img.shape[0] + img.shape[0])//2, (resized_img.shape[1] - img.shape[1])//2:(resized_img.shape[1] + img.shape[1])//2]
    
    tmp_img = img.copy()
    tmp_img[mask==0] = center_img_blurred[mask==0]  # Replace white margins with resized blurred image.
    
    # Apply the threshold on tmp_img 
    th = cv2.adaptiveThreshold(tmp_img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
    
    # Remove the margins from th
    th[mask == 0] = 0
    
    # Show images for testing:
    cv2.imshow('mask', cv2.resize(mask, (1024, 1024)))
    cv2.imshow('center_img_blurred', cv2.resize(center_img_blurred, (1024, 1024)))
    cv2.imshow('tmp_img', cv2.resize(tmp_img, (1024, 1024)))
    cv2.imshow('th', cv2.resize(th, (1024, 1024)))
    cv2.waitKey()
    cv2.destroyAllWindows()
    
    cv2.imwrite('tmp_img.jpg', cv2.resize(tmp_img, (1024, 1024)))
    cv2.imwrite('th.png', cv2.resize(th, (1024, 1024)))
    

    Result:
    enter image description here

    tmp_img:
    enter image description here