使用 Python 从视频片段中确定足球球员球衣的颜色

本文介绍了使用Python和OpenCV从足球比赛视频中通过K-Means聚类算法提取球员球衣颜色的过程。首先,讨论了图像处理的基础知识,包括加载、旋转、裁剪、调整大小和颜色空间转换。接着,详细阐述了从图像和视频中提取颜色的方法,如提取单个像素颜色、平均颜色和K-Means聚类。最后,展示了如何处理视频帧,提取JSON文件中的边界框,应用K-Means确定球衣颜色,并通过GUI可视化结果。文章强调了处理误报和提高颜色检测准确性的重要性。
摘要由CSDN通过智能技术生成

使用 K-Means 聚类来识别球员球衣颜色

d50b0cd420a08b2ecc7c987e3f8718b2.jpeg

足球是世界上最受欢迎的运动。在洪都拉斯,足球能够吸引大众的注意力,并在 90 分钟内让人群陷入情绪的漩涡。

多年来,我们看到各种技术被实施,以获取有关比赛内事件和球员表现的各种统计数据和信息。

通常,不仅为足球,而且为许多其他运动开发/实施的最有趣的技术应用程序之一是计算机视觉。计算机视觉 (CV) 是有关开发能够理解图像或视频等视觉数据的算法和/或人工智能的领域。CV 非常强大,在 Instagram 过滤器、自动驾驶汽车、MRI 重建、癌症检测等许多应用中都很常见。

在这个项目中,我们在不同的足球比赛中拍摄了一系列视频片段,并使用 K-Means 聚类算法确定了球员球衣颜色的颜色。

本文将详细介绍实现该目标的过程。这里开发的例程将视频片段作为输入,并生成一个包含聚类过程结果的 pandas 数据帧作为输出。

这个项目需要执行数据清理、聚类、图像/视频处理、图像中对象的基本分类、读取 JSON 文件以及各种 pandas/numpy 数组/列表操作。

本文目录:

  • 图像处理基础

  • 从图像中提取颜色

  • 从视频文件中提取帧

  • 从JSON文件中提取播放器边界框

  • 实现K-Means聚类确定球员球衣颜色

  • 制作用于快速可视化聚类结果的GUI

  • 结论

让我们开始吧!

图像/视频处理基础

本节将介绍对本项目很重要的图像和视频处理/操作的基础知识。

使用足球历史上我最喜欢的时刻之一作为参考图像来尝试各种可用的处理技术。那一刻是罗纳尔迪尼奥在 2005 年 11 月 19 日效力于巴塞罗那足球俱乐部时,对阵皇家马德里的精彩进球,如下图所示。

2c3e680aa8a90f951bae9beb71c9efd2.jpeg

2005 年 11 月 19 日,罗纳尔迪尼奥对皇家马德里的进球。

使用 OpenCV 加载图像

需要做的第一件事是将图像加载到笔记本中。如果你将图像保存在计算机上,则可以简单地使用cv2.imread函数。但是,对于在这部分工作中使用的图像,是通过 URL 获取的。然后,加载图像需要我们:

  1. 将我们的 URL 传入urllib.request.urlopen

  2. 从 URL 中的图像创建一个 numpy 数组

  3. cv2.imdecode用于从内存缓存中读取图像数据,并将其转换为图像格式。

  4. 由于cv2.imdecode默认以 BGR 格式加载图像,因此我将使用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)原始 RGB 处理和渲染图像。

#Render image from URL
req = urllib.request.urlopen('https://www.sportbible.com/cdn-cgi/image/width=648,quality=70,format=webp,fit=pad,dpr=1/https%3A%2F%2Fs3-images.sportbible.com%2Fs3%2Fcontent%2Fcf2701795dd2a49b4d404d9fa38f99fd.jpg')
arr = np.asarray(bytearray(req.read()), dtype=np.uint8)
bgr_img = cv2.imdecode(arr, -1) # 'Load it as it is'

# Determine the figures size in inches to fit image
dpi = plt.rcParams['figure.dpi']
height, width, depth = bgr_img.shape
figsize = width / float(dpi), height / float(dpi)

plt.figure(figsize=figsize)
plt.imshow(bgr_img)
plt.show()

此过程的结果如下所示:

9ddfd0d8ed4e1b30bec9de4fecb567fb.png

使用 OpenCV 在 BGR 空间中加载的图像。

如你所见,加载的此图像中的颜色与原始图像中看到的颜色不匹配。这是因为 OpenCV 在 BGR 颜色空间中默认加载的图像。

不过问题不大,因为切换到 RGB 颜色空间可以通过快速的代码行来完成,如下所示:

#Convert image to RGB from BGR
rgb_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=figsize)
plt.imshow(rgb_img)
plt.show()
523f1da8654cc0b1cacf94c195e7701a.png

使用 OpenCV 在 BGR 空间中加载的图像。

现在可以开始使用各种图像处理/操作技术了。将在这里展示其中的一些!

旋转图像

有几种不同的方法可以旋转图像。imutils 包通过imutils.rotate_bound函数具有最简单的实现,因为它所需要的只是要旋转的图像,以及我们要旋转图像的角度。

除此之外,此功能确保显示的旋转图像不会被裁剪并完全包含在边界内。其他方法需要首先构建旋转矩阵,然后应用旋转矩阵。

#Rotating an image
rotated0 = imutils.rotate_bound(rgb_img,0)
rotated45 = imutils.rotate_bound(rgb_img,45)
rotated90 = imutils.rotate_bound(rgb_img,90)
fig,axs = plt.subplots(1,3, figsize=(30,15))
axs[0].imshow(rotated0)
axs[1].imshow(rotated45)
axs[2].imshow(rotated90)
plt.show()

此操作的结果如下所示:

0b3165bc3785e5f5d1510bbeab763024.png

在 Python 中旋转图像。

裁剪图像

通过 OpenCV 加载图像时,图像被加载为 numpy 数组。然后,要裁剪图像,我们可以简单地使用 numpy 切片来裁剪内容。

我们有多种裁剪的方法。将在这里展示一个简单的示例,我们可以按不同的高度和宽度百分比裁剪图像。通过定义感兴趣区域 (ROI) 和轮廓,将在后面的部分中展示更多的方法来裁剪。

#Need to find the starting/ending column and row index first for the desired cropping
cropIni = [0.15,0.3,0.45]

#Crop width and height of image by 15% each
startRow1 = int(height*cropIni[0])       ;startCol1 = int(width*cropIni[0])
endRow1   = int(height*(1-cropIni[0]))   ;endCol1   = int(width*(1-cropIni[0]))

#Crop width and height of image by 30% each
startRow2= int(height*cropIni[1])        ;startCol2 = int(width*cropIni[1])
endRow2   = int(height*(1-cropIni[1]))   ;endCol2   = int(width*(1-cropIni[1]))

#Crop width and height of image by 40% each
startRow3 = int(height*cropIni[2])       ;startCol3 = int(width*cropIni[2])
endRow3   = int(height*(1-cropIni[2]))   ;endCol3   = int(width*(1-cropIni[2]))

#This is just slicing the array 
fig,axs = plt.subplots(1,3, figsize=(30,15))
crop1 = rgb_img[startRow1:endRow1, startCol1:endCol1]
crop2 = rgb_img[startRow2:endRow2, startCol2:endCol2]
crop3 = rgb_img[startRow3:endRow3, startCol3:endCol3]
axs[0].imshow(crop1)
axs[1].imshow(crop2)
axs[2].imshow(crop3)
plt.show()
0bf8a8200b78bdc839ab5fced2408c04.png

通过 Python 中的 numpy 切片裁剪图像。

调整图像大小

调整图像大小的方法有很多。在这里,将展示如何使用 OpenCV 中的 resize 函数调整图像大小。尽管图像看起来相同,但可以看出,当我们调整图像大小时,图像的大小(高度和宽度)会发生变化。

#Resizing an image
#cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])
xscale = [0.75,0.5,0.25]
yscale = [0.75,0.5,0.25]

rimg1 = cv2.resize(rgb_img, (0,0), fx=xscale[0], fy=yscale[0])
rimg2 = cv2.resize(rgb_img, (0,0), fx=xscale[1], fy=yscale[1])
rimg3 = cv2.resize(rgb_img, (0,0), fx=xscale[2], fy=yscale[2])

fig,axs = plt.subplots(1,3, figsize=(30,15))
axs[0].imshow(rimg1)
axs[1].imshow(rimg2)
axs[2].imshow(rimg3)
plt.show()
print("The width, height and depth of this image are ",rimg1.shape)
print("The width, height and depth of this image are ",rimg2.shape)
print("The width, height and depth of this image are ",rimg3.shape)
1a425b1fb4b3bad4b080ef136a4ceb30.png

在 Python 中调整图像大小。

The width, height and depth of this image are  (304, 486, 3)
The width, height and depth of this image are  (202, 324, 3)
The width, height and depth of this image are  (101, 162, 3)

调整图像的亮度/对比度

可以通过OpenCV 中的addWeighted功能来调整图像的亮度/对比度。这是一个称为混合的过程。此函数使用以下转换对图像进行这些调整:

result = αsrc1 + βsrc2 + γ

在上面的等式中,通过将α值应用于源图像、将β值应用于其他图像(它可以是相同的源图像)并将其值增加来修改混合图像γ

混合效果如下图所示。

第一行图显示了α在保持其他两个参数不变的情况下变化的效果(α从左到右递减)。

第二行图显示了β在保持其他两个参数不变的情况下变化的效果(β从左到右增加)。

第三行图显示了γ在保持其他两个参数不变的情况下变化的效果(γ从左到右增加)。

  • 减小α使图像变暗。

  • 增加β使图像具有更强的对比度。

  • 减小γ使图像柔化。

#cv2.addWeighted(source_img1, alpha, source_img2, beta, gamma)
alpha = [0.75, 0.5, 0.25]
beta =  [0, 1 , 10]
gamma = [0, 10 ,100]

#Vary alpha
alpha_img1 = cv2.addWeighted(rgb_img, alpha[0], rgb_img, beta[0], gamma[0])
alpha_img2 = cv2.addWeighted(rgb_img, alpha[1], rgb_img, beta[0], gamma[0])
alpha_img3 = cv2.addWeighted(rgb_img, alpha[2], rgb_img, beta[0], gamma[0])

#Vary beta
beta_img1 = cv2.addWeighted(rgb_img, alpha[0], rgb_img, beta[0], gamma[0])
beta_img2 = cv2.addWeighted(rgb_img, alpha[0], rgb_img, beta[1], gamma[0])
beta_img3 = cv2.addWeighted(rgb_img, alpha[0], rgb_img, beta[2], gamma[0])

#Vary gamma
gamma_img1 = cv2.addWeighted(rgb_img, alpha[0], rgb_img, beta[0], gamma[0])
gamma_img2 = cv2.addWeighted(rgb_img, alpha[0], rgb_img, beta[0], gamma[1])
gamma_img3 = cv2.addWeighted(rgb_img, alpha[0], rgb_img, beta[0], gamma[2])
1b6849b6561570c479449a6bb897238a.png

在 Python 中更改图像的亮度和对比度。

更改图像的色彩空间

图像处理中使用了多种颜色空间,可以促进各种任务,例如边缘检测、颜色检测和应用蒙版等等。

使用 OpenCV 通过cvtColor函数可以很容易地在颜色空间之间进行转换

下面列出了一些常见的色彩空间:

  • RGB -> 许多图像最初都是使用这种格式编码的

  • HSV -> 提供对颜色色调的更好控制

  • 灰色 -> 使许多图像处理方法更准确

改变颜色空间的一些示例如下所示:

gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_RGB2GRAY)
bgr_img = cv2.cvtColor(rgb_img, cv2.COLOR_
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值