如何在自适应阈值处理后清除图像边缘的黑色框架/边界/轮廓

huangapple go评论61阅读模式
英文:

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

问题

我对我的.tif图像应用了自适应高斯阈值处理,但在边缘出现了黑色的边框(轮廓)。不理解为什么会这样,以及如何删除。

非常感谢您的帮助!
附:在 cv2.threshold(img,127,255,cv2.THRESH_BINARY) 之后没有边框。

这是我的原始图像:

原始图像链接

这是我的图像片段(彩色)和高斯阈值处理后的图像(白色和黑色)。图像边缘的黑色轮廓清晰可见。

图片描述链接

我的代码:

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

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

尝试了以下代码(在Stack Overflow上找到),但没有结果:

img = cv2.imread(file_path, 0)

rows, cols = img.shape

cv2.floodFill(img, None, seedPoint=(0, 0), newVal=255, loDiff=1, upDiff=1)  # 填充左上角
cv2.floodFill(img, None, seedPoint=(cols-1, 0), newVal=255, loDiff=1, upDiff=1)  # 填充右上角
cv2.floodFill(img, None, seedPoint=(0, rows-1), newVal=255, loDiff=1, upDiff=1)  # 填充左下角
cv2.floodFill(img, None, seedPoint=(cols-1, rows-1), newVal=255, loDiff=1, upDiff=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

答案1

得分: 1

黑边是由于图像数据中灰度级别之间的急剧变化与白色边距之间的急剧变化而导致的。

为了解决这个问题,我们可以用更接近图像像素的值填充边距,应用adaptiveThreshold,然后恢复边距。

用更接近像素的值填充边距并不那么简单。假设图像相对均匀,我们可以采用以下步骤来覆盖白色边距:

  • 在每个轴上将图像的大小调整为1.5倍(1.5倍是关于sqrt(2)的,适用于45度旋转)。
  • 使用大内核对调整大小的图像进行模糊处理。
  • 裁剪与原始图像相同大小的中心部分。
  • 用调整大小、模糊处理、裁剪后的图像中匹配的像素替换白色边距。

在覆盖边距后,执行adaptiveThreshold,并将边距填充为零。

代码示例:

import cv2
import numpy as np

img = cv2.imread('ndsi.tiff')

# 假设边距是白色的,图像的其他部分几乎没有白色像素。
# 创建一个掩码,其中像素是白色的为True,否则为False。
mask = np.all(img != 255, axis=-1).astype(np.uint8)*255

img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换为灰度图像。

# 应用形态学闭运算以删除图像内部的小白色部分。
# 注意,为了获得更好的掩码,我们可以根据Micka的建议找到minAreaRect。
# mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8))

# mask = cv2.erode(mask, np.ones((5, 5), np.uint8))  # 腐蚀掩码,因为有太多伪影

# 在每个轴上将图像的大小调整为1.5倍
resized_img = cv2.resize(img, (img.shape[1]*3//2, img.shape[0]*3//2))

# 使用大内核对调整大小的图像进行模糊处理
resized_img_blurred = cv2.GaussianBlur(resized_img, (51, 51), 50)

# 裁剪与原始图像相同大小的中心部分
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]  # 用调整大小的模糊处理、裁剪后的图像替换白色边距。

# 在tmp_img上应用阈值
th = cv2.adaptiveThreshold(tmp_img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)

# 从th中去除边距
th[mask == 0] = 0

# 用于测试的显示图像:
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)))

结果:

如何在自适应阈值处理后清除图像边缘的黑色框架/边界/轮廓

tmp_img

如何在自适应阈值处理后清除图像边缘的黑色框架/边界/轮廓

英文:

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:
如何在自适应阈值处理后清除图像边缘的黑色框架/边界/轮廓

tmp_img:
如何在自适应阈值处理后清除图像边缘的黑色框架/边界/轮廓

huangapple
  • 本文由 发表于 2023年1月9日 00:33:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75049505.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定