如何跟踪具有特定颜色的矩形
Posted
技术标签:
【中文标题】如何跟踪具有特定颜色的矩形【英文标题】:How to track rectangle with specific color 【发布时间】:2016-05-08 06:39:07 【问题描述】:我只找到了面部跟踪的样本。
如何跟踪特定颜色的矩形?
我需要它的像素。
【问题讨论】:
您基本上会遍历屏幕并查找特定的颜色值。一旦你找到它,你必须从那个位置开始迭代一个几乎没有正方形大小的部分,并检查所有值是否匹配。让我告诉你,这是为视频游戏编写机器人的最糟糕的方式,如果你想更新每一帧,即使你找到了优化它的方法,它也很容易出错并且需要大量的计算能力。一种更好的方法是直接从 Ram 或您的套接字流中获取这些坐标,但这在 Python 中是不可能的。 【参考方案1】:这是一个可以做到这一点的脚本:
from PIL import Image
from math import sqrt
RED = 0
GREEN = 1
BLUE = 2
COLORS = [RED, GREEN, BLUE]
RED_HEALTH = (234, 105, 112)
BLUE_HEALTH = (84, 165, 226)
HEALTH_BORDER = (0, 0, 0)
image = Image.open("image.jpg")
def close_enough_to(src, target, delta):
diff = 0
for color in COLORS:
diff += (src[color] - target[color]) ** 2
diff = sqrt(diff)
return diff <= delta
class HealthBar:
def __init__(self, team, health_percentage, length, pos):
self.team = team
self.health_percentage = health_percentage
self.length = length
self.pos = pos
def __str__(self):
return "team , percentage , length , pos ".format(self.team,
self.health_percentage,
self.length,
self.pos
)
def __repr__(self):
return str(self)
def flood_fill_health_bar(image, pos, color, traversed):
(x, y) = pos
health_pixels = 0
while close_enough_to(image.getpixel((x, y)), color) \
and (x, y) not in traversed:
health_pixels += 1
traversed.add((x, y))
x += 1
black_pixels = 0
while close_enough_to(image.getpixel((x, y)), HEALTH_BORDER, 50) \
and (x, y) not in traversed:
black_pixels += 1
traversed.add((x, y))
x += 1
if black_pixels > 0:
if color is RED_HEALTH:
team = "red"
else:
team = "blue"
percent_health = health_pixels / (health_pixels + black_pixels)
return HealthBar(team, percent_health, health_pixels + black_pixels, pos)
def in_bounds(image, pos):
return pos[0] >= 0 and pos[1] >= 0 \
and pos[0] < image.width and pos[1] < image.height
def flood_fill_image(image, start, delta):
flood_fill_queue = [start]
traversed = []
color = image.getpixel(start)
pos = start
pix = image.load()
while len(flood_fill_queue):
(x, y) = flood_fill_queue.pop()
positions = [(x+1, y), (x-1, y), (x, y+1), (x, y-1)]
for position in positions:
if in_bounds(image, position) \
and close_enough_to(image.getpixel(position), color, delta):
if position not in traversed:
flood_fill_queue.append(position)
traversed.append(position)
(x, y) = position
pix[x, y] = (0, 0, 255)
return traversed
def get_width(positions):
return get_max_x(positions) - get_min_x(positions)
def get_height(positions):
return get_max_y(positions) - get_min_y(positions)
def get_max_x(positions):
return sorted(list(positions), key=lambda x: x[0])[-1][0]
def get_max_y(positions):
return sorted(list(positions), key=lambda x: x[1])[-1][1]
def get_min_x(positions):
return sorted(list(positions), key=lambda x: x[0])[0][0]
def get_min_y(positions):
return sorted(list(positions), key=lambda x: x[1])[0][1]
def find_health_bars(image):
traversed = set()
health_bars = []
pix = image.load()
(width, height) = image.size
for col in range(0, width):
for row in range(0, height):
# pix = image.getpixel((col, row))
if (col, row) in traversed:
continue
for health_color in [RED_HEALTH, BLUE_HEALTH]:
border_pixels = []
if close_enough_to(image.getpixel((col, row)), health_color, 10):
health_pixels = flood_fill_image(image, (col, row), 100)
for pos in health_pixels:
(x, y) = pos
traversed.add(pos)
pix[x, y] = (255, 255, 0)
border_pixels = flood_fill_image(image, (col - 1, row - 1), 30)
if len(border_pixels) is 0:
continue
health_bar_width = get_width(border_pixels)
health_bar_height = get_height(border_pixels)
health_width = get_width(health_pixels)
if abs(health_bar_width / health_bar_height) - 10 <= 0.5:
team = "blue" if health_color == BLUE_HEALTH else "red"
percent_health = health_width / health_bar_width
health_bar = HealthBar(team, percent_health, health_bar_width, (col, row))
health_bars.append(health_bar)
for pos in border_pixels:
(x, y) = pos
traversed.add(pos)
pix[x, y] = (0, 255, 255)
health_bars = [health_bar for health_bar in health_bars if health_bar is not None]
health_bars.sort(key=lambda x: x.length)
return health_bars
health_bars = find_health_bars(image)
print(health_bars)
基本上是这样的算法:
-
遍历整个图像,寻找健康条的红色/蓝色
一旦我们找到了,运行一个超级hacky的洪水填充函数来找到健康条占据的坐标。
运行相同的 flood-fill 函数来获取生命值条的边界。
求边框的宽度和生命值的宽度,然后将一个除以另一个得到生命值百分比。
这是计算完洪水填充后的视觉效果(该函数与您的圈子不匹配,但我想这不会成为问题......):
黄色区域是生命条的生命部分,青色是边界。如您所见,它并不完美,但希望它足够接近。另外,我假设您将使用它的图像将是 png 而不是 jpg,这样可以消除一些不准确的地方。
编辑:这是打印health_bars
的输出:
[team blue, percentage 1.0, length 20, pos (66, 433), team blue, percentage 1.0, length 34, pos (130, 436), team red, percentage 0.38095238095238093, length 63, pos (149, 357), team blue, percentage 0.953125, length 64, pos (27, 404), team red, percentage 0.6703296703296703, length 91, pos (480, 119), team red, percentage 0.5700934579439252, length 107, pos (500, 52)]
【讨论】:
非常感谢,马库斯。 RED_HEALTH = (234, 105, 112),作为close_enough_to的一个参数,如何得到健康值? 你的意思是我是怎么想出(234, 105, 112)
的?我只是使用颜色选择器来获取健康栏中像素的 RGB 值。如果你的意思是如何获取一个仆从的生命值,你想看看输出中的percentage
字段。
好吧,我的意思是(234、105、112),我明白了【参考方案2】:
制作一个列表,在其中放置每个仆从,然后遍历该列表并查看它是红色还是蓝色。如果可以的话……
【讨论】:
以上是关于如何跟踪具有特定颜色的矩形的主要内容,如果未能解决你的问题,请参考以下文章
Plotly:如何在 Plotly 中绘制具有渐变颜色的矩形?
Plotly:如何获取跟踪颜色属性以绘制具有相同颜色的选定标记?