FastGetPixel(), FastSetPixel() Speed Improvment

pdabasic

Active Member
Licensed User
I try to write a little pixelization program but at the start it looks like criticaly slow...

Please check my code and tell me how can I improve the speed faster! :sign0163:

Thank you

B4X:
Sub Globals
   'Declare the global variables here.
   Dim Type(Alpha, Red, Green, Blue) col As byte
End Sub

Sub App_Start
   web.New1("Form1",240,0,240,270)
   cap.New1
   img.New1
   web.Navigate("http://www.youtube.com/watch?v=UD3XJDhstNo&feature=related")
   Form1.Show
End Sub

Sub Timer1_Tick
   Dim i, j
   cap.ControlCapture(web.ControlRef,0,0,web.Width,web.Height)
   cap.FastPixelsStart
   img.FastPixelsStart
   For j = 0 To 269
      For i = 0 To 239
         col() = cap.FastGetPixel(i, j)
         img.FastSetPixel(i, j, col.Alpha, col.Red, col.Green, col.Blue)
      Next
   Next
   cap.FastPixelsEnd
   img.FastPixelsEnd
   Image1.Image=img.Image
   Timer1.Enabled=False
   Msgbox()
End Sub

Sub Button1_Click
   Timer1.Enabled=True
End Sub
 

pdabasic

Active Member
Licensed User
As you seem to be doing a straight copy then drawing one image on the other using Drawer.DrawImMage1 or Drawerex.DrawImage would be much much faster.

Thank you Agraham for quick response.
As usual

I will check it!
 

pdabasic

Active Member
Licensed User
I reedited my code with the absolute minimum content's but it's still working for 3-4 seconds... :sign0148:

On the picture you can see what I woold like to solve.
It's working with 30 frame per second.
My project is working 30 second per frame :BangHead:

B4X:
Sub Globals
   'Declare the global variables here.
   Dim Type(Alpha, Red, Green, Blue) col As byte
End Sub

Sub App_Start
   cap.New1
   Form1.Show
End Sub

Sub Button1_Click
   cap.ControlCapture("Form1",0,0,Form1.Width,Form1.Height)
   cap.FastPixelsStart
   For j = 0 To Form1.Width-1
      For i = 0 To Form1.Height-1
         col() = cap.FastGetPixel(i,j)
      Next
   Next
   cap.FastPixelsEnd
   Msgbox()
End Sub
 

Attachments

  • pixelate.jpg
    25.1 KB · Views: 236

pdabasic

Active Member
Licensed User
:sign0163:

I think the FOR Loop statment is very very slow for this project.
What can I use instead of FOR?
 

agraham

Expert
Licensed User
Longtime User
I already told you. Use Drawer.DrawImage1 or Drawerex.DrawImage to draw cap.Image onto your img bitmap.

You would probably be better off using a BitmapEx from ImageLibEx for screen capture as that can be merged into the exe when optimised compiled.
 

pdabasic

Active Member
Licensed User

Sory Agraham, I misunderstanded you.
I thought only this line
B4X:
Image1.Image=img.Image
must I replace with drawex
 

pdabasic

Active Member
Licensed User
Hello Agraham!

I tried what you sugested but it isn't so faster then the prew. code...
Just a little bit

B4X:
Sub Globals

End Sub

Sub App_Start
   bmp.New4
   ret.New1(0,0,240,270)
   bmp.ScreenCapture(ret.Value)
   Form1.Show
End Sub

Sub Button1_Click
   bmp.LockBits
   For j = 0 To ret.Width-1
      For i = 0 To ret.Height-1
         bmp.SetLockedPixel(i,j,bmp.GetLockedPixel(i,j))
      Next
   Next
   bmp.UnlockBits
   Msgbox()
End Sub
 

agraham

Expert
Licensed User
Longtime User
I'm not entirely sure what you are trying to do as the last fragments you posted were functionless, but you have entirely ignored my suggestion.

My Basic4ppc image handling is a bit rusty but assuming you want to display a screen capture then do someting like the following.
B4X:
' do a screen capture
rect.New1(0,0,240,270)
bmpex.ScreenCapture(rect.Value)

' assign it directly to a view, don't f*rt about with loops
Image1.Image=bmpex.value  

' or if needed copy it by drawing it onto another bitmap
bmpexcopy.New2(240,270)
DrawerEx1.New2(bmpexcopy.value)
DrawerEx1.DrawImage(bmpex.value, rect,  rect, false)
 

pdabasic

Active Member
Licensed User
I'm not entirely sure what you are trying to do

I have a led matrix on what I can control any pixel rgb value.
And I would like to control it as a "video wall".

So I need to capture the video for example an youtube webpage and get all pixel rgb value what i can send my led matrix.

What picture I attached you can see a program what can do this, so it is not impossible.

My idea looks like this
B4X:
' do a screen capture
rect.New1(0,0,240,270)
bmpex.ScreenCapture(rect.Value)

' get each pixel curent state and send it to the appropriate rgb led pixel
bmp.LockBits
For j = 0 To ret.Width-1
  For i = 0 To ret.Height-1
    pixelcolor = bmp.GetLockedPixel(i,j))
    'write curent pixelcolor to the appropriate led pixel
     writebytestoMatrix(color,i,j)
  Next
Next
bmp.UnlockBits

To an smoothed video I must to repeat the complete code
minimum 20 times/second
Link to the video what present what I want
 
Last edited:

Basic4Life

Member
Licensed User
Screen capturing seems highly inefficient to process video streams.
But to help you, you need to give much more details.
First, are you running on a smartphone or desktop?
How do you communicate with your LED matrix?
Do you need it to work in real time or can you process the video fully first or cache quite alot?
What resolution is your LED matrix?
Do you only need it for youtube?

Off the top of my head, if you are running on a device, grabbing the direct link to the video via youtube api and then process the stream via DirectShow (But you'll need to write a wrapper to do that in B4PPC) and filter it for only changed pixels, seems to be the best approach

Edit:
Just did a quick google research and it seems there doesn't exist a frameserver that runs on windows mobile, so another idea would be to do all the "work" on a desktop and just transfer the relevant data to your device.
 
Last edited:

pdabasic

Active Member
Licensed User
Hy Basic4Life!

I'm glad to see you here

So it's an desktop only app and I need to do it in real time.

I communicate the led matrix via usb to I2C adapter and i write bytes to the led matrix.

The resolution is chnagable. But first it is 32*32 (this is the smalllest)
 

pdabasic

Active Member
Licensed User
I read about the suggested directshow. I think that's what I'm looking for.

So I don't need the capturing function. With the directshow I can play files in to my app and after this I can get the pixel information of the movie but how with B4P???

I think I must to use the for loop but does it enough fast to this process? Or I must to use the SharpDevelop for this project?
 
Last edited:

Basic4Life

Member
Licensed User
Since you asked, yes SharpDevelop or c# in general is the better choice for this task.
But I like the challenge of doing it in B4PPC.

So I tried it myself (see LED MAtrix.zip). To get the frames in B4PPC, screen capturing is probably your only option without a wrapper for the .net wrapper for Directshow. If you decide to use Sharpdevelop see this link .net Directshow, the samples have a demo for capturing frames. But you still have to get the stream to work/ download the file, resize and crop for your needs. But then going back to B4PPC probably doesn't make much sense, better do your analysis and communication in SharpDevelop too.

My approach also uses the screen capture method. I understand the bottleneck is the analysis performance, due to the higher resolution. So I am outsourcing the resizing of the video to the flash player itself. This is achieved by taking the video url from youtube and then embedding it in a smaller player. In my example I am using 32x32 and it works quite fast. Although I didn't test for pixel analysis yet. (you can change the resolution by changing the embedded template and the capture webbrowser)

Obviously you still have the issues with screen capturing, like no exact starting or ending time or advertising, no audio control, fading timeline and the window mustn't be covered. But my example might give you a starting point.

I also attached another file called Youtube Link Parser, it takes a video page and extracts a somewhat downloadable link to the video itself. It doesn't work with the http library/webrequest/webresponse, but if you enter the url from the textbox at the bottom into the webbrowser or firefox it will prompt you a download window and you can download the video.


Howto opperate LED MATRIX:

click the button called "Youtube" at the top right, browse for the video you want to play. Wait till page is loaded and then click the button "use video"

Edit:

If you know which videos/ animations you want to play ahead of time, you could take a quite different approach and do all the processing first and just store the data stream and send it to the LED matrix when you need it. You'll lose the feature of browsing youtube in realtime but gain a lot more control and performance and this method seems easier to implement

Edit2:
I don't know how your LED matrix is build, but if it has its own controller, is there a chance to declare it as a screen device?
 

Attachments

  • LED MATRIX.zip
    27.2 KB · Views: 242
  • Youtube Link Parser.zip
    7.6 KB · Views: 220
Last edited:
Cookies are required to use this site. You must accept them to continue using the site. Learn more…