<h3>代码</h3>
<pre><code>import cv2
import numpy as np
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_canny = cv2.Canny(img_gray, 10, 20)
kernel = np.ones((13, 13))
img_dilate = cv2.dilate(img_canny, kernel, iterations=1)
return cv2.erode(img_dilate, kernel, iterations=1)
def get_mask(img):
contours, _ = cv2.findContours(process(img), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
blank = np.zeros(img.shape[:2]).astype('uint8')
for cnt in contours:
if cv2.contourArea(cnt) > 500:
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, peri * 0.004, True)
cv2.drawContours(blank, [approx], -1, 255, -1)
return blank
img = cv2.imread("crystal.jpg")
img_masked = cv2.bitwise_and(img, img, mask=get_mask(img))
cv2.imshow("Masked", img_masked)
cv2.waitKey(0)
</code></pre>
<h3>输出</h3>
<p><a href="https://i.stack.imgur.com/1EK6e.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1EK6e.jpg" alt="enter image description here"/></a></p>
<h3>解释</h3>
<ol>
<li>导入必要的库:</li>
</ol>
<pre><code>import cv2
import numpy as np
</code></pre>
<ol start=“2”>
<li>定义一个函数来处理图像,使其适合于正确的轮廓检测。在函数中,首先将图像转换为灰度,然后使用canny边缘检测器检测其边缘。检测到边缘后,我们可以对其进行一次放大和腐蚀,以使边缘更加完整:</li>
</ol>
<pre><code>def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_canny = cv2.Canny(img_gray, 10, 20)
kernel = np.ones((13, 13))
img_dilate = cv2.dilate(img_canny, kernel, iterations=1)
return cv2.erode(img_dilate, kernel, iterations=1)
</code></pre>
<ol start=“3”>
<li>定义一个函数以生成图像的遮罩。在找到图像的轮廓后,用图像的形状定义灰度空白图像,绘制每个轮廓Em>(大于^ {CD1> }的区域以滤除噪声)< EEM >填充到空白图像上。我还对轮廓进行了近似处理,以稍微平滑一些:</li>
</ol>
<pre><code>def get_mask(img):
contours, _ = cv2.findContours(process(img), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
blank = np.zeros(img.shape[:2]).astype('uint8')
for cnt in contours:
if cv2.contourArea(cnt) > 500:
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, peri * 0.004, True)
cv2.drawContours(blank, [approx], -1, 255, -1)
return blank
</code></pre>
<ol start=“4”>
<li>最后,读入图像,并使用<code>cv2.bitwise_and</code>方法以及我们定义的<code>get_mask</code>函数屏蔽图像,该函数使用我们定义的<code>process</code>函数。最后显示蒙版图像:</li>
</ol>
<pre><code>img = cv2.imread("crystal.jpg")
img_masked = cv2.bitwise_and(img, img, mask=get_mask(img))
cv2.imshow("Masked", img_masked)
cv2.waitKey(0)
</code></pre>
<h3>透明背景</h3>
<p>您可以使用<code>cv2.merge</code>方法代替<code>cv2.bitwise_and</code>方法:</p>
<pre><code>img = cv2.imread("crystal.jpg")
img_masked = cv2.merge(cv2.split(img) + [get_mask(img)])
cv2.imwrite("masked_crystal.png", img_masked)
</code></pre>
<p>生成的图像(屏幕截图):</p>
<p><a href="https://i.stack.imgur.com/KgHKr.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/KgHKr.png" alt="enter image description here"/></a></p>
<p>说明:</p>
<ol>
<li>请记住,我们已经将<code>cv2</code>模块和<code>numpy</code>模块作为<code>np</code>导入。我们还定义了一个<code>process</code>函数和一个<code>get_mask</code>函数,我们可以在图像中读取:</li>
</ol>
<pre><code>img = cv2.imread("crystal.jpg")
</code></pre>
<ol start=“2”>
<li><code>cv2.split</code>方法接收图像数组并返回图像中存在的每个通道的列表。在我们的例子中,我们只有3个通道,为了使图像透明,我们需要第四个通道:alpha通道。<code>cv2.merge</code>方法的作用与<code>cv2.split</code>相反;它接收单个通道的列表,并返回带有通道的图像数组。接下来,我们在列表中获取图像的bgr通道,并将图像的掩码连接为alpha通道:</li>
</ol>
<pre><code>img_masked = cv2.merge(cv2.split(img) + [get_mask(img)])
</code></pre>
<ol start=“3”>
<li>最后,我们可以将四通道图像写入文件:</li>
</ol>
<pre><code>cv2.imwrite("masked_crystal.png", img_masked)
</code></pre>
<p>下面是<code>cv2.merge</code>方法的更多示例:<a href="https://www.programcreek.com/python/example/85133/cv2.merge" rel="nofollow noreferrer">Python cv2.merge() Examples</a></p>