鱼C论坛

 找回密码
 立即注册
查看: 1280|回复: 9

[已解决]GetPixel读取坐标处颜色出错求助

[复制链接]
发表于 2022-5-4 03:35:05 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 sjyabd 于 2022-5-4 04:47 编辑

求助各位大佬,我自己写了一个小游戏的脚本,功能逻辑很简单,是游戏内商城扫货的。大致原理为:

循环点击商城刷新按钮 -> 判断商品栏位颜色
-> 如果商品未出现,则continue继续刷新
-> 判断如果商品出现,通过GetPixel判断得到显示商品的栏位颜色匹配为制定商品颜色
-> 点击商品选中,点击购买,continue继续循环

我原本想要在睡觉的时候,让小号可以挂机,自动秒所有上架的材料。但是问题是
  • 正常情况应该为:每次刷新商城,货架为空,读取的颜色为(142,155,31)。
  • 当有人上架:货架有了商品,读取的颜色为(166,28,127),这个颜色通过if语句判断匹配后,进入后面的购买操作。购买结束后,继续循环,继续刷新商城。
  • 每次循环到5000次的时候,从5001次开始,GetPixel读取的颜色便不是正常的RGB格式,而是返回(255,255,-1)。导致无法继续读取货架位置的颜色,从而无法判断和购买
  • 手动ctrl+c终止程序,然后再次运行,恢复正常。等循环到5000次的时候,问题再次出现。
  • 尝试用try except来捕捉异常 但是程序其实并没有报错,GetPixel仍然在一直读数出来,但是读到的RGB元组却是不合理的。所以无法用这个办法来解决。
  • 在网上搜索,有人说GetPixel是读取内存里的数据(巴拉巴拉,其他的没看太懂)。我猜想是不是存储颜色的内存满了,就尝试手动释放内存。判断当读数为(255,255,-1),使用gc.collect()释放内存,然后开启新的循环。但该办法无效,释放内存后读数仍为(255,255,-1)。
  • 尝试用双循环来实现,在内循环检测到错误RGB值出现时break,由外循环开启新的循环,以达到自动“重启”的效果。但是该方法失败。
    while True
        while True
            正常的代码循环
            if getPixel == (255,255,-1):
                    break
  • 当使用双循环时,程序运行到3334次开始报错,而不是之前的5000次。不知道为什么报错的次数会在多了一重循环之后减少。希望这个可以给大佬一点线索。


GetPixel处具体代码如下:
def get_colour(x,y):
    gdi32 = windll.gdi32
    user32 = windll.user32
    hdc = user32.GetDC(None)
    pixel = gdi32.GetPixel(hdc, x, y)
    r = pixel & 0x0000ff
    g = (pixel & 0x00ff00) >> 8
    b = pixel >> 16
    return (r,g,b)

其他地方的代码实在是简单的不能再简单了,基本上就是:
While True,
if colour == XXX:,
mouse.click;
if colour == XXX:
continue
应该不是其他地方的代码出的问题。如果大佬需要看整个代码的话,我再贴出来。

最佳答案
2022-5-4 22:26:16
本帖最后由 hrpzcf 于 2022-5-4 22:27 编辑
from ctypes import windll

# 把以下三行从函数内移出,避免每次调用函数都获取一次HDC但又不释放
gdi32 = windll.gdi32
user32 = windll.user32

HDC = user32.GetDC(None)


def get_colour(x, y):
    pixel = gdi32.GetPixel(HDC, x, y)
    r = pixel & 0x0000FF
    g = (pixel & 0x00FF00) >> 8
    b = pixel >> 16
    return (r, g, b)


count = 0
while count < 10000:
    count += 1
    print(f"{count:>10}", get_colour(1000, 800))

# 程序退出时
user32.ReleaseDC(None, HDC)

不知道行不行,代码改不改我都没有成功复现楼主的问题

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-5-4 09:34:28 | 显示全部楼层

回帖奖励 +1 鱼币

没了解过这些,不过这个库有问题自己解决不了,可以找下其他类似功能的库代替吧,可能是库有bug也不一定
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-5-4 14:26:17 | 显示全部楼层
不懂
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2022-5-4 20:15:34 | 显示全部楼层
specail 发表于 2022-5-4 09:34
没了解过这些,不过这个库有问题自己解决不了,可以找下其他类似功能的库代替吧,可能是库有bug也不一定

谢谢建议
我之前其实是从PIL的ImageGrab换到这个GetPixel这里来的
原始的方法是:
每次判断颜色的时候 通过ImageGrab截一张图
然后打开,读取图片
读取图片上指定坐标的颜色。
返回颜色

这样的方法运行起来感觉有点慢,因为每次都要截图、保存、读取的这个过程。我也是为了提高速度和效率才换到这个GetPixel的,这样可以直接从鼠标的坐标位置读到颜色。
我再去研究研究,看看也没有什么其他的库可以实现类似的功能吧,还是谢谢啦!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-5-4 21:02:03 | 显示全部楼层
sjyabd 发表于 2022-5-4 20:15
谢谢建议
我之前其实是从PIL的ImageGrab换到这个GetPixel这里来的
原始的方法是:

我刚刚又用PIL的ImageGrab试了一次
读取100次颜色花费27秒多
平均一下 一秒才能读4次 这还不算进行颜色判断 和后续的操作。。就只是每次循环把颜色print()出来
这个方法确实是有点慢了。。
看来如果想要高效的话 还是得找其他的库 能直接读取的。。
我猜测这个imagegrabe 虽然慢一点但是说不定更稳定吧。。如果没有其他更好的办法就可能只能这样退而求其次了。。
def get_colour(x,y):
    position = x,y
    im = ImageGrab.grab()
    im.save("screentest.png")   
    img_file = Image.open("screentest.png")
    img = img_file.load()   
    colour = img[int(position[0]), int(position[1])]
    return colour

start = time.time()
for x in range(1200,1210): # 随便指定了一块10*10的区域
    for y in range (1000,1010):
        test = get_colour(x,y)
        print('RGB元组为',test)
        print('数组格式为',type(test))
end = time.time()
print('读取100次颜色的时间:', end - start)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-5-4 21:59:02 | 显示全部楼层

回帖奖励 +1 鱼币

学习下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-5-4 22:26:16 | 显示全部楼层    本楼为最佳答案   

回帖奖励 +1 鱼币

本帖最后由 hrpzcf 于 2022-5-4 22:27 编辑
from ctypes import windll

# 把以下三行从函数内移出,避免每次调用函数都获取一次HDC但又不释放
gdi32 = windll.gdi32
user32 = windll.user32

HDC = user32.GetDC(None)


def get_colour(x, y):
    pixel = gdi32.GetPixel(HDC, x, y)
    r = pixel & 0x0000FF
    g = (pixel & 0x00FF00) >> 8
    b = pixel >> 16
    return (r, g, b)


count = 0
while count < 10000:
    count += 1
    print(f"{count:>10}", get_colour(1000, 800))

# 程序退出时
user32.ReleaseDC(None, HDC)

不知道行不行,代码改不改我都没有成功复现楼主的问题

评分

参与人数 1荣誉 +2 鱼币 +2 贡献 +2 收起 理由
sjyabd + 2 + 2 + 2

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-5-4 23:11:10 | 显示全部楼层

回帖奖励 +1 鱼币

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-5-5 00:09:36 | 显示全部楼层

回帖奖励 +1 鱼币

学习下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-5-6 21:16:13 | 显示全部楼层
hrpzcf 发表于 2022-5-4 22:26
不知道行不行,代码改不改我都没有成功复现楼主的问题

哇 兄弟牛批!我按照你的方法把它们移到函数外就没事儿了!昨天晚上运行了一晚上 将近20W次 没有任何的问题!非常感谢!

关于没有复现 我是这么想的,因为我发现出错的时候不总是5000次,当代码变复杂,就变成了3334次。因为我这个脚本还有其他的判断 读取 模拟鼠标的操作,所以感觉起来就好像是,当运行这些代码积累到一定量,达到了临界,就报错了。
如果兄弟你的代码就只有单纯这一个功能,可能积累到这个临界的时间比较长?说不定要运行好几万或十万次?。。

我也不知道。。瞎猜的。。但是非常感谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-18 10:46

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表