OpenCV跟踪轮廓将整个图像跟踪为最大轮廓?

Posted

技术标签:

【中文标题】OpenCV跟踪轮廓将整个图像跟踪为最大轮廓?【英文标题】:OpenCV trace contours tracing whole image as largest contour? 【发布时间】:2021-03-12 18:10:43 【问题描述】:

我正在尝试生成用于训练神经网络的数据集,这需要我在视频的多个帧中围绕移动对象(蜗牛)进行裁剪。

我已将视频分割成帧并使用 OpenCV 通过使用 HSV 阈值和轮廓跟踪来裁剪对象,如下所示:

import cv2 
import pandas as pd 
import matplotlib
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt

img = cv2.imread("./pngs/04Feb21_1_crop/20000.png")
img_edit = cv2.imread("./pngs/04Feb21_1_crop/20000.png")

hsv_img = cv2.cvtColor(img_edit, cv2.COLOR_BGR2HSV)
plt.imshow(hsv_img) ## 1

low = np.array([99, 109, 77] )
high = np.array([115, 255, 255])
curr_mask = cv2.inRange(hsv_img, low, high)
hsv_img[curr_mask > 0] = ([84, 255, 200])

# converting the hsv image to gray in order to be able to apply
# contouring
RGB_again = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2RGB)
gray = cv2.cvtColor(RGB_again, cv2.COLOR_RGB2GRAY)

ret, threshold = cv2.threshold(gray, 90, 255, 0)
plt.imshow(threshold, cmap="binary")

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
threshold = cv2.morphologyEx(threshold, cv2.MORPH_OPEN, kernel)
threshold = cv2.morphologyEx(threshold, cv2.MORPH_CLOSE, kernel)

contours, hierarchy =  cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_edit = cv2.drawContours(img_edit, contours, -1, (0,255,0), 3)
plt.imshow(img_edit)

正如您在此处看到的,底部的绿线表示存在包含照片底部边缘的轮廓。因此,当我选择最大的轮廓并围绕它进行裁剪时,如下所示:

# find largest contour
areaArray = []
count = 1

for i, c in enumerate(contours):
    area = cv2.contourArea(c)
    areaArray.append(area)

#first sort the array by area
sorteddata = sorted(zip(areaArray, contours), key=lambda x: x[0], reverse=True)

#find the nth largest contour [n-1][1], in this case 2
largestcontour = sorteddata[0][1]

x,y,w,h = cv2.boundingRect(largestcontour)
crop = img[y:y+h, x:x+w]
plt.imshow(crop)

整个图像被裁剪,因为最大轮廓的边界矩形本质上就是图像的大小。

我一直在通过选择第二大轮廓来规避这个问题,但它不适用于我的所有框架。例如,在这个框架中,选择第二大轮廓,如下所示:

secondlargestcontour = sorteddata[1][1]

像以前一样裁剪会产生这个灰色区域:

我在 HSV 阈值方面做错了吗?是不是因为物体本身与水的阴影/反射不够清晰?

非常感谢任何和所有帮助。我是 Python 和 OpenCV 的新手,如果我遗漏了一些非常明显的东西,我提前道歉。

用于所有代码的原始图像在这里:

【问题讨论】:

【参考方案1】:

我认为改变 HSV 的上下边界可以解决你的问题。

我已将值更改为此

low = np.array([0, 35, 0])
high = np.array([253, 255, 255])

测试代码

import cv2
import numpy as np

image = cv2.imread("image.png")
HSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

low = np.array([0, 35, 0])
high = np.array([253, 255, 255])

mask = cv2.inRange(HSV, low, high)
cv2.imshow("mask", mask)

result = cv2.bitwise_and(image, image, mask=mask)
cv2.imshow("result", result)

contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
sorted_contour = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)

largestcontour = sorted_contour[0]
x, y, w, h = cv2.boundingRect(largestcontour)
crop = image[y:y+h, x:x+w]

cv2.imshow("crop", crop)

cv2.waitKey(0)
cv2.destroyAllWindows()

输出:

mask image result image crop image

【讨论】:

以上是关于OpenCV跟踪轮廓将整个图像跟踪为最大轮廓?的主要内容,如果未能解决你的问题,请参考以下文章

基于 OpenCV 实战:对象跟踪

求C++中利用opencv计算轮廓图像傅里叶描述子的代码

数字图像处理内边界跟踪算法

使用OpenCV(Python)找到具有最大封闭区域的轮廓

OpenCV findContours 只查找图像的边框

数据增强——python opencv 找出图像中的最大轮廓并填充(生成mask)——python 轮廓内部填充