Create a grayscaled image on the fly?

BlitzMax Forums/BlitzMax Beginners Area/Create a grayscaled image on the fly?

Grisu(Posted 2006) [#1]
Hi!

Has someone written a function that grayscales an existing image file handle?

Grisu


CS_TBL(Posted 2006) [#2]
Tested once, looked ok.
Didn't verify anything tho :P

SuperStrict

Local window:TGadget=CreateWindow("o_O",0,0,640,480)
Local canvas:TGadget=CreateCanvas(0,0,640,480,window)
Local img:TImage=LoadImage("Porn193882.JPG")

MakeGrey img

SetGraphics CanvasGraphics(canvas)
	Cls
	DrawImage img,0,0
Flip
Notify "o_O"
End


Function MakeGrey(img:TImage)
	If img=Null RuntimeError "no image!"
	Local c:Int
	Local x:Int
	Local y:Int
	Local pm:TPixmap=LockImage(img)
		For y=0 Until ImageHeight(img)
			For x=0 Until ImageWidth(img)
				c= ReadPixel(pm,x,y) & 255
				c:+(ReadPixel(pm,x,y) Shr 8) & 255
				c:+(ReadPixel(pm,x,y) Shr 16) & 255
				c:/3
				WritePixel pm,x,y,$ff000000|c+256*c+65536*c
			Next
		Next
	UnlockImage img
End Function



FlameDuck(Posted 2006) [#3]
Has someone written a function that grayscales an existing image file handle?
Yes, Birdie has. Check the FilmClip sample that's distributed along with BlitzMAX. It's in /samples/birdie/misc/filmclip/.


CS_TBL(Posted 2006) [#4]
grmbl, that birdie-example just froze my system pretty hard..


Grisu(Posted 2006) [#5]
Thanks everyone!

My guess is Birdies code is faster as it only uses ONE readpixel a time!

edit: The code works fine and IS A LOT FASTER!

Function ConvertToBW(i:TImage,frame)
  Local col,a,r,g,b,cc,x=0,y=0
  Local pix:TPixmap
  
  pix=LockImage(i,frame)
  While y<i.height
    x=0
    While x<i.width
      col = ReadPixel( pix, x, y )
      a = ( col & $ff000000)
      r = ( col & $ff0000 ) Shr 16
      g = ( col & $ff00 ) Shr 8
      b = ( col & $ff )
      cc= (r+g+b)/3
      col = a | (cc Shl 16) | (cc Shl 8) | cc
      WritePixel( pix, x, y, col )
      x=x+1
    Wend
    y=y+1
  Wend
  UnlockImage i,frame
EndFunction



CS_TBL(Posted 2006) [#6]
uh yeah.. st00pid me.. ^_^


ImaginaryHuman(Posted 2006) [#7]
Some ideas on how you can make that faster:

Get rid of having to store all the components in separate variables, and also get rid of putting the combined components into the col variable - just do the combining in the WritePixel.

Get rid of the ReadPixel and the WritePixel because they each require a calculation (that includes a multiply) to work out where in memory to read/write the pixel data. Just use an Int Ptr pointing to the base address of the pixmap memory, and make sure to add any additional pitch to the end of each row. Then use address[x] to read/write the data, and add width in pixels at the end of each row to skip to the next row.

Take out the i.height and i.width, put them in local variables outside the loops and call the local variables.

Local pix:TPixmap can be just Local pix:TPixmap=LockImage(i,frame)

It's not necessarily faster to use a While/Wend than to use a For-Next - you are only doing manually what a for-next loop would do automatically

Try and find a way to get rid of the /3


Anyway, that aside, you shouldn't have to do this `offline` away from video memory, you can probably get your image to render in grayscale using some blend mode of the graphics card hardware.


Grisu(Posted 2006) [#8]
This one is faster, but now the image is all dark blue... :(
Function ConvertBW(i:TImage)
  Local w,h,col,a,r,g,b,cc,x=0,y=0
  Local pix:TPixmap=LockImage(i)

  h= i.height
  w= i.width
  While y < h
    x=0
    While x < w
      col = ReadPixel( pix, x, y )
      col = ( col & $ff000000) | ((col & $ff0000) Shl 16) | ((col & $ff00) Shl 8) | (col & $ff)
      WritePixel( pix, x, y, col )
      x=x+1
    Wend
    y=y+1
  Wend
  UnlockImage i
EndFunction



TartanTangerine (was Indiepath)(Posted 2006) [#9]
You guys are going about it all the wrong way : http://www.blitzbasic.com/Community/posts.php?topic=56099


BlackSp1der(Posted 2006) [#10]

This one is faster, but now the image is all dark blue... :(



Because you forgot something

col = ( col & $ff000000) | ( ((col & $ff0000) Shr 16) + ((col & $ff00) Shr 8) + (col & $ff) )/3 * 65793


and what about it?. create a pixmap image with format ' PF_I8 - 8 bit intensity'

Graphics 640,480,0

Local full:TPixmap=LoadPixmap("IMAGEN.jpg")
Local gray:TPixmap=CreatePixmap(PixmapWidth(full),PixmapHeight(full),PF_I8,1)

For Local y:Int=0 To PixmapHeight(full)-1
	For Local x:Int=0 To PixmapWidth(full)-1
		WritePixel( gray, x, y, ReadPixel( full, x, y ) )
	Next
Next

DrawPixmap gray,100,100
Flip
WaitKey()


or........!

Graphics 640,480,0

Local full:TPixmap=LoadPixmap("IMAGEN.jpg")
Local gray:TPixmap

gray=full.Convert(PF_I8)
DrawPixmap gray,100,100

Flip
WaitKey()



Grisu(Posted 2006) [#11]
Thanks for the code BlackSp1der!

Seems as fast as it can get... :)