opencv 使用Python从图像中提取ROI

h9a6wy2h  于 2023-10-24  发布在  Python
关注(0)|答案(2)|浏览(152)

我正在尝试去除图像的背景。我使用这里描述的方法运气不佳(从Canny边缘获取边界并去除图像的背景),但是当图像的背景是白色或浅色时,我已经能够成功地去除背景(“123456789.jpg”)。问题是当背景颜色为黑色或深色时,此方法无法删除图像的背景(“12345678.jpg”)。以下是我运行的代码:
123456789.jpg123456789success.jpg12345678.jpg12345678fail.jpg

import cv2
import numpy as np
image = cv2.imread("123456789.jpg")
original = image.copy()
mask = np.zeros(image.shape, dtype=np.uint8)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
for c in cnts:
    cv2.drawContours(mask, [c], -1, (255,255,255), -1)
    break
close = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=4)
close = cv2.cvtColor(close, cv2.COLOR_BGR2GRAY)
result = cv2.bitwise_and(original, original, mask=close)
result[close==0] = (0,0,0)
cv2.imshow('result', result)
cv2.waitKey()

因此,我想改进我的方法,使我可以去除图像的黑色背景,以获得感兴趣区域。

sz81bmfz

sz81bmfz1#

在代码中,您使用大津(cv2.THRESH_OTSU)自动确定阈值,并执行更多的形态学操作。您还选择最大的轮廓作为遮罩,如果前景中有复杂的形状,并希望确保保留最大的部分,这可能是有益的。但在您的示例中并非如此。
更新代码:

import cv2
import numpy as np

# Load the image
image = cv2.imread("123456789.jpg")
original = image.copy()

# Convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Threshold the grayscale image to separate the foreground from the dark background
_, thresh = cv2.threshold(gray, 40, 255, cv2.THRESH_BINARY)

# Find contours in the thresholded image
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Create a mask to store the foreground region
mask = np.zeros_like(image)

# Iterate through the contours and draw them on the mask
for contour in contours:
    cv2.drawContours(mask, [contour], -1, (255, 255, 255), -1)

# Bitwise AND the original image and the mask to extract the foreground
result = cv2.bitwise_and(original, mask)

# Show the result
cv2.imshow('Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这段代码中,我使用一个较低的阈值(在本例中为40)来创建一个二进制掩码,将暗背景与前景分开。然后,我在二进制掩码中找到轮廓,创建一个掩码来存储前景区域,并在此掩码上绘制轮廓。然后,我使用逐位AND操作从使用掩码的原始图像中提取前景。
这段代码为您的图像提供了所需的图像,并且也更简单。

请注意,您应该根据需要调整阈值(本例中为40),以获得特定图像的最佳效果。此方法适用于深色背景的图像。

此外,如果你是open-cv的新手或者想大规模地这样做,你也可以看看一些可以进行智能裁剪的AI工具,比如Smart Image Crop APICloudinary's Imagga crop插件。
希望这对你有帮助。

xpszyzbs

xpszyzbs2#

在Python/OpenCV中处理图像的一种方法是在饱和度通道上转换为HSV和阈值等,因为您的背景似乎是灰度的,而中心对象是彩色的。

  • 读取输入
  • 转换为HSV并提取饱和度通道
  • 饱和通道阈值
  • 应用形态学靠近填充孔
  • 由于输入中存在模糊的边框,请删除此图像中的任何边框
  • 找到轮廓并提取最大的一个
  • 在输入的副本上绘制此轮廓作为结果
  • 保存结果
import cv2
import numpy as np

# read the input
img = cv2.imread('light.jpg')
#img = cv2.imread('dark.jpg')
hh, ww = img.shape[:2]

# convert to HSV and extract the saturation channel
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
sat = hsv[:,:,1]

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

# apply morphology close 
kernel = cv2.getStructuringElement(cv2.MORPH_RECT , (21,21))
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# remove border detected from (second) input
bias = 10
morph = morph[bias:hh-bias, bias:ww-bias]
morph = cv2.copyMakeBorder(morph, bias,bias,bias,bias, borderType=cv2.BORDER_CONSTANT, value=(0,0,0))

# get largest contour and draw it on input
result = img.copy()
contours = cv2.findContours(morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
cv2.drawContours(result, [big_contour], 0, (0,255,0), 2)

# save results
cv2.imwrite('light_contour.jpg', result)
#cv2.imwrite('dark_contour.jpg', result)

# show results
cv2.imshow('sat', sat)
cv2.imshow('thresh', thresh)
cv2.imshow('morph', morph)
cv2.imshow('result', result)
cv2.waitKey(0)

输入1(浅色背景):

结果一:

输入2(暗背景):

结果二:

相关问题