加速截图功能 - Python
Accelerating a screenshot function - Python
我需要我的截图功能尽可能快,现在每次调用该功能大约需要 0.2 秒。
这是函数:
def get_screenshot(self, width, height):
image = self.screen_capture.grab(self.monitor)
image = Image.frombuffer('RGB', image.size, image.bgra, 'raw', 'BGRX')
image = image.resize((int(width), int(height)), Image.BICUBIC) # Resize to the size of 0.8 from original picture
image = np.array(image)
image = np.swapaxes(image, 0, 1)
# This code below supposed to replace each black color ([0,0,0]) to the color of [0,0,1]
# r1,g1,b1 = [0,0,0] and r2,g2,b2 = [0,0,1]
red, green, blue = image[:, :, 0], image[:, :, 1], image[:, :, 2]
mask = (red == r1) & (green == g1) & (blue == b1)
image[:, :, :3][mask] = [r2, g2, b2]
return image
你注意到我可以做些什么来使函数更快吗?
编辑: 忘记说的一些细节:
我的屏幕尺寸是1920*1080
此功能是我目前正在进行的直播项目的一部分。 Carlo 在下面建议的解决方案在这种情况下不合适,因为远程计算机将不会与我们的计算机屏幕同步。
这只是我的意思的一个例子。
如果它解决了问题,请告诉我。
您可以创建两个不同的线程。一个截取屏幕截图,另一个稍后详细说明屏幕。两者都将结果添加到列表中。
这提高了 get_screenshot 函数的速度。但要详细说明,您需要函数执行所需的时间。
import threading
#import your stuff
class your_class(object):
def __init__(self):
self.images = list()
self.elaborated_images = list()
threading.Thread(name="Take_Screen", target=self.get_screenshot, args=(width, height))
threading.Thread(name="Elaborate_Screen", target=self.elaborate_screenshot)
def get_screenshot(self, width, height):
while True:
images.append(self.screen_capture.grab(self.monitor))
def elaborate_screenshot(self):
while True:
image = self.images[0]
image = Image.frombuffer('RGB', image.size, image.bgra, 'raw', 'BGRX')
image = image.resize((int(width), int(height)), Image.BICUBIC) # Resize to the size of 0.8 from original picture
image = np.array(image)
image = np.swapaxes(image, 0, 1)
# This code below supposed to replace each black color ([0,0,0]) to the color of [0,0,1]
# r1,g1,b1 = [0,0,0] and r2,g2,b2 = [0,0,1]
red, green, blue = image[:, :, 0], image[:, :, 1], image[:, :, 2]
mask = (red == r1) & (green == g1) & (blue == b1)
image[:, :, :3][mask] = [r2, g2, b2]
del self.images[0]
self.elaborated_images.append(image)
your_class()
因为我没有你的完整代码,所以我无法尽可能地构建它。
由于您的代码不完整,我只能猜测可能有什么帮助,所以这里有一些想法...
我从一张 1200x1200 的图片开始,因为我不知道你的有多大,由于你代码中的注释,我将它缩小了 0.8 倍到 960x960。
我加速它的想法是基于使用不同的插值方法,或者使用高度优化的 SIMD 代码的 OpenCV。一个或两个都合适,但我不知道你的图片是什么样的,只有你能说。
所以,我们开始吧,首先使用 PIL resize()
和不同的插值方法:
# Open image with PIL
i = Image.open('start.png').convert('RGB')
In [91]: %timeit s = i.resize((960,960), Image.BICUBIC)
16.2 ms ± 28 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [92]: %timeit s = i.resize((960,960), Image.BILINEAR)
10.9 ms ± 87.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [93]: %timeit s = i.resize((960,960), Image.NEAREST)
440 µs ± 10.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
因此,BILINEAR 比 BICUBIC 快 1.5 倍,真正的赢家是 NEAREST,快 32 倍。
现在,转换为 Numpy 数组(正如您正在做的那样)并使用高度优化的 OpenCV SIMD 代码调整大小:
# Now make into Numpy array for OpenCV methods
n = np.array(i)
In [100]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_CUBIC)
806 µs ± 9.81 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [101]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_LINEAR)
3.69 ms ± 29 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [102]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_AREA)
12.3 ms ± 136 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [103]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_NEAREST)
692 µs ± 448 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这里的获胜者看起来像 INTER_CUBIC,比 PIL 的 resize()
.
快 20 倍
请全部尝试一下,看看哪种适合您!只需删除行首的 Python 魔术 %timeit
和 运行 剩下的内容。
我需要我的截图功能尽可能快,现在每次调用该功能大约需要 0.2 秒。
这是函数:
def get_screenshot(self, width, height):
image = self.screen_capture.grab(self.monitor)
image = Image.frombuffer('RGB', image.size, image.bgra, 'raw', 'BGRX')
image = image.resize((int(width), int(height)), Image.BICUBIC) # Resize to the size of 0.8 from original picture
image = np.array(image)
image = np.swapaxes(image, 0, 1)
# This code below supposed to replace each black color ([0,0,0]) to the color of [0,0,1]
# r1,g1,b1 = [0,0,0] and r2,g2,b2 = [0,0,1]
red, green, blue = image[:, :, 0], image[:, :, 1], image[:, :, 2]
mask = (red == r1) & (green == g1) & (blue == b1)
image[:, :, :3][mask] = [r2, g2, b2]
return image
你注意到我可以做些什么来使函数更快吗?
编辑: 忘记说的一些细节:
我的屏幕尺寸是1920*1080
此功能是我目前正在进行的直播项目的一部分。 Carlo 在下面建议的解决方案在这种情况下不合适,因为远程计算机将不会与我们的计算机屏幕同步。
这只是我的意思的一个例子。 如果它解决了问题,请告诉我。
您可以创建两个不同的线程。一个截取屏幕截图,另一个稍后详细说明屏幕。两者都将结果添加到列表中。 这提高了 get_screenshot 函数的速度。但要详细说明,您需要函数执行所需的时间。
import threading
#import your stuff
class your_class(object):
def __init__(self):
self.images = list()
self.elaborated_images = list()
threading.Thread(name="Take_Screen", target=self.get_screenshot, args=(width, height))
threading.Thread(name="Elaborate_Screen", target=self.elaborate_screenshot)
def get_screenshot(self, width, height):
while True:
images.append(self.screen_capture.grab(self.monitor))
def elaborate_screenshot(self):
while True:
image = self.images[0]
image = Image.frombuffer('RGB', image.size, image.bgra, 'raw', 'BGRX')
image = image.resize((int(width), int(height)), Image.BICUBIC) # Resize to the size of 0.8 from original picture
image = np.array(image)
image = np.swapaxes(image, 0, 1)
# This code below supposed to replace each black color ([0,0,0]) to the color of [0,0,1]
# r1,g1,b1 = [0,0,0] and r2,g2,b2 = [0,0,1]
red, green, blue = image[:, :, 0], image[:, :, 1], image[:, :, 2]
mask = (red == r1) & (green == g1) & (blue == b1)
image[:, :, :3][mask] = [r2, g2, b2]
del self.images[0]
self.elaborated_images.append(image)
your_class()
因为我没有你的完整代码,所以我无法尽可能地构建它。
由于您的代码不完整,我只能猜测可能有什么帮助,所以这里有一些想法...
我从一张 1200x1200 的图片开始,因为我不知道你的有多大,由于你代码中的注释,我将它缩小了 0.8 倍到 960x960。
我加速它的想法是基于使用不同的插值方法,或者使用高度优化的 SIMD 代码的 OpenCV。一个或两个都合适,但我不知道你的图片是什么样的,只有你能说。
所以,我们开始吧,首先使用 PIL resize()
和不同的插值方法:
# Open image with PIL
i = Image.open('start.png').convert('RGB')
In [91]: %timeit s = i.resize((960,960), Image.BICUBIC)
16.2 ms ± 28 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [92]: %timeit s = i.resize((960,960), Image.BILINEAR)
10.9 ms ± 87.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [93]: %timeit s = i.resize((960,960), Image.NEAREST)
440 µs ± 10.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
因此,BILINEAR 比 BICUBIC 快 1.5 倍,真正的赢家是 NEAREST,快 32 倍。
现在,转换为 Numpy 数组(正如您正在做的那样)并使用高度优化的 OpenCV SIMD 代码调整大小:
# Now make into Numpy array for OpenCV methods
n = np.array(i)
In [100]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_CUBIC)
806 µs ± 9.81 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [101]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_LINEAR)
3.69 ms ± 29 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [102]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_AREA)
12.3 ms ± 136 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [103]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_NEAREST)
692 µs ± 448 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
这里的获胜者看起来像 INTER_CUBIC,比 PIL 的 resize()
.
请全部尝试一下,看看哪种适合您!只需删除行首的 Python 魔术 %timeit
和 运行 剩下的内容。