覆盖填充的半透明轮廓

时间:2021-05-06 17:41:31

标签: python opencv

我正在尝试找到图像的轮廓并将它们(具有一定的透明度)覆盖在另一个图像上。但是,当我执行以下代码时,我得到了一个不想要的效果(见下图)。

img = cv2.imread('image1.bmp',cv2.IMREAD_GRAYSCALE)
contours, hierarchy = cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

im = cv2.imread('image2.jpg')
im_copy = im.copy()

for j,cont in enumerate(contours): 
    im_copy = cv2.drawContours(im_copy, [cont], -1, (0, 0, 255), -1)
    im = cv2.addWeighted(im_copy, 0.4, im, 1 - 0.2, 0)
    im = cv2.drawContours(im, [cont], -1, (0, 0, 255), 0)

cv2.imwrite(f'projects/{prj.name}/logs/repeated_img/{file}', im)

Output image

我调用 drawContours() 两次以获得半透明填充和实心边框。显然,其中一个轮廓似乎比另一个更不透明。我怀疑同一轮廓的 drawContours 被调用了两次,所以我尝试了以下更改:

    im_copy = cv2.drawContours(im_copy, [cont], j, (0, 0, 255), -1)
    im = cv2.addWeighted(im_copy, 0.4, im, 1 - 0.2, 0)
    im = cv2.drawContours(im, [cont], j, (0, 0, 255), 0)

尝试绘制第二个轮廓时会产生以下错误:

(-215:Assertion failed) 0 <= contourIdx && contourIdx < (int)last in function 'drawContours'

轮廓会根据某些条件以不同的颜色绘制,因此我需要能够独立绘制它们。

是什么导致了这种不良影响?


编辑

回答评论,使用以下代码转换为rbga

im = cv2.imread('image2.jpg')
im = cv2.cvtColor(im, cv2.COLOR_BGR2BGRA)
im_copy = im.copy()
    
for j,cont in enumerate(contours): 
    im_copy = cv2.drawContours(im_copy, [cont], -1, (0, 0, 255,128), -1)
    im = cv2.drawContours(im, [cont], -1, (0, 0, 255, 255), 0)

结果如下图:

Output image

2 个答案:

答案 0 :(得分:1)

这是在 Python/OpenCV 中执行此操作的一种方法。为了演示,我将在最大的区域上绘制一个部分透明的红色轮廓。我通过在输入上绘制一次全红色然后与原始输入混合来做到这一点。我看不到直接绘制部分透明轮廓的方法。

输入:

enter image description here

import cv2
import numpy as np

# read image
img = cv2.imread('scan.png')
hh, ww = img.shape[:2]

# convert to gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# threshold
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]

# get largest contour
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)

# draw red filled contour on image background
back = img.copy()
cv2.drawContours(back, [big_contour], 0, (0,0,255), -1)

# blend with original image
alpha = 0.25
result = cv2.addWeighted(img, 1-alpha, back, alpha, 0)

# write results
cv2.imwrite('scan_transparent_contour.png', result)

# show results
cv2.imshow("img", img)
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)
cv2.waitKey(0)

结果:

enter image description here

答案 1 :(得分:0)

该问题是由 addWeight() 引起的,因为每个轮廓调用一次。这导致一些轮廓与原始图像的权重超过一倍,因此一些区域看起来更透明。我通过以下方式解决了这个问题:

im = cv2.imread('image1.jpg')                           
im_copy = im.copy()

alpha = 0.5
for cont in contours: 
    if cv2.contourArea(cont) <= 1:
        im_copy = cv2.drawContours(im_copy, [cont], -1, (0, 0, 255), -1)
    else:
        im_copy = cv2.drawContours(im_copy, [cont], -1, (51, 197, 255), -1)
filled = cv2.addWeighted(im, alpha, im_copy, 1-alpha, 0)
for cont in contours: 
    if cv2.contourArea(cont) <= 1:
        result = cv2.drawContours(filled, [cont], -1, (0, 0, 255), 0)
    else:
        result = cv2.drawContours(filled, [cont], -1, (51, 197, 255), 0)

cv2.imwrite('result.bmp', result)