如何在 OpenCV 中沿轮廓裁剪给定的不规则形状对象
How to crop the given Irregularly shaped object along its outline in OpenCV
我一直在研究一个代码,其中给出了如图所示的图像
我必须将这把刀放在其他图像上。条件是我必须沿着它的轮廓而不是在一个矩形框中裁剪刀。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('2.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
img_blur = cv2.bilateralFilter(img, d = 7,
sigmaSpace = 75, sigmaColor =75)
img_gray = cv2.cvtColor(img_blur, cv2.COLOR_RGB2GRAY)
a = img_gray.max()
_, thresh = cv2.threshold(img_gray, a/2+60, a,cv2.THRESH_BINARY_INV)
plt.imshow(thresh, cmap = 'gray')
contours, hierarchy = cv2.findContours(
image = thresh,
mode = cv2.RETR_TREE,
method = cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key = cv2.contourArea, reverse = True)
img_copy = img.copy()
final = cv2.drawContours(img_copy, contours, contourIdx = -1,
color = (255, 0, 0), thickness = 2)
plt.imshow(img_copy)
这是我试过的方法,但似乎效果不佳。
输入
输出
您可以使用添加了气球力的蛇形算法从边界框开始。
Snake 的算法被定义为最小化 3 种能量 - 连续性、曲率和梯度。当点(曲线上)越来越近时,前两个(一起称为内部能量)会最小化,即收缩。如果它们膨胀,那么能量就会增加,这是蛇算法所不允许的。
但是 1987 年提出的这个初始算法存在一些问题。问题之一是在平坦区域(梯度为零)算法无法收敛并且什么都不做。提出了几种修改来解决这个问题。这里感兴趣的解法是——LD Cohen在1989年提出的Balloon Force。
气球力引导图像 non-informative 区域中的轮廓,即图像梯度太小而无法将轮廓推向边界的区域。 负值会缩小轮廓,而正值会扩大这些区域的轮廓。将此设置为零将禁用气球力。
另一个改进是 - Morphological Snakes,它在二进制数组上使用形态学运算符(例如膨胀或腐蚀),而不是在浮点数组上求解 PDE,这是活动轮廓的标准方法。这使得 Morphological Snakes 比传统的对应物更快并且在数值上更稳定。
Scikit-image使用以上两个改进的实现是morphological_geodesic_active_contour
。它有一个参数 balloon
使用您的图片
import numpy as np
import matplotlib.pyplot as plt
from skimage.segmentation import morphological_geodesic_active_contour, inverse_gaussian_gradient
from skimage.color import rgb2gray
from skimage.util import img_as_float
from PIL import Image, ImageDraw
im = Image.open('knife.jpg')
im = np.array(im)
im = rgb2gray(im)
im = img_as_float(im)
plt.imshow(im, cmap='gray')
现在让我们创建一个函数来帮助我们存储迭代:
def store_evolution_in(lst):
"""Returns a callback function to store the evolution of the level sets in
the given list.
"""
def _store(x):
lst.append(np.copy(x))
return _store
该方法需要对图片进行预处理,突出轮廓。这可以使用函数 inverse_gaussian_gradient
来完成,尽管用户可能想要定义他们自己的版本。 MorphGAC 分割的质量很大程度上取决于这个预处理步骤。
gimage = inverse_gaussian_gradient(im)
下面我们定义我们的起点——边界框。
init_ls = np.zeros(im.shape, dtype=np.int8)
init_ls[200:-400, 20:-30] = 1
列出用于绘制进化的中间结果
evolution = []
callback = store_evolution_in(evolution)
现在 morphological_geodesic_active_contour 气球收缩所需的魔法线如下:
ls = morphological_geodesic_active_contour(gimage, 200, init_ls,
smoothing=1, balloon=-0.75,
threshold=0.7,
iter_callback=callback)
现在让我们绘制结果:
fig, axes = plt.subplots(1, 2, figsize=(8, 8))
ax = axes.flatten()
ax[0].imshow(im, cmap="gray")
ax[0].set_axis_off()
ax[0].contour(ls, [0.5], colors='b')
ax[0].set_title("Morphological GAC segmentation", fontsize=12)
ax[1].imshow(ls, cmap="gray")
ax[1].set_axis_off()
contour = ax[1].contour(evolution[0], [0.5], colors='r')
contour.collections[0].set_label("Starting Contour")
contour = ax[1].contour(evolution[25], [0.5], colors='g')
contour.collections[0].set_label("Iteration 25")
contour = ax[1].contour(evolution[-1], [0.5], colors='b')
contour.collections[0].set_label("Last Iteration")
ax[1].legend(loc="upper right")
title = "Morphological GAC Curve evolution"
ax[1].set_title(title, fontsize=12)
plt.show()
气球力越大也只能得到刀刃
ls = morphological_geodesic_active_contour(gimage, 100, init_ls,
smoothing=1, balloon=-1,
threshold=0.7,
iter_callback=callback)
使用这些参数 - smoothing, balloon, threshold
获得完美曲线
我一直在研究一个代码,其中给出了如图所示的图像 我必须将这把刀放在其他图像上。条件是我必须沿着它的轮廓而不是在一个矩形框中裁剪刀。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('2.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
img_blur = cv2.bilateralFilter(img, d = 7,
sigmaSpace = 75, sigmaColor =75)
img_gray = cv2.cvtColor(img_blur, cv2.COLOR_RGB2GRAY)
a = img_gray.max()
_, thresh = cv2.threshold(img_gray, a/2+60, a,cv2.THRESH_BINARY_INV)
plt.imshow(thresh, cmap = 'gray')
contours, hierarchy = cv2.findContours(
image = thresh,
mode = cv2.RETR_TREE,
method = cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key = cv2.contourArea, reverse = True)
img_copy = img.copy()
final = cv2.drawContours(img_copy, contours, contourIdx = -1,
color = (255, 0, 0), thickness = 2)
plt.imshow(img_copy)
这是我试过的方法,但似乎效果不佳。
输入
输出
您可以使用添加了气球力的蛇形算法从边界框开始。
Snake 的算法被定义为最小化 3 种能量 - 连续性、曲率和梯度。当点(曲线上)越来越近时,前两个(一起称为内部能量)会最小化,即收缩。如果它们膨胀,那么能量就会增加,这是蛇算法所不允许的。
但是 1987 年提出的这个初始算法存在一些问题。问题之一是在平坦区域(梯度为零)算法无法收敛并且什么都不做。提出了几种修改来解决这个问题。这里感兴趣的解法是——LD Cohen在1989年提出的Balloon Force。
气球力引导图像 non-informative 区域中的轮廓,即图像梯度太小而无法将轮廓推向边界的区域。 负值会缩小轮廓,而正值会扩大这些区域的轮廓。将此设置为零将禁用气球力。
另一个改进是 - Morphological Snakes,它在二进制数组上使用形态学运算符(例如膨胀或腐蚀),而不是在浮点数组上求解 PDE,这是活动轮廓的标准方法。这使得 Morphological Snakes 比传统的对应物更快并且在数值上更稳定。
Scikit-image使用以上两个改进的实现是morphological_geodesic_active_contour
。它有一个参数 balloon
使用您的图片
import numpy as np
import matplotlib.pyplot as plt
from skimage.segmentation import morphological_geodesic_active_contour, inverse_gaussian_gradient
from skimage.color import rgb2gray
from skimage.util import img_as_float
from PIL import Image, ImageDraw
im = Image.open('knife.jpg')
im = np.array(im)
im = rgb2gray(im)
im = img_as_float(im)
plt.imshow(im, cmap='gray')
现在让我们创建一个函数来帮助我们存储迭代:
def store_evolution_in(lst):
"""Returns a callback function to store the evolution of the level sets in
the given list.
"""
def _store(x):
lst.append(np.copy(x))
return _store
该方法需要对图片进行预处理,突出轮廓。这可以使用函数 inverse_gaussian_gradient
来完成,尽管用户可能想要定义他们自己的版本。 MorphGAC 分割的质量很大程度上取决于这个预处理步骤。
gimage = inverse_gaussian_gradient(im)
下面我们定义我们的起点——边界框。
init_ls = np.zeros(im.shape, dtype=np.int8)
init_ls[200:-400, 20:-30] = 1
列出用于绘制进化的中间结果
evolution = []
callback = store_evolution_in(evolution)
现在 morphological_geodesic_active_contour 气球收缩所需的魔法线如下:
ls = morphological_geodesic_active_contour(gimage, 200, init_ls,
smoothing=1, balloon=-0.75,
threshold=0.7,
iter_callback=callback)
现在让我们绘制结果:
fig, axes = plt.subplots(1, 2, figsize=(8, 8))
ax = axes.flatten()
ax[0].imshow(im, cmap="gray")
ax[0].set_axis_off()
ax[0].contour(ls, [0.5], colors='b')
ax[0].set_title("Morphological GAC segmentation", fontsize=12)
ax[1].imshow(ls, cmap="gray")
ax[1].set_axis_off()
contour = ax[1].contour(evolution[0], [0.5], colors='r')
contour.collections[0].set_label("Starting Contour")
contour = ax[1].contour(evolution[25], [0.5], colors='g')
contour.collections[0].set_label("Iteration 25")
contour = ax[1].contour(evolution[-1], [0.5], colors='b')
contour.collections[0].set_label("Last Iteration")
ax[1].legend(loc="upper right")
title = "Morphological GAC Curve evolution"
ax[1].set_title(title, fontsize=12)
plt.show()
气球力越大也只能得到刀刃
ls = morphological_geodesic_active_contour(gimage, 100, init_ls,
smoothing=1, balloon=-1,
threshold=0.7,
iter_callback=callback)
使用这些参数 - smoothing, balloon, threshold
获得完美曲线