从阈值图像中去除噪声opencv python

wtlkbnrh  于 2022-11-15  发布在  Python
关注(0)|答案(4)|浏览(182)

我试着在图像中得到盒子的角。下面是示例图像,它们的阈值结果,右边箭头后面是我需要的结果。你可能已经看到过这些图像,因为我用这些图像来回答我的松弛问题。

下面的代码允许我到达中间的图像。

import cv2
import numpy as np

img_file = 'C:/Users/box.jpg'
img = cv2.imread(img_file, cv2.IMREAD_COLOR)
img = cv2.blur(img, (5, 5))

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)

thresh0 = cv2.adaptiveThreshold(s, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
thresh1 = cv2.adaptiveThreshold(v, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
thresh2 = cv2.adaptiveThreshold(v, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
thresh = cv2.bitwise_or(thresh0, thresh1)

cv2.imshow('Image-thresh0', thresh0)
cv2.waitKey(0)
cv2.imshow('Image-thresh1', thresh1)
cv2.waitKey(0)
cv2.imshow('Image-thresh2', thresh2)
cv2.waitKey(0)

在opencv中有没有什么方法可以帮我做到这一点。我尝试了膨胀cv2.dilate()和腐 eclipse cv2.erode(),但它在我的情况下不工作。或者如果没有,那么有什么可以替代的方法来做它?谢谢
谨慎版本的图像......左侧为低阈值,右侧为高阈值

cnjp1d6j

cnjp1d6j1#

下面是@dhanushka方法的python实现

import cv2
import numpy as np

# load color image
im = cv2.imread('input.jpg')

# smooth the image with alternative closing and opening
# with an enlarging kernel
morph = im.copy()

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))

# take morphological gradient
gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel)

# split the gradient image into channels
image_channels = np.split(np.asarray(gradient_image), 3, axis=2)

channel_height, channel_width, _ = image_channels[0].shape

# apply Otsu threshold to each channel
for i in range(0, 3):
    _, image_channels[i] = cv2.threshold(~image_channels[i], 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY)
    image_channels[i] = np.reshape(image_channels[i], newshape=(channel_height, channel_width, 1))

# merge the channels
image_channels = np.concatenate((image_channels[0], image_channels[1], image_channels[2]), axis=2)

# save the denoised image
cv2.imwrite('output.jpg', image_channels)

如果您处理的图像是发票(或在白色背景上有大量文本),上述代码不会给予好的结果。为了在此类图像上获得好的结果,请删除

gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel)

并将morph obj传递给split函数,并删除for循环内的~符号

yqyhoc1h

yqyhoc1h2#

你可以通过使用一个放大的结构元素来应用形态学的闭合和打开操作,在一定程度上平滑图像。
第一页
然后取图像的形态梯度。
第一次
然后对每个通道应用大津阈值,并合并这些通道。
第一次
如果你的图片尺寸不同(更大),你可能需要修改代码的一些参数,或者把图片的大小调整到这里使用的大小。代码是c++,但是移植到python并不难。

/* load color image */
Mat im = imread(INPUT_FOLDER_PATH + string("2.jpg"));
/* 
smooth the image with alternative closing and opening
with an enlarging kernel
*/
Mat morph = im.clone();
for (int r = 1; r < 4; r++)
{
    Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(2*r+1, 2*r+1));
    morphologyEx(morph, morph, CV_MOP_CLOSE, kernel);
    morphologyEx(morph, morph, CV_MOP_OPEN, kernel);
}
/* take morphological gradient */
Mat mgrad;
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
morphologyEx(morph, mgrad, CV_MOP_GRADIENT, kernel);

Mat ch[3], merged;
/* split the gradient image into channels */
split(mgrad, ch);
/* apply Otsu threshold to each channel */
threshold(ch[0], ch[0], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
threshold(ch[1], ch[1], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
threshold(ch[2], ch[2], 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
/* merge the channels */
merge(ch, 3, merged);
kb5ga3dv

kb5ga3dv3#

不确定该解决方案的鲁棒性如何,但想法很简单。框的边缘应该比那些图像上的所有其他高频更明显。因此,使用一些基本的预处理应该允许强调它们。
我用你的代码做了一个原型,但是轮廓查找并不一定是正确的路径。也很抱歉迭代反锐化遮罩-没有时间调整参数。

import cv2
import numpy as np

def unsharp_mask(img, blur_size = (9,9), imgWeight = 1.5, gaussianWeight = -0.5):
    gaussian = cv2.GaussianBlur(img, (5,5), 0)
    return cv2.addWeighted(img, imgWeight, gaussian, gaussianWeight, 0)

img_file = 'box.png'
img = cv2.imread(img_file, cv2.IMREAD_COLOR)
img = cv2.blur(img, (5, 5))
img = unsharp_mask(img)
img = unsharp_mask(img)
img = unsharp_mask(img)

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)

thresh = cv2.adaptiveThreshold(s, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
_, contours, heirarchy = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = sorted(contours, key = cv2.contourArea, reverse = True)
#for cnt in cnts:
canvas_for_contours = thresh.copy()
cv2.drawContours(thresh, cnts[:-1], 0, (0,255,0), 3)
cv2.drawContours(canvas_for_contours, contours, 0, (0,255,0), 3)
cv2.imshow('Result', canvas_for_contours - thresh)
cv2.imwrite("result.jpg", canvas_for_contours - thresh)
cv2.waitKey(0)
anauzrmj

anauzrmj4#

方法1:使用人工智能模型

总是尝试图像分割模型如果可行到你的项目,鲁棒的模型将工作更好在一个更宽的域比任何阈值技术.例如Rembg,尝试在线在一个Huggingface space
结果如下:
第一次

方法二:

几乎与其他答案相似,但采用了另一种方法。
1.我们使用cv2.bilateralFilter,它类似于photoshop的表面模糊,read more,而不是关闭和打开来模糊“噪声

im = cv2.imread('1.png')
blur = cv2.bilateralFilter(im,21,75,75)

第一次
1.用sobel滤波器寻找边缘

from skimage.filters import sobel
gray = cv2.cvtColor(blur,cv2.COLOR_BGR2GRAY)
mm = sobel(gray)
mm = ((mm/mm.max())*255).astype('uint8')


指令集
1.应用阈值,我在这里使用Sauvola Thresholding

from skimage.filters import threshold_sauvola

mm2 = np.invert(mm)
thresh_sauvola = threshold_sauvola(mm2, window_size=51)
th = mm2 < thresh_sauvola

1.扩张和填充孔:

def fill_hole(input_mask):
  h, w = input_mask.shape
  canvas = np.zeros((h + 2, w + 2), np.uint8)
  canvas[1:h + 1, 1:w + 1] = input_mask.copy()
  mask = np.zeros((h + 4, w + 4), np.uint8)
  cv2.floodFill(canvas, mask, (0, 0), 1)
  canvas = canvas[1:h + 1, 1:w + 1].astype(np.bool)

  return ~canvas | input_mask

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
th2 =cv2.morphologyEx((th*255).astype('uint8'), cv2.MORPH_DILATE, kernel) 
filled = fill_hole(th2==255)


指令集

相关问题