Code archives/Graphics/Negative

This code has been declared by its author to be Public Domain code.

Download source code

Negative by MuffinRemnant2002
Slow but functional.
Graphics 800,600,16,1
SetBuffer BackBuffer()
Global av#

; hardcoded for the named bitmap 64x64 pixels...
img=LoadImage("test.bmp")


For y=0 To 63
	For x=0 To 63


		SetBuffer(ImageBuffer(img))		
		GetColor(x,y)
		
		r=ColorRed()
		g=ColorGreen()
		b=ColorBlue()
		
		av=255-(r+g+b)/3
		
		Color av,av,av
		SetBuffer BackBuffer()

		Plot x,y
		
	Next
Next

Flip

WaitKey()

End 

Comments

Doggie2010
It's greyscale, not negative.


Oiduts Studios2010
His last post was 6 years ago, but whatever floats your boat.


Doggie2010
it wasn't meant as personal so much as informational for anyone who's looking for a negative filter. Water...


Streaksy2010
yeh thats greyscale. for negative you'd just do:

r=255-r
g=255-g
b=255-b

instead of the average thing.

would be a lot faster if you unlock the image buffer and graphicsbuffer, use writepixelfast instead of plot, and lock the buffers again. Also, youre setting the current buffer for every pixel. And there was no need to declare av# as global. And instead of FOR X=0 TO 63, etc, use FOR X=0 TO IMAGEWIDTH(IMG)-1

The code's fine but let me chuck in a few optimisations :P


Graphics 800,600,32,2
SetBuffer BackBuffer()

img=LoadImage("test.bmp")
Repeat
Cls
DrawImage img,MouseX(),MouseY()
DrawImageGreyscale img,MouseX()+200,MouseY()+100
DrawImageNegative img,MouseX()+400,MouseY()+200
Flip
Until KeyHit(1)
End




Function DrawImageGreyscale(Img,dx,dy) ;draw a greyscale image of an image on the screen (can be slow if image is large)
LockBuffer ImageBuffer(Img)
LockBuffer GraphicsBuffer()
gw=GraphicsWidth():gh=GraphicsHeight()
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		If dx+x=>0 And dy+y=>0 And dx+x<gw And dy+y<gh Then
		col=ReadPixelFast(x,y,ImageBuffer(img))
		r=(col And $00FF0000) Shr 16:g=(col And $0000FF00) Shr 8:b=(hue And $000000FF)
		average=(r+g+b)/3
		WritePixelFast dx+x,dy+y,average Shl 16 Or average Shl 8 Or average,GraphicsBuffer()
		EndIf
	Next
Next
UnlockBuffer ImageBuffer(Img)
UnlockBuffer GraphicsBuffer()
End Function

Function MakeImageGreyscale(Img) ;convert an image to greyscale so you can draw fast it with DrawImage instead of DrawImageGreyscale.
LockBuffer ImageBuffer(Img)
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		col=ReadPixelFast(x,y,ImageBuffer(img))
		r=(col And $00FF0000) Shr 16:g=(col And $0000FF00) Shr 8:b=(hue And $000000FF)
		average=(r+g+b)/3
		WritePixelFast x,y,average Shl 16 Or average Shl 8 Or average,ImageBuffer(img)
	Next
Next
UnlockBuffer ImageBuffer(Img)
End Function



Function DrawImageNegative(Img,dx,dy) ;draw a negative image of an image on the screen (can be slow if image is large)
LockBuffer ImageBuffer(Img)
LockBuffer GraphicsBuffer()
gw=GraphicsWidth():gh=GraphicsHeight()
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		If dx+x=>0 And dy+y=>0 And dx+x<gw And dy+y<gh Then
		col=ReadPixelFast(x,y,ImageBuffer(img))
		r=(col And $00FF0000) Shr 16:g=(col And $0000FF00) Shr 8:b=(hue And $000000FF)
		r=255-r:g=255-g:b=255-b
		WritePixelFast dx+x,dy+y,R Shl 16 Or G Shl 8 Or B,GraphicsBuffer()
		EndIf
	Next
Next
UnlockBuffer ImageBuffer(Img)
UnlockBuffer GraphicsBuffer()
End Function

Function MakeImageNegative(Img) ;convert an image to greyscale so you can draw fast it with DrawImage instead of DrawImageNegative.
LockBuffer ImageBuffer(Img)
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		col=ReadPixelFast(x,y,ImageBuffer(img))
		r=(col And $00FF0000) Shr 16:g=(col And $0000FF00) Shr 8:b=(hue And $000000FF)
		r=255-r:g=255-g:b=255-b
		WritePixelFast x,y,r Shl 16 Or g Shl 8 Or b,ImageBuffer(img)
	Next
Next
UnlockBuffer ImageBuffer(Img)
End Function



Doggie2010
Wow. Thanks so much. I'm working on a sprite/image editor right now and wanting to add as many effects as I can.

DOG


_PJ_2010
Hate to be a pedantic sod, but grey-scaling isn't actually just a case of resolving the colours to an average. That would be grey-averaging ;)

Don't forget the "Scale" part!

Technically, grey-scaling makes use of the very darkest, and very lightest regions of the image, and scales the grey values of 0 - 255 accordingly, this way, regardless of how light or dark your image contrast spans, the result will always be a gradient from 0 - 255.

Of course, this overcomplicates things a little - Il try and get back to this and code an example soon :)


Floyd2010
To "negate" the r,g,b values in col, turning r into 255-r etc. you can just do this:

col = ~col

The ~ means bitwise not, which simply flips all the bits.

Note this is only suitable for images, not textures. You probably don't want to negate the alpha channel. But Blitz3D images don't have alpha, so no problem.


_PJ_2010
Thanks, Floyd. That's a very handy answer for my question here:
http://www.blitzbasic.com/Community/posts.php?topic=88972

:)


Charrua2010
hi, let me be more technically, that's the formula used on TV equipment as my teacher on this area told me some time ago.

Luminance = Y = 0.3 Red + 0.59 Green + 0.11 Blue

then SetColor y,y,y
to get a gray with the luminance present in the original red, green and blue.

As you can see, the green component is the most significant part on the luminance formula, btw, is for that, that the old monocrome monitors only use de Green signal from the VGA connector.
Out from topic:
I remember some time ago, palying Indiana Jones and the fate of Atlantis..., in some part of the game, he enters a cave with lava every where, obviously all were black or red, nobody see anything on the contemporaneous monochrome monitors, execpt those wiht an expensive color moinitor.

i didn't try this formula wiht images, but is te more exact one we should try.

Juan


xlsior2010
the reason for that 0.3/0.59/0.11 is that the human eye has different sensitivities to the various wavelengths of light.

Your eyes have a much harder time seeing blue than they do seeing green and red. Some image compression formats make use of that fact when compressing images:

If you seperate a picture in the R, G and B layers, you can compress the snot out the blue layer before the human eye really starts noticing it. It's much more important to preserve the green layer, and red to a lesser extend.

Simple experiment: take a color photo, and resize the blue layer to a quarter of the original resolution and then stretch it back to its original size. LAyer it with the original red and green, and the picture will still look pretty decent.
do the same thing to the green layer instead (and keep red/blue original), and it will look like crap.


Streaksy2010
Floyd: col = ~col .... brillant! Much faster. Also, mine wasn't giving true negative!

Doggie... what other effects do you want help with? =D

So true greyscaling is just adjusting the channels' ratios? Cool, thats easy enough. 0.3/0.59/0.11. I'll remember that.


Here's the revised code going by everyone's tips. (thanks)




Graphics 800,600,32,2
SetBuffer BackBuffer()

img=LoadImage("test.png")
Repeat
Cls
DrawImage img,MouseX(),MouseY()
DrawImageGreyscale img,MouseX()+200,MouseY()+100
DrawImageNegative img,MouseX()+400,MouseY()+200
Flip
Until KeyHit(1)
End




Function DrawImageGreyscale(Img,dx,dy) ;draw a greyscale image of an image on the screen (can be slow if image is large)
LockBuffer ImageBuffer(Img)
LockBuffer GraphicsBuffer()
gw=GraphicsWidth():gh=GraphicsHeight()
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		If dx+x=>0 And dy+y=>0 And dx+x<gw And dy+y<gh Then
		col=ReadPixelFast(x,y,ImageBuffer(img))
		r=(col And $00FF0000) Shr 16:g=(col And $0000FF00) Shr 8:b=(hue And $000000FF)
		average=((r*.3)+(g*.59)+(b*.11))
		WritePixelFast dx+x,dy+y,average Shl 16 Or average Shl 8 Or average,GraphicsBuffer()
		EndIf
	Next
Next
UnlockBuffer ImageBuffer(Img)
UnlockBuffer GraphicsBuffer()
End Function

Function MakeImageGreyscale(Img) ;convert an image to greyscale so you can draw fast it with DrawImage instead of DrawImageGreyscale.
LockBuffer ImageBuffer(Img)
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		col=ReadPixelFast(x,y,ImageBuffer(img))
		r=(col And $00FF0000) Shr 16:g=(col And $0000FF00) Shr 8:b=(hue And $000000FF)
		average=(r+g+b)/3
		WritePixelFast x,y,average Shl 16 Or average Shl 8 Or average,ImageBuffer(img)
	Next
Next
UnlockBuffer ImageBuffer(Img)
End Function



Function DrawImageNegative(Img,dx,dy) ;draw a negative image of an image on the screen (can be slow if image is large)
LockBuffer ImageBuffer(Img)
LockBuffer GraphicsBuffer()
gw=GraphicsWidth():gh=GraphicsHeight()
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		If dx+x=>0 And dy+y=>0 And dx+x<gw And dy+y<gh Then
		col=ReadPixelFast(x,y,ImageBuffer(img))
		col=~col
		WritePixelFast dx+x,dy+y,col,GraphicsBuffer()
		EndIf
	Next
Next
UnlockBuffer ImageBuffer(Img)
UnlockBuffer GraphicsBuffer()
End Function

Function MakeImageNegative(Img) ;convert an image to greyscale so you can draw fast it with DrawImage instead of DrawImageNegative.
LockBuffer ImageBuffer(Img)
w=ImageWidth(img):h=ImageHeight(img)
For x=0 To w-1
	For y=0 To h-1
		col=ReadPixelFast(x,y,ImageBuffer(img))
		col=~col
		WritePixelFast x,y,col,ImageBuffer(img)
	Next
Next
UnlockBuffer ImageBuffer(Img)
End Function



Doggie2010
Yep, I do think that's better.
I'd like a good sketch routine. I got one started but it's really just angled lines. I could use help with an outline filter and making anaglyph images is always fun for me.(See StereoSpun 2 in ToolBox)The filters aren't really that integral a part of a sprite editor but they are fun to mess with. I'm drawing to an image buffer that is 224by224 if you're wondering. I'd also like a magnification routine. I tried just drawing another buffer slightly bigger but that's no help since I need to magnify rather than enlarge the whole image. So if you got some code along any of those lines I'd be interested.


Streaksy2010
Nope sorry but I could probably knock up punch/skew filters or something :P Maybe posturise, soften, nothing too fancy. Or rotation with a custom angle (instead of multiples of 90)


_PJ_2010
I recall xlsior taught me about those wavelengths and the sensitivity of the human eye elsewhere.

Tghe following omits those ratio differences, though (Very simply, it would require a bit more checking which I didn't wish to go into right now) but the following should greyscale an image proportionately as with 'true' greyscaling albeit without clsior's modifcation.

This method will eb significantl slower, though ive tried to optimise it as best as possible, with fewer function calls and using biitwise operaytions where possible. The main reason for the speed difference, is that it was necessary to store the aRGB values read, then modify them to scale them correctly, beore writing. This means basically, that there are two loops, one for read, one for write as opposed to streaksy's single loop. Also, to store the values, I used an array.

Dim GreyScale(1,1)

Function GreyScaleImage(Img)
	Local Lowest=254
	Local Highest=1

	Local w=ImageWidth(Img)
	Local h=ImageHeight(Img)
	
	Dim GreyScale(w,h)
	
	Local x=0
	Local y=0

	Local RGB
	Local Grey
	
	LockBuffer ImageBuffer(Img)
	
	For x=0 To w-1
		For y=0 To h-1
			RGB=ReadPixelFast(x,y,ImageBuffer(Img))
		Grey=(((RBG And 255) Shl 16) + ((RGB And 255) Shl 8) + (RGB And 255)  ) * 0.333
			If  (Grey<Lowest)
				Lowest=Grey
			Else
				If  (Grey>Highest) Then Highest=Grey
			End If
			GreyScale(x,y)=Grey
		Next
	Next
	
	LockBuffer ImageBuffer(Img)
	Ratio=(Highest-Lowest) Shr 8
	For x=0 To w-1
		For y=0 To h-1
			Grey=GreyScale(x,y) / (Ratio Shl 8)
			WritePixelFast(x,y,(0 Or ((Grey And 255) Shl 16)) Or ((Grey And 255) Shl 8) Or (Grey And 255),ImageBuffer(Img))
		Next
	Next
	UnlockBuffer(ImageBuffer(Img))
	Return Img		
End Function



Streaksy2010
Gawd. Didnt know greyscaling was such a debated issue :P


Doggie2010
I think the more controversial issue is whether it's spelled with an "a" or an "e".
The above code needs to decide on "img" or "image" and Blitz wasn't happy about that "dim" statement not appearing elsewhere in my code. (just for arguments sake) ;)
Thanks for all the input.

Here's VisualBasic code for edge detection. Might be a start.

Function FindEdges(ByVal K As Integer) As Image

Dim image1 As Bitmap
Try

image1 = New Bitmap(m_StartingImage)
Dim x, y As Integer
Dim r1, r2, g1, g2, b1, b2, D1, D2, DTotal As Integer

' Loop through the images pixels to Extract the (R,G ,B) components of this pixel.
For x = 0 To image1.Width - 1
For y = 0 To image1.Height - 1
Dim pixelColor As Color = image1.GetPixel(x, y) 'get starting pixel color
r1 = pixelColor.R
g1 = pixelColor.G
b1 = pixelColor.B
If x < image1.Width - 1 Then
get pixel color right of last pixel
pixelColor = image1.GetPixel(x + 1, y)
r2 = pixelColor.R
g2 = pixelColor.G
b2 = pixelColor.B
D1 = Math.Sqrt((r1 - r2) ^ 2 + (g1 - g2) ^ 2 + (b1 - b2) ^ 2)
'Get differance in color
End If<br />

If y < image1.Height - 1 Then
'Get Pixel below
pixelColor = image1.GetPixel(x, y + 1)
r2 = pixelColor.R
g2 = pixelColor.G
b2 = pixelColor.B
D2 = Math.Sqrt((r1 - r2) ^ 2 + (g1 - g2) ^ 2 + (b1 - b2) ^ 2)
'Get differance in color

End If

If D1 > K Then
Dim newColor1 As Color = Color.FromArgb(pixelColor.R, 0, 0)
image1.SetPixel(x, y, newColor1)
ElseIf D2 > K Then
Dim newColor1 As Color = Color.FromArgb(pixelColor.R, 0, 0)
image1.SetPixel(x, y, newColor1)
Else
Dim newColor2 As Color = Color.FromArgb(pixelColor.R, 255, 255, 255)
image1.SetPixel(x, y, newColor2)
End If
Next
Next
Return = image1

Catch ex As Exception<br />

MessageBox.Show("There was an error.")
'Add error logging and recovery
End Try<br />

End Function


_PJ_2010
oops sorry! I corrected the earlier code - I initially had Image, but when I noticed the other posts used "Img" I went through changing them.. musta missed a couple!

Oh and I rememnbered the initial Dim(1,1) too :)


Code Archives Forum