1

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

Carrie
  • 13
  • 3
  • 1
    Can you please post the original image and not a screenshot of the original image (try to post the image in PNG format, if it's too large, try posting a downscaled PNG image)? Do you have the original image before rotation? – Rotem Jan 08 '23 at 17:26
  • @Rotem This image is not a screenshot. I used - plt.savefig("myfile.png") . I didn't do the rotation, this is the original satellite image (combination of two bands). . Ok will try downscaling (sorry, my first question here, have difficulties with downloading) =( – Carrie Jan 08 '23 at 18:56
  • Are you able to theshold away all the not wanted regions like background and axes etc.? Afterwards use minAreaRect to fet the whole rotatee rectangle part, including all the stuff that additionally was masked away. – Micka Jan 08 '23 at 20:02
  • @Carrie can you post the original image instead of the figure? Use cv2.imwrite('My.png', img), or better: `img = cv2.imread("My.tiff", cv2.IMREAD_UNCHANGED)` and `cv2.imwrite('My.png', img)`. In case the pixel format is RGBA, and the background (corners) are transparent, it may help. – Rotem Jan 08 '23 at 20:20
  • @Rotem Look please, I resized my image cv2.resize(img, dim, interpolation = cv2.INTER_AREA) and applied cv2.imwrite() . My new image - after words "This is my original image:" . I hope everything is correct now. – Carrie Jan 08 '23 at 21:40
  • 1
    It's still a JPEG due to a size limit. Use `cv2.INTER_NEAREST`, and resize to 512x512 (or share the original Tiff image using other site). – Rotem Jan 08 '23 at 21:48

1 Answers1

1

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:

  • Resize the image by a factor of 1.5 in each axis (1.5 factor is about sqrt(2) that applies 45 degree rotation).
  • Blur the resized image with a large kernel.
  • Crop the center that is the same size as the original image.
  • Replace the white margins with the matching pixels in the resized, blurred cropped image.

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

Rotem
  • 30,366
  • 4
  • 32
  • 65
  • Thank you so much for your detailed explanation!! I couldn’t have solved this problem without your help! – Carrie Jan 09 '23 at 06:41