Python:使用OpenCV提取形状内对象

hts6caw3  于 2022-11-15  发布在  Python
关注(0)|答案(2)|浏览(194)

我需要使用python OpenCV从这个矩形框中提取图像。

我看过并尝试过几种从形状内部提取内容的方法,但每种方法都有局限性。(0,255,0)或红色(255,0,0)。然而,我的问题是红框有一些透明/不透明,使矩形的识别困难得多。矩形的红色像素颜色范围从175- 220,但是图像的其余部分也具有类似的红色色调,使得提取更加困难。

我对OpenCV还是个新手,所以非常感谢您的帮助。我已经在this线程上尝试了这两种解决方案,但是都没有产生预期的结果。

pqwbnv8z

pqwbnv8z1#

以下是一个可能的解决方案:
1.图像转换为HSV
1.红色阈值用于分割矩形
1.应用一些形态学以尽可能闭合轮廓
1.检测外部轮廓
1.根据面积过滤噪声斑点;您正在寻找最大的轮廓
1.获取轮廓的边界矩形
1.切片使用边界矩形的图像
让我们看看代码:

# imports:
import cv2
import numpy as np

# image path
path = "D://opencvImages//"
fileName = "uHNzL.jpg"

# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)
# Deep copy for results:
inputImageCopy = inputImage.copy()

# Convert the image to the HSV color space:
hsvImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2HSV)

# Set the HSV values:
lowRange = np.array([144, 105, 0])
uppRange = np.array([179, 255, 255])

# Create the HSV mask
binaryMask = cv2.inRange(hsvImage, lowRange, uppRange)

这是面具:

正如你所看到的,矩形(大部分)在那里。让我们尝试用一些形态学来改善轮廓。一些扩张和侵 eclipse 应该可以做到这一点:

# Apply Dilate + Erode:
kernel = np.ones((3, 3), np.uint8)
binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_DILATE, kernel, iterations=3)
binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_ERODE, kernel, iterations=3)

这就是结果:

矩形稍大一些,但噪声也大一些。但是,我们要寻找最大的斑点,所以我们可以按面积过滤。让我们裁剪最大的斑点:

# Find the target blobs on the binary mask:
contours, hierarchy = cv2.findContours(binaryMask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# Alright, just look for the outer bounding boxes:
for _, c in enumerate(contours):

    # Get blob area:
    blobArea = cv2.contourArea(c)

    # Set minimum area:
    minArea = 1000

    if blobArea > minArea:
        # Get the bounding rectangle:
        boundRect = cv2.boundingRect(c)

        # Bondary offset:
        offset = 15

        # Draw the rectangle on the input image:
        # Get the dimensions of the bounding rect:
        rectX = int(boundRect[0] + offset)
        rectY = int(boundRect[1] + offset)
        rectWidth = int(boundRect[2] - 2 * offset)
        rectHeight = int(boundRect[3] - 2 * offset)

        #  Green Color, detected blobs:
        color = (0, 255, 0)
        cv2.rectangle(inputImageCopy, (int(rectX), int(rectY)),
                      (int(rectX + rectWidth), int(rectY + rectHeight)), color, 2)

        # Crop contour:
        croppedImage = inputImage[rectY:rectY + rectHeight, rectX:rectX + rectWidth]
        cv2.imshow("croppedImage", croppedImage)
        cv2.waitKey(0)

    cv2.imshow("Rectangles", inputImageCopy)
    cv2.waitKey(0)

现在,因为我们正在处理一个变形图像,矩形二进制轮廓比实际的红色矩形稍大,所以我引入了一个偏移量,以更紧密地裁剪图像。
这是偏移量为15像素的边框:

这是裁剪后的图像:

4smxwvx5

4smxwvx52#

非常感谢你的帮助;这是非常有帮助的!我确实必须修改代码,以概括它足以适用于数百万张图像。我得到了大约95%+的准确率。错误包括图像中的多个建筑物非常接近红色屋顶,深红色土壤,车辆...基本上任何红色的东西。因此,我把最小面积的阈值提高到一个很高的值,以排除红色框外的大的红色物体。希望这对其他人有帮助。
主要变更...
1.我删除了偏移,它没有概括得足够好,在一些图像中,所需的内容被从最终产品中剪掉了。
1.我确实需要合并轮廓以避免出现大量较小的矩形,这也是我增加minArea阈值的原因。我发现即使是100的小减量有时也会产生2+轮廓,所以我必须在计算边界矩形之前将它们合并。
1.非常重要的是,我创建了一个上限和下限颜色范围,以确保我得到的是红色框所涵盖的整个区域。由于红色框的透明度,色调和饱和度无处不在,这有助于始终确保我捕捉到所需的内容。
希望这对其他人有帮助。

# Original image
src = cv2.imread(img_file, cv2.IMREAD_COLOR)
img = cv2.cvtColor(src, cv2.COLOR_BGR2RGB )

# HSV
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)

# lower boundary RED color range values; Hue (0 - 10)
lower1 = np.array([0, 100, 20])
upper1 = np.array([10, 255, 255])
 
# upper boundary RED color range values; Hue (160 - 180)
lower2 = np.array([160,100,20])
upper2 = np.array([179,255,255])
 
lower_mask = cv2.inRange(hsv, lower1, upper1)
upper_mask = cv2.inRange(hsv, lower2, upper2)
 
binaryMask = lower_mask + upper_mask

# kernel dialation and erode
kernel = np.ones((3, 3), np.uint8)
binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_DILATE, kernel, iterations=3)
binaryMask = cv2.morphologyEx(binaryMask, cv2.MORPH_ERODE, kernel, iterations=3)

# Find the target blob
contours, hierarchy = cv2.findContours(binaryMask, cv2.RETR_EXTERNAL,
                                       cv2.CHAIN_APPROX_SIMPLE)
flag = True
minArea = 50_000
while flag and minArea > 100:
    contours_ = [contour for contour in contours
                if cv2.contourArea(contour) > minArea]
    contoursAreas = [cv2.contourArea(contour) for contour in contours]

    if contours_:
        contour = np.vstack(contours_)
        flag = False
    else:
        minArea -= 500

# blob to bounding rectangle
offset = 15
boundRect = cv2.boundingRect(contour)
rectX = int(boundRect[0])
rectY = int(boundRect[1])
rectWidth = int(boundRect[2])
rectHeight = int(boundRect[3])

# Crop orignal image and save image
croppedImage = src[rectY:rectY + rectHeight, rectX:rectX + rectWidth]
imgFName = os.path.split(img_file)[-1]
imgFPath = os.path.join(OUT_IMG_PATH, imgFName)
cv2.imwrite(imgFPath, croppedImage)

相关问题