python检测屏幕图像_使用Python,有没有办法自动检测图像中的一盒像素?

该任务所需的基本工具/值包括:

>连接组件标签方法;

>确定是否丢弃或保持连接组件的阈值;

>用于计算连接组件之间距离的度量标准以及用于确定是否加入它们的阈值(仅当您确实需要执行此类操作时才需要这一点,这仍然不清楚).

第一个在PIL上不可用,但是scipy提供它.如果您也不想使用scipy,请在https://stackoverflow.com/a/14350691/1832154处考虑答案.我已经使用了该答案的代码,将其修改为使用PIL图像而不是普通列表,并假设其中存在的函数放在一个名为的模块中wu_ccl.对于第三步,我以O(n ^ 2)的方式使用了简单的棋盘距离.

然后,丢弃小于200像素的组件,考虑到小于100像素的组件应位于同一个边界框中,并以10像素填充边界框,这就是我们得到的:

您可以简单地将组件阈值更改为更高的值,以便仅保留最大值.此外,您可以按相反的顺序执行此图像之前提到的两个步骤:首先连接关闭组件,然后丢弃(但这不在下面的代码中完成).

虽然这些是相对简单的任务,但代码并不短,因为我们不依赖于任何库来执行任务.以下是实现上述图像的示例代码,连接组件的合并特别大,我想快速编写代码的代码比需要的大得多.

import sys

from collections import defaultdict

from PIL import Image, ImageDraw

from wu_ccl import scan, flatten_label

def borders(img):

result = img.copy()

res = result.load()

im = img.load()

width, height = img.size

for x in xrange(1, width - 1):

for y in xrange(1, height - 1):

if not im[x, y]: continue

if im[x, y-1] and im[x, y+1] and im[x-1, y] and im[x+1, y]:

res[x, y] = 0

return result

def do_wu_ccl(img):

label, p = scan(img)

ncc = flatten_label(p)

# Relabel.

l = label.load()

for x in xrange(width):

for y in xrange(height):

if l[x, y]:

l[x, y] = p[l[x, y]]

return label, ncc

def calc_dist(a, b):

dist = float('inf')

for p1 in a:

for p2 in b:

p1p2_chessboard = max(abs(p1[0] - p2[0]), abs(p1[1] - p2[1]))

if p1p2_chessboard < dist:

dist = p1p2_chessboard

return dist

img = Image.open(sys.argv[1]).convert('RGB')

width, height = img.size

# Pad image.

img_padded = Image.new('L', (width + 2, height + 2), 0)

width, height = img_padded.size

# "discard" jpeg artifacts.

img_padded.paste(img.convert('L').point(lambda x: 255 if x > 30 else 0), (1, 1))

# Label the connected components.

label, ncc = do_wu_ccl(img_padded)

# Count number of pixels in each component and discard those too small.

minsize = 200

cc_size = defaultdict(int)

l = label.load()

for x in xrange(width):

for y in xrange(height):

cc_size[l[x, y]] += 1

cc_filtered = dict((k, v) for k, v in cc_size.items() if k > 0 and v > minsize)

# Consider only the borders of the remaining components.

result = Image.new('L', img.size)

res = result.load()

im = img_padded.load()

l = label.load()

for x in xrange(1, width - 1):

for y in xrange(1, height - 1):

if im[x, y] and l[x, y] in cc_filtered:

res[x-1, y-1] = l[x, y]

result = borders(result)

width, height = result.size

result.save(sys.argv[2])

# Collect the border points for each of the remainig components.

res = result.load()

cc_points = defaultdict(list)

for x in xrange(width):

for y in xrange(height):

if res[x, y]:

cc_points[res[x, y]].append((x, y))

cc_points_l = list(cc_points.items())

# Perform a dummy O(n^2) method to determine whether two components are close.

grouped_cc = defaultdict(set)

dist_threshold = 100 # pixels

for i in xrange(len(cc_points_l)):

ki = cc_points_l[i][0]

grouped_cc[ki].add(ki)

for j in xrange(i + 1, len(cc_points_l)):

vi = cc_points_l[i][1]

vj = cc_points_l[j][1]

kj = cc_points_l[j][0]

dist = calc_dist(vi, vj)

if dist < dist_threshold:

grouped_cc[ki].add(kj)

grouped_cc[kj].add(ki)

# Flatten groups.

flat_groups = defaultdict(set)

used = set()

for group, v in grouped_cc.items():

work = set(v)

if group in used:

continue

while work:

gi = work.pop()

if gi in flat_groups[group] or gi in used:

continue

used.add(gi)

flat_groups[group].add(gi)

new = grouped_cc[gi]

if not flat_groups[group].issuperset(new):

work.update(new)

# Draw a bounding box around each group.

draw = ImageDraw.Draw(img)

bpad = 10

for cc in flat_groups.values():

data = []

for vi in cc:

data.extend(cc_points[vi])

xsort = sorted(data)

ysort = sorted(data, key=lambda x: x[1])

# Padded bounding box.

bbox = (xsort[0][0] - bpad, ysort[0][1] - bpad,

xsort[-1][0] + bpad, ysort[-1][1] + bpad)

draw.rectangle(bbox, outline=(0, 255, 0))

img.save(sys.argv[2])

同样,需要调整函数wu_ccl.scan(取自上面提到的答案),为此,考虑在其中创建一个模式为“I”的图像,而不是使用嵌套的Python列表.我也对flatten_label稍作修改,因此返回连接组件的数量(但实际上并没有在最终的代码中使用).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值