【问题标题】:OpenCV - Smoothing bordersOpenCV - 平滑边界
【发布时间】:2018-07-10 13:40:53
【问题描述】:

我想将多个图像补丁拼接到一个新的主要是灰色背景图像上。如果可能,图像补丁包含不应更改的彩色元素。它们的形状和颜色多种多样。和新的背景图片一样,图片补丁的边框也是灰色的,只是略有不同,但如果我路过,你会看到强烈的边框

ImgPatch = cv2.imread("C://...//ImagePatch.png")
NewBackground = cv2.imread("C://...//NewBackground.png")
height, width, channels = ImgPatch.shape
NewBackground[y:y+height,x:x+width] = ImgPatch

我按照本教程中的说明尝试了cv2.seamlessClone() (docs.opencv.org):

www.learnopencv.com/seamless-cloning-using-opencv-python-cpp

边缘完美平滑,但不幸的是元素的颜色变化太多。我知道每个图像补丁的灰色边框的大致宽度和高度。如果我可以特别平滑那个可能是一个开始的区域,并让结果看起来已经比我拥有的更好。我用cv2.seamlessClone() 尝试了不同的面具,但没有一种尝试过的方法有效。所以不幸的是,到目前为止,我找不到正确的方法来仅混合补丁的边界。

以下图片以非常抽象的方式可视化了我的问题。

我有什么:

左:背景,右:图像补丁

我想要什么:

我目前使用cv2.seamlessClone()得到的结果:

任何帮助将不胜感激!

编辑因为我可能不够清楚:真实图像要复杂得多,所以不幸的是,我无法通过使用 cv2.findContour 获得所有图像补丁的合理结果...我是什么寻找是一种合并边界的方法,因此您无法再看到补丁到背景的确切过渡。

【问题讨论】:

  • cv2.seamlessClone() 在这里帮不了你。它试图使对象融入背景图像的周围环境中。
  • 是的,我已经放弃了这种方法。我目前正在尝试不同的想法,例如使用 cv2.GaussianBlur() 或其他方法模糊边界。但到目前为止,没有什么看起来很好。有什么好主意可能是最好的方法吗?我不是真正的 openCV 专家...
  • 您的实际情况要复杂多少?提问时最好简化,但如果简化太多,就会得到过于简单的答案。补丁的背景是否总是相同的灰色?补丁中其他地方的背景颜色是否可见?如果没有,你应该可以使用蓝屏技术(灰屏?)。
  • 你解决了吗?我遇到了同样的问题。我只是想消除边框但无缝克隆做得太多了!我认为@Kunibert 只是想要一个“不太有效”的无缝克隆,就像我一样。

标签: python opencv image-processing


【解决方案1】:
patch = cv2.imread('patch.png', cv2.IMREAD_UNCHANGED);
image = cv2.imread('image.png', cv2.IMREAD_UNCHANGED);

mask = 255 * np.ones(patch.shape, patch.dtype)

width, height, channels = image.shape
center = (height//2, width//2)

mixed_clone = cv2.seamlessClone(patch, image, mask, center, cv2.cv2.NORMAL_CLONE)

【讨论】:

  • 这正是我所做的。但是颜色变化太大。如果可能的话,我希望这些元素尽可能接近它们在图像处理之前的外观。
  • @Kumbert,那么为什么这看起来与您问题中的图片不同?
【解决方案2】:

您可以尝试使用cv2.findContour()(红点)在图像补丁中找到轮廓。然后去除轮廓的背景并保存图像。你终于可以将你保存的那个(没有背景的红点)与带有cv2.add()的灰色背景图像结合起来。我结合了一些我曾经玩过的代码和 OpenCV 文档中的代码(cv2.add())。希望它有所帮助(注意示例广告在左上角的图像 - 如果你想在其他地方你应该更改代码)。干杯!

例子:

import cv2
import numpy as np
from PIL import Image

img = cv2.imread('background2.png', cv2.IMREAD_UNCHANGED)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, threshold = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY_INV)

height,width = gray.shape
mask = np.zeros((height,width), np.uint8)

_, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
cv2.drawContours(mask,[cnt], -1, (255,255,255),thickness=-1)

masked = cv2.bitwise_and(img, img, mask=mask)
_,thresh = cv2.threshold(mask,1,255,cv2.THRESH_BINARY)
contours = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
x,y,w,h = cv2.boundingRect(contours[0])
circle = masked[y:y+h,x:x+w]

cv2.imwrite('temp.png', circle)
cv2.waitKey(0)
cv2.destroyAllWindows()

img = Image.open('temp.png')
img = img.convert("RGBA")
datas = img.getdata()

newData = []
for item in datas:
    if item[0] == 0 and item[1] == 0 and item[2] == 0:
        newData.append((255, 255, 255, 0))
    else:
        newData.append(item)

img.putdata(newData)
img.save('background3.png', "PNG")

img1 = cv2.imread('background1.png')
img2 = cv2.imread('background3.png')

rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 110, 255, cv2.THRESH_BINARY_INV)
mask_inv = cv2.bitwise_not(mask)
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols] = dst
cv2.imshow('img',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

【讨论】:

  • 非常感谢您的努力!不幸的是,我已经尝试过了。我可能不够清楚,我真的很抱歉,但红点不应代表一个特定颜色的区域。真实图像要复杂得多,所以不幸的是,我无法通过使用cv2.findContour 获得所有图像补丁的合理结果...我需要一种合并边界的方法,所以你无法再看到补丁到背景的确切过渡
  • 哦,对不起,我误解了这个问题……希望您能找到解决方案!
猜你喜欢
  • 2014-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-16
  • 2013-01-21
  • 1970-01-01
  • 2014-03-14
  • 1970-01-01
相关资源
最近更新 更多