MixImages function help

BlitzPlus Forums/BlitzPlus Programming/MixImages function help

Dabbede(Posted 2003) [#1]
Hello everybody! I need an help. I need to speed up a little this function...can anyone help me? Thanks!
Function MixImages(mix,ima1,ima2)

	b1=ImageBuffer(ima1)
	b2=ImageBuffer(ima2)
	bm=ImageBuffer(mix)

	LockBuffer b1
	LockBuffer b2
	LockBuffer bm
	
	For y=0 To Screen_Height
		For x=0 To Screen_Width 
			c1=ReadPixelFast(x,y,b1)
			c2=ReadPixelFast(x,y,b2)
			WritePixelFast x,y,c1+c2,bm
		Next
	Next

	UnlockBuffer bm
	UnlockBuffer b2
	UnlockBuffer b1
	
End Function



DarkEagle(Posted 2003) [#2]
right, you cant just add the 2 colors. what you are going to have to do is split the color into its red, green, and blue components, add these together, and write back. theres functions to split/combine colors in the archives :)


Sir Gak(Posted 2003) [#3]
Three thoughts on your dilemna.
First:
When you use the following line:
WritePixelFast x,y,c1+c2,bm 

you have to remember that the red, green, and blue values each are limited to values of 0 to 255. If you do a straight across the board c1+c2, where if the sum of any red, green, or blue values could add together to more than 255, there could be unpredictable results. Try this to illustrate what I am saying:
Graphics 800,600

c1=$ffaabbcc ;using red, green, blue values that will
c2=$ffaabbcc ;overflow, that is, go greater than 255 each
c3=c1+c2
Print Hex$(c3) ;this operation effectively halves the color

Color $aa,$bb,$cc  ;ie the original color
Rect 100,100,200,200

Color (c3 And $ff0000) Shr 16,(c3 And $ff00) Shr 8,(c3 And $ff) ;ie the colors added togther
Rect 400,100,200,200

MouseWait()
End


Second:
I don't know what the effects are of using the lockbuffer command three times sequentially. Maybe some other voices can address this point.

Third (to go faster):
You could try reading the color values of the images into arrays, then instead of doing ReadPixelFast on-the-fly, the values could just be read back in from the array. It's a little more memory intensive, but is faster. In other words, put the following OUTSIDE the function:
dim c1(Screen_Width-1,Screen_Height-1);arrays are global
dim c2(Screen_Width-1,Screen_Height-1)
For y=0 To Screen_Height 
For x=0 To Screen_Width 
c1(x,y)=ReadPixelFast(x,y,b1) 
c2(x,y)=ReadPixelFast(x,y,b2)  
Next 
Next 


Then you can access that info inside your Function:
For y=0 To Screen_Height 
For x=0 To Screen_Width 
WritePixelFast x,y,c1(x,y)+c2(x,y),bm 
Next 
Next 


Of course, this latter bit of code still doesn't address the issue of summing RGB color values together when they can overflow past 255 within their 0-255 range. Depending on what you want to do, you might read in the red, green and blue values separately into intergers, add the integers together and divide by two (if an average is what you're looking for), or just let the color info max out at 255. Generally, these two concepts are illustrated thus:
my_red = (c1_red+c2_red)/2 ;if averaging is what you want

(OR)
my_red = (c1_red+c2_red):if my_red>255 then my_red=255



Dabbede(Posted 2003) [#4]
I've tried to make something like what you said:
Dim c1(Screen_Width-1,Screen_Height-1) 
Dim c2(Screen_Width-1,Screen_Height-1) 
Dim cm(Screen_Width-1,Screen_Height-1) 

Function MixImages(mix,ima1,ima2)

	buf1=ImageBuffer(ima1)
	buf2=ImageBuffer(ima2)
	bufm=ImageBuffer(mix)

	LockBuffer buf1
	LockBuffer buf2
	LockBuffer bufm
	
	For y=0 To Screen_Height-1
		For x=0 To Screen_Width-1
			c1(x,y)=ReadPixelFast(x,y,buf1)
			c2(x,y)=ReadPixelFast(x,y,buf2)
		Next
	Next
	
	For y=0 To Screen_Height-1
		For x=0 To Screen_Width-1
			red1=GetRed(c1(x,y))     :  red2=GetRed(c2(x,y))
			green1=GetGreen(c1(x,y)) :  green2=GetGreen(c2(x,y))
			blue1=GetBlue(c1(x,y))   :  blue2=GetBlue(c2(x,y))
			
			rm=red1+red2 : If rm>255 Then rm=255
			gm=green1+green2 : If gm>255 Then gm=255
			bm=blue1+blue2 : If bm>255 Then bm=255
			
			cm(x,y)=Combine(rm,gm,bm)
		Next
	Next

	For y=0 To Screen_Height-1
		For x=0 To Screen_Width-1
			WritePixelFast x,y,cm(x,y),bufm
		Next
	Next

	UnlockBuffer bufm
	UnlockBuffer buf2
	UnlockBuffer buf1
	
End Function

But it is slower than what I wrote yesterday! I think that using all this arrays it isn't usefull.
Is the code similar to what you thought?

A last question: how can I wrote the codes in green in this forums? Thanks!


Tiger(Posted 2003) [#5]
What are the forum codes?


Dabbede(Posted 2003) [#6]
Thanks Tiger!


Sir Gak(Posted 2003) [#7]
When you add the colors together, what effect are you trying to make happen? In other words, "why" are you adding the colors together? Depending on the effect, you might do better to logically "OR" them, or logically "AND" them. For example, instead of c3=c1+c2, use this:
c3= (c1 OR c2).
or use this:
 c3=(c1 AND c2) 

Whenever you are inside a loop, you always want the fastest possible operations occurring. The closer you can get to the LEAST number of operations occurring inside a loop, the faster will be the loop's total execution time. Also, certain operations are FASTER than others. IF you can logically OR/AND them, that will be faster than adding them together and then dividing by two (regarding the logical OR or the logical AND, either operation is only one(1) operation, thereby taking less time than adding and dividing, which are two operations which therefore use more time).

Back to your original question, can the READPIXELFAST commands be executed outside the function, or are the graphics content in the imagebuffers going to be ever-changing and therefore have to be done inside the Function? If the latter, then don't bother with the arrays, because that becomes extra work for the CPU, and then of course that takes more time. If this is the situation, go back to your original code, and instead of doing a addition (ie c1+c2) operation, try the (c1 OR c2), or the (c1 AND c2).

Ahh, nuts. It's hard to offer suggestions, because I'm not sure what effect you are going for. Could you enlighten me a wee bit? Thanks.


Dabbede(Posted 2003) [#8]
I had to Mix two images with the OR operation (thanks, i didn't know that I could write "c1 OR c2") because I had to show the two views of a stereo-camera in only one screen! This is the problem!
Yes, it could be written out of the function but since the 2 images change every frame, I must write the ReadPixelFast inside the main loop, and so I cant get any speed improvement...
Otherwise I can texture 2 sprites (with alpha=0.5) with the images and then render them, but I dont know how far must they be from the camera, in order to render them in 1:1 scale factor. I should try with Orthographic Projection... mmh... let's try!


Dabbede(Posted 2003) [#9]
Nothing to do... it works very fast but the sprites are shifted a little and the textures on them seem to be smaller than the screen width-height. Can anyone tell me how to solve this bug? (Texture size and offset from camera)


Sir Gak(Posted 2003) [#10]
Yes, the OR operation would blend two colors together, and there is no need to separate out the individual RGB values either to do it (time saver, there). Logical AND tends to subtract colors, rather than blend them together. In fact, logical AND is what is used to mask a graphics image so that the non-black portion of an image is rendered, but not the black portion (assuming of course that the default COLOR 0,0,0 is used for the transparent mask color).

Back to your speed problem. After thinking about it a bit, I realized that you are doing the readpixelfast / writepixelfast on a LOT of pixels! At 640x480, you are reading 307200 pixels each for b1 and b2, and then OR-ing those together and writing 307200 pixels, for a total of 921600 pixels. At 800x600, the total jumps to 1440000 pixels! That's smokin'!

If I understand your application, you are working in the Graphics3d mode (you mentioned Texture and Camera), and are trying to do a 3d-stereoscopic-type image.

If this is the case, is it necessary to do the entire screen's area for each imagebuffer, or can you get away with a portion of the screen?

If you MUST use the entire screen, take a look at the triple lockbuffer commands set you are using in your Function as I mentioned in point 2 of my original response. I don't know if using three lockbuffers is OK, or if they are in any way impeding each other. One way to find out, is to lockbuffer the first imagebuffer, read its color info into an array, then unlock it and lock the second imagebuffer, reading it into another array, unlock it, then lock the third imagebuffer, and writepixelfast (via logical OR) the two array values into it, finally unlocking it. See if that causes any speed increase.


Sir Gak(Posted 2003) [#11]
Hello, I was re=reading your original code. The following three lines are incorrect, I think:
b1=ImageBuffer(ima1) 
b2=ImageBuffer(ima2) 
bm=ImageBuffer(mix) 


The docs show imagebuffer as a command to use with setbuffer, as in:
Setbuffer Imagebuffer(handle)


From the code
 Function MixImages(mix,ima1,ima2) 
I assume that you are supplying the Function with image handles. Therefore, if I understand the command properly, the proper way to use it inside your function would be like this:
;arrays are global, so they will be seen inside your function
Global Const Screen_Width=640
Global Const Screen_Height=480
dim b1array(Screen_Width-1,Screen_Height-1) 
dim b2array(Screen_Width-1,Screen_Height-1)
;arrays are dimensioned minus one, because they start
;counting at 0, ie (0 to 639) x (0 to 479) for 640x480
;
Function MixImages(bm,b1,b2)
;where bm,b1 and b2 are the graphic images handles 
;you are mixing together.
LockBuffer Imagebuffer(b1)
For y=0 To Screen_Height-1 
  For x=0 To Screen_Width-1 
    b1array(x,y)=ReadPixelFast(x,y) 
  Next 
Next 
unLockBuffer Imagebuffer(b1)

LockBuffer Imagebuffer(b2)
For y=0 To Screen_Height-1 
  For x=0 To Screen_Width-1 
    b2array(x,y)=ReadPixelFast(x,y) 
  Next 
Next 
unLockBuffer Imagebuffer(b2)
 
LockBuffer Imagebuffer(bm)
For y=0 To Screen_Height-1 
  For x=0 To Screen_Width-1 
    WritePixelFast x,y,(b1array(x,y) OR b2array(x,y)) 
  Next 
Next 
unLockBuffer Imagebuffer(bm)
End Function 




Dabbede(Posted 2003) [#12]
The commands
b1=ImageBuffer(ima1) 
b2=ImageBuffer(ima2) 
bm=ImageBuffer(mix) 

are ok, because the function "ImageBuffer()" return the handle of the image buffer, and so it is more quick use a variable (b1,b2,bm) instead calling every time ImageBuffer()... now I'll try your last code... wait!


Dabbede(Posted 2003) [#13]
Nothing... FPS are the same!
And so it means that lock 3 buffer it's allowed, too!

I think the only way is to reduce the resolution (but it is about 11 Fps at 320x200!!!) to reduce the number of pixel that must be calculated, or use 2 sprites as I say yesterday. The last idea sounds very good, but I don't know how to apply it


cyberseth(Posted 2003) [#14]
Don't forget to use Flag 2 for mixing images in Blitz+ 1.34.

img1 = LoadImage("image1.bmp",2)
img2 = LoadImage("image2.bmp",2)

This will make the imagebuffers WAY faster! I discovered also that you should really never mix two different types of image buffers or your program will slow down drastically!

[edit]
Also, try out the 3 different graphics drivers in Blitz. Native, OpenGL and DirectDraw, and see which one is fastest. Use SetGfxDriver(1 - 3)
[/edit]


Dabbede(Posted 2003) [#15]
Thanks Cyberseth :)

But now I managed to use 2 sprites in front of my camera to mix the 2 images...I need no more help! Anyway, thanks for the tips! :D


Dabbede(Posted 2003) [#16]
Now I've added my code to the code archives, 3d section ("Stereoscopic Camera")! Thanks to all the persons who have helped me in this forum! And also thanks for having understood me even if I'm not good in english :D
Bye


Dabbede(Posted 2003) [#17]
A special thanks comes to Tobias Müller, who has written the "TEXTURE-HUD" code which has helped me a lot!