简体   繁体   English

使用 OpenCv 的阈值?

[英]Threshold using OpenCv?

As the questions states, I want to apply a two-way Adaptive Thresholding technique to my image.正如问题所述,我想对我的图像应用双向自适应阈值技术。 That is to say, I want to find each pixel value in the neighborhood and set it to 255 if it is less than or greater than the mean of the neighborhood minus a constant c.也就是说,我想找到邻域中的每个像素值,如果小于或大于邻域的均值减去常数c,则将其设置为255。

Take this image, for example, as the neighborhood of pixels.以这个图像为例,作为像素的邻域。 The desired pixel areas to keep are the darker areas on the third and sixth squares' upper-half (from left-to-right and top-to-bottom), as well as the eight and twelve squares' upper-half.需要保留的像素区域是第三和第六个方块上半部分(从左到右和从上到下)以及第八和十二个方块的上半部分的较暗区域。

Obviously, this all depends on the set constant value, but ideally areas that are significantly different than the mean pixel value of the neighborhood will be kept.显然,这一切都取决于设置的常数值,但理想情况下,与邻域的平均像素值显着不同的区域将被保留。 I can worry about the tuning myself though.不过,我可以自己担心调音。

在此处输入图片说明

Your question and comment are contradictory: Keep everything (significantly) brighter/darker than the mean (+/- constant) of the neighbourhood (question) vs. keep everything within mean +/- constant (comment).您的问题和评论是相互矛盾的:保持一切(显着)比邻域(问题)的平均值(+/- 常数)更亮/更暗,而将所有东西保持在平均值 +/- 不变(评论)内。 I assume the first one to be the correct, and I'll try to give an answer.我假设第一个是正确的,我会尝试给出答案。

Using cv2.adaptiveThreshold is certainly useful;使用cv2.adaptiveThreshold当然很有用; parameterization might be tricky, especially given the example image.参数化可能很棘手,尤其是考虑到示例图像。 First, let's have a look at the output:首先,让我们看一下输出:

输出

We see, that the intensity value range in the given image is small.我们看到,给定图像中的强度值范围很小。 The upper-halfs of the third and sixth' squares don't really differ from their neighbourhood.第三个和第六个'正方形的上半部分与他们的邻居并没有真正的不同。 It's quite unlikely to find a proper difference there.不太可能在那里找到适当的差异。 The upper-halfs of squares #8 and #12 (or also the lower-half of square #10) are more likely to be found.更容易找到方格#8 和#12 的上半部分(或者还有#10 方格的下半部分)。

Top row now shows some more "global" parameters ( blocksize = 151 , c = 25 ), bottom row more "local" parameters ( blocksize = 51 , c = 5 ).顶行现在显示更多“全局”参数( blocksize = 151 , c = 25 ),底行显示更多“本地”参数( blocksize = 51 , c = 5 )。 Middle column is everything darker than the neighbourhood (with respect to the paramters), right column is everything brighter than the neighbourhood.中间列是比邻域更暗的所有东西(就参数而言),右列是比邻域更亮的所有东西。 We see, in the more "global" case, we get the proper upper-halfs, but there are mostly no "significant" darker areas.我们看到,在更“全局”的情况下,我们得到了适当的上半部分,但大多没有“显着”的较暗区域。 Looking, at the more "local" case, we see some darker areas, but we won't find the complete upper-/lower-halfs in question.看,在更“局部”的情况下,我们看到一些较暗的区域,但我们不会找到完整的上半部分/下半部分。 That's just because how the different triangles are arranged.那只是因为不同的三角形是如何排列的。

On the technical side: You need two calls of cv2.adaptiveThreshold , one using the cv2.THRESH_BINARY_INV mode to find everything darker and one using the cv2.THRESH_BINARY mode to find everything brighter.在技​​术方面:您需要两次调用cv2.adaptiveThreshold ,一次使用cv2.THRESH_BINARY_INV模式查找更暗的所有内容,另一次使用cv2.THRESH_BINARY模式查找更亮的所有内容。 Also, you have to provide c or -c for the two different cases.此外,您必须为两种不同的情况提供c-c

Here's the full code:这是完整的代码:

import cv2
from matplotlib import pyplot as plt
from skimage import io          # Only needed for web grabbing images

plt.figure(1, figsize=(15, 10))

img = cv2.cvtColor(io.imread('https://i.stack.imgur.com/dA1Vt.png'), cv2.COLOR_RGB2GRAY)

plt.subplot(2, 3, 1), plt.imshow(img, cmap='gray'), plt.colorbar()

# More "global" parameters
bs = 151
c = 25
img_le = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, bs, c)
img_gt = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, bs, -c)
plt.subplot(2, 3, 2), plt.imshow(img_le, cmap='gray')
plt.subplot(2, 3, 3), plt.imshow(img_gt, cmap='gray')

# More "local" parameters
bs = 51
c = 5
img_le = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, bs, c)
img_gt = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, bs, -c)
plt.subplot(2, 3, 5), plt.imshow(img_le, cmap='gray')
plt.subplot(2, 3, 6), plt.imshow(img_gt, cmap='gray')

plt.tight_layout()
plt.show()

Hope that helps – somehow!希望有所帮助 - 不知何故!

-----------------------
System information
-----------------------
Python:      3.8.1
Matplotlib:  3.2.0rc1
OpenCV:      4.1.2
-----------------------

Another way to look at this is that where abs(mean - image) <= c, you want that to become white, otherwise you want that to become black.另一种看待这个问题的方法是,abs(mean - image) <= c,你希望它变成白色,否则你希望它变成黑色。 In Python/OpenCV/Scipy/Numpy, I first compute the local uniform mean (average) using a uniform 51x51 pixel block averaging filter (boxcar average).在 Python/OpenCV/Scipy/Numpy 中,我首先使用统一的 51x51 像素块平均滤波器(boxcar 平均值)计算局部均匀平均值(平均值)。 You could use some weighted averaging method such as the Gaussian average, if you want.如果需要,您可以使用一些加权平均方法,例如高斯平均。 Then I compute the abs(mean - image).然后我计算 abs(mean - image)。 Then I use Numpy thresholding.然后我使用 Numpy 阈值。 Note: You could also just use one simple threshold (cv2.threshold) on the abs(mean-image) result in place of two numpy thresholds.注意:您也可以在 abs(mean-image) 结果上使用一个简单的阈值 (cv2.threshold) 代替两个 numpy 阈值。

Input:输入:

在此处输入图片说明

import cv2
import numpy as np
from scipy import ndimage

# read image as grayscale
# convert to floats in the range 0 to 1 so that the difference keeps negative values
img = cv2.imread('squares.png',0).astype(np.float32)/255.0

# get uniform (51x51 block) average
ave = ndimage.uniform_filter(img, size=51)

# get abs difference between ave and img and convert back to integers in the range 0 to 255
diff = 255*np.abs(ave - img)
diff = diff.astype(np.uint8)

# threshold
# Note: could also just use one simple cv2.Threshold on diff
c = 5
diff_thresh = diff.copy()
diff_thresh[ diff_thresh <= c ] = 255
diff_thresh[ diff_thresh != 255 ] = 0


# view result
cv2.imshow("img", img)
cv2.imshow("ave", ave)
cv2.imshow("diff", diff)
cv2.imshow("threshold", diff_thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save result
cv2.imwrite("squares_2way_thresh.jpg", diff_thresh)


Result:结果:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM