Read pixels from another program.

Just starting out? Need help? Post your questions and find answers here.
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Read pixels from another program.

Post by matalog »

How can I read pixels from whatever program that is displaying screen data on whatever part of the screen I instruct the program to look at?

For this project, reading a single pixel from a few sceeen coordinates will be fine.

I will eventually want an overlay to float above the pixels being read at the time.

Any ideas or similar projects?
User avatar
Fig
Enthusiast
Enthusiast
Posts: 352
Joined: Thu Apr 30, 2009 5:23 pm
Location: Côtes d'Azur, France

Re: Read pixels from another program.

Post by Fig »

There are 2 methods to program bugless.
But only the third works fine.

Win10, Pb x64 5.71 LTS
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Re: Read pixels from another program.

Post by matalog »

Thanks, I was hoping for something that could read 9 individual pixels, in less than 1 millisecond. To be honest I only want to check if it is black or white (or close to either).

I saw the use of GetPixel_() in that thread, tried that out, and it takes around 18 milliseconds to get one single pixel's colour. I won't be able to use that.

I also see BitBlt being used, and said to be faster, but I don't really understand how it is used yet. Is it possible to quickly read one single pixels colour with BitBlt?
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Re: Read pixels from another program.

Post by matalog »

Would it be easier to do If I only wanted to read from a single window of another running program?
Fred
Administrator
Administrator
Posts: 18167
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Read pixels from another program.

Post by Fred »

Just wondering, why do you need to read other programs pixels ?
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Re: Read pixels from another program.

Post by matalog »

Fred wrote: Sun Aug 25, 2024 7:44 pm Just wondering, why do you need to read other programs pixels ?
I'm planning a little visual communication setup - I have written the encoder program, which will make 8 boxes black or white depending if the bit of data is set, now I want to write a decoder, and I want the 2 to be seperate for various reasons.

I also plan to get a program to read the score or other data from a retro computer emulator during gameplay.
Fred
Administrator
Administrator
Posts: 18167
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: Read pixels from another program.

Post by Fred »

Looks cool 👍
BarryG
Addict
Addict
Posts: 4160
Joined: Thu Apr 18, 2019 8:17 am

Re: Read pixels from another program.

Post by BarryG »

matalog wrote: Sun Aug 25, 2024 7:05 pmI saw the use of GetPixel_() in that thread, tried that out, and it takes around 18 milliseconds to get one single pixel's colour. I won't be able to use that.
Maybe try this non-threaded version (I haven't timed it). You can use Red(), Green() and Blue() on the result if needed; or for your black/white test the result will simply be #Black or #White.

Code: Select all

Procedure PixelColor(x,y)
  c=-1
  hDC=GetDC_(0)
  If hDC
    c=GetPixel_(hDC,x,y)
    ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure
Mr.L
Enthusiast
Enthusiast
Posts: 146
Joined: Sun Oct 09, 2011 7:39 am

Re: Read pixels from another program.

Post by Mr.L »

I was just about to post a similar approach as BarryG.
Scanning 9 Pixels takes around 5 ms on my outdated Laptop...
(Activate the DPI-Aware switch)

Code: Select all

Define hwnd, hdc, pt.Point,p1.Point, rc.RECT, x, y
Define wid = 3, hig = 3,size = 50
Dim color(wid,hig)

OpenWindow(0,0,0,wid*size,hig*size,"", #PB_Window_Tool|#PB_Window_SystemMenu)
CanvasGadget(0,5,5,WindowWidth(0)-10,WindowHeight(0)-10)
StickyWindow(0, 1)

Repeat
	Define time = ElapsedMilliseconds()
	If pt\x <> DesktopMouseX() Or pt\y <> DesktopMouseY()
		pt\x = DesktopMouseX()
		pt\y = DesktopMouseY()
		
		hwnd = WindowFromPoint_(PeekQ(pt))
		If hwnd
			hdc = GetDC_(hwnd)
			If hdc
				For y = 0 To hig-1
					For x = 0 To wid-1
						p1\x = pt\x + x - wid/2
						p1\y = pt\y + y - hig/2
						If ScreenToClient_(hwnd , p1)
							color(x, y) = GetPixel_(hdc, p1\x, p1\y)
						EndIf
					Next
				Next
				ReleaseDC_(hwnd, hdc)
			EndIf
		EndIf	
		
		SetWindowTitle(0, Str(ElapsedMilliseconds() - time) + " ms")
		StartDrawing(CanvasOutput(0))
		For y = 0 To hig-1
			For x = 0 To wid-1
				Box(OutputWidth()/wid*x,OutputHeight()/hig*y,OutputWidth()/wid,OutputHeight()/hig,color(x,y))
			Next
		Next
		StopDrawing()
	EndIf
	
	While WindowEvent():If Event()=#PB_Event_CloseWindow:End:EndIf:Wend
ForEver
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Re: Read pixels from another program.

Post by matalog »

Thanks, yes, the way you use GetPixel_() seems to be faster.

The pixel coordinates seem to be different from purebasic, coordinates, is that possible?
Mr.L
Enthusiast
Enthusiast
Posts: 146
Joined: Sun Oct 09, 2011 7:39 am

Re: Read pixels from another program.

Post by Mr.L »

the coordinates used in GetPixel_ are relative to the window (client area) rather than the entire screen. The origin (0, 0) in window coordinates is usually the top-left corner of the window's client area.
Therefore I use ScreenToClient_ to convert the screen coordinates (DesktopMouseX() / DesktopMouseY()) to the windows coordinates.
Also the DPI scaling affects the coordinates, that's why you have to enable the "Enable DPI aware executable" switch in the Compiler Options.
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Re: Read pixels from another program.

Post by matalog »

Can you see why this is taking a much longer time in my program, I would like it to be a procedure:

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0

Global Dim pi.i(9)
Procedure PixelColor(x,y)
  Shared pi
  c=-1
  hDC=GetDC_(0)
  If hDC
    For a=1 To 9
    pi(a)=GetPixel_(hDC,a*50-20+50,100)
    ;SetPixel_(hDC,a*50-20+1+50,100+1,255)
    Next
ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure


  
    StartTime.q = ElapsedMilliseconds()    
    PixelColor(0,0)
    newcol=pi(9)
 Debug ElapsedMilliseconds() - StartTime 
It seems to take around 150 ms to read the 9 pixels.
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Re: Read pixels from another program.

Post by matalog »

Nevermind, I got that just as fast as yours:

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0
Define hwnd, hdc, pt.Point,p1.Point, rc.RECT, x, y
Define wid = 3, hig = 3,size = 50
Dim color(wid,hig)

Global Dim pi.i(9)
Procedure PixelColor(x,y)
  Shared pi,pt,pi
  c=-1
  hwnd = WindowFromPoint_(PeekQ(pt))
  hdc = GetDC_(hwnd)
  If hDC
    For a=1 To 9
    pi(a)=GetPixel_(hDC,a*50-20+50,100)
    ;SetPixel_(hDC,a*50-20+1+50,100+1,255)
    Next
ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure


  
    StartTime.q = ElapsedMilliseconds()    
    PixelColor(0,0)
    newcol=pi(9)
 Debug ElapsedMilliseconds() - StartTime 
   
User avatar
matalog
Enthusiast
Enthusiast
Posts: 304
Joined: Tue Sep 05, 2017 10:07 am

Re: Read pixels from another program.

Post by matalog »

To test if GetPixel_() works for what I want I have 2 programs here that should be run together. Their debugged output's should be the same if GetPixel_() was working as I expected.

What is causing the strangley randomly wrong debugged numbers in the first program?

Run the first program first, then, it will wait for the second program to be run, and both will print to debug windows.

The second program uses its own image and POINT to test the pixels, the first program uses GetPixel_() on the second program's image.

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0
Define hwnd, hdc, pt.Point,p1.Point, rc.RECT
Define wid = 3, hig = 3,size = 50
Dim color(wid,hig)

Global Dim pi.i(9)
Procedure PixelColor(x,y)
  Shared pi,pt,pi,p1
  c=-1
  hwnd = WindowFromPoint_(PeekQ(pt))
  hdc = GetDC_(hwnd)
  If hDC
    For a=1 To 9
      p1\x=a*50+3+20
      p1\y=100+3
      ScreenToClient_(hwnd,p1)
      pi(a)=GetPixel_(hDC,p1\x,p1\y)
      SetPixel_(hDC,p1\x+1,p1\y+1,255)
      SetPixel_(hDC,p1\x+1,p1\y,255)
      SetPixel_(hDC,p1\x+1,p1\y-1,255)
      SetPixel_(hDC,p1\x,p1\y+1,255)
      SetPixel_(hDC,p1\x,p1\y-1,255)
      SetPixel_(hDC,p1\x-1,p1\y,255)
      SetPixel_(hDC,p1\x-1,p1\y+1,255)
      SetPixel_(hDC,p1\x-1,p1\y-1,255)
    Next
    ReleaseDC_(0,hDC)
  EndIf
  ProcedureReturn c
EndProcedure


Repeat
  
  PixelColor(0,0)
  newcol=pi(9)
  If newcol<>lastcol
    tot=tot+1
    temp=0
    For x=1 To 8
      power.i=1<<((x-1))
      temp=temp+Bool(pi(x)>10000)*power
    Next
    Debug temp
    
    lastcol=newcol
  EndIf
  
  
  
Until tot>60
And the second program.

Code: Select all

Global lastcol.i=1234,newcol.i=0,tot.i=0

#width=500
#height=900

OpenWindow(0,0,0,#width,#height,"Flash Bits")

CreateImage(0,#width,#height)
ImageGadget(0,0,0,#width,#height,ImageID(0))

Global byte.a=0
Global x.i=0
Global flip.a=0
Global temp.a=0

StartDrawing(ImageOutput(0))
Box(0,0,#width,#height,0)
Box(0,0,#width,#height,0)
StopDrawing()
SetGadgetState(0,ImageID(0))

For t=1 To 100
  byte=t
StartDrawing(ImageOutput(0))
For x=1 To 8
      power.i=1<<((x-1))
  Box(x*50,0,50,700,#White*Bool(byte & power))
Next
StopDrawing()
SetGadgetState(0,ImageID(0))
StartDrawing(ImageOutput(0))
Box(9*50,0,40,800,flip*#White)
If flip
  flip=0
Else
  flip=1
EndIf
temp=0

For x=1 To 8
  power.i=Pow(2,x-1)
  temp=temp+Bool(Point(x*50+2,100+2)>10000)*power
Next
s$="Point()= "+Str(temp)
Debug s$
StopDrawing()
SetGadgetState(0,ImageID(0))
  Event =WindowEvent()
  Select Event
    Case #PB_Event_CloseWindow
      End
  EndSelect
Delay(1000)
Next
Repeat
 
  Event =WindowEvent()
  Select Event

    Case #PB_Event_CloseWindow
      End
  EndSelect
  


Until 0
End
Post Reply