-1

Is there any way to achieve faster color reading than what I wrote?

class MyApi:
    def __init__(self):
        self.width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
        self.height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
        self.left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
        self.top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
        self.hwin = win32gui.GetDesktopWindow()
        self.hwindc = win32gui.GetWindowDC(self.hwin)
        self.srcdc = win32ui.CreateDCFromHandle(self.hwindc)

        self.memdc = self.srcdc.CreateCompatibleDC()

        self.bmp = win32ui.CreateBitmap()
        self.bmp.CreateCompatibleBitmap(self.srcdc, self.width, self.height)
        self.memdc.SelectObject(self.bmp)

    def get_xy_color(self, *args):
        self.memdc.BitBlt((0, 0), (self.width, self.height), self.srcdc, (self.left, self.top), win32con.SRCCOPY)
        bmp = self.bmp.GetBitmapBits(False)
        # colors = []
        # for pixel in args:
        #     tmp = (pixel[1] * self.width + pixel[0]) * 4
        #     colors += [255 + c if c < 0 else c for c in bmp[tmp:tmp+3]][::-1]
        # return colors

Uncommented get_xy_color part takes about 0.11 ms - it is far too long for my purposes. Can it be faster?

BitBlt is pretty fast, but GetBitmapBits is taking long time.
Also I can say that I don't need whole screen info, I would be happy if I would get some part of it, for example from point (100, 100) to (150, 150).

The purpose is to get a colors at least 30 times a second for Ambilight project.

Marek
  • 1,189
  • 3
  • 13
  • 33
  • Should this be migrated to Code Review? – Rob Murray Jan 18 '16 at 20:01
  • This may be a good question for [codereview.se], so long as: **(A)** _the code works_, **and (B)** _it's not hypothetical or incomplete in any way_. Please read the [on-topic guide](http://codereview.stackexchange.com/help/on-topic) before posting, if you choose to go to [Code Review](http://codereview.stackexchange.com/questions/ask). If you have any questions or concerns, join us at our [CR Help Desk](http://chat.stackexchange.com/rooms/34045). – Phrancis Jan 18 '16 at 20:06
  • *"It is far too long for my purposes"* - Well, what are your purposes? We cannot recommend a solution, without knowing the problem you are trying to solve. – IInspectable Jan 18 '16 at 20:38
  • So for me it is suggested to migrate question to CodeRevies, but this http://stackoverflow.com/questions/34872664/python-3-better-iterate-over-list-or-over-range-of-indexes question has been migrated to SO. I think that dilema is almost the same. Even my fits more SO, because I am asking for something faster (I know there is something faster) and in mentioned question there is only comparison of two methods. Weird. – Marek Jan 19 '16 at 09:54
  • I would suggest you to clearly describe that do you want to accomplish. You wrote ambient light project. where does the color should be from? My first approach would be to just take a view samples from the screen border. maybe a few GetPixel calls on hdc 0 are enough for this. – vlad_tepesch Jan 19 '16 at 17:17
  • One `GetPixel` lasts about few ms. Don't wanna think about the time for 100 pixels. – Marek Jan 19 '16 at 22:37

1 Answers1

1

Here you go jotto:

    self.bmp = win32ui.CreateBitmap()
    self.bmp.CreateCompatibleBitmap(self.srcdc, self.width, 80)
    self.memdc.SelectObject(self.bmp)

def get_xy_color(self, left, right):
    self.memdc.BitBlt((0, -500), (self.width, 580), self.srcdc, (self.left, self.top), win32con.SRCCOPY)
    bmp = self.bmp.GetBitmapBits(False)

This will focus on a line between 500 and 500 px on height and full width of screen. I was just not aware that I can use negative values. I have checked how to do this by saving bitmap as a file and seeking for good solution.

For now I do not proccess whole screen and reduced time to between 10 and 20 ms. WHich is perfect result for me.

Purpose of the code was for AmbiLight projects. Colors are being send through Serial Port to Arduino, which proccess this to LED colors.

With this solution I am able to do between 39 and 60 gets&sends to Arduino - good result.

Marek
  • 1,189
  • 3
  • 13
  • 33
  • That's what I meant: You never provided a sufficient explanation of your problem, or a succinct specification for a solution. I'm pretty sure you could use [DWM Thumbnails](https://msdn.microsoft.com/en-us/library/windows/desktop/aa969541.aspx) for your purposes. Highly optimized code, built right into the system. Filtering comes for free. – IInspectable Jan 18 '16 at 21:54
  • I've seen zero solutions using DWM to do the job. I've even see people that dissuade DWM. Are you able to Provide anything in particular? – Marek Jan 19 '16 at 06:16
  • what exactly does your `GetBitmapBits` do? the win32 function `GetBitmapBits` is deprecated and the replacement `GetDIBits` copies bitmap data that seems to be not necessary since you already have your own bitmap. – vlad_tepesch Jan 19 '16 at 17:23
  • It would be great if you could provide me some example how to use GetDIBits, because I cannot find myself. – Marek Jan 19 '16 at 22:39
  • I've found example over here: http://nullege.com/codes/show/src@m@s@mss-0.0.7@mss.py/701/ctypes.windll.gdi32.GetDIBits (line 701), but it returns me an array of this: ` – Marek Jan 19 '16 at 23:04