Get and store RGB values per pixel on a sprite.

Previous topic - Next topic

erico

Hi guys, gotta a question here and am sorry I didn´t try to figure out much by my own yet.
I thought to ask about to who did this before at least to easy some time.

I want to open an image, loadsprite, and create an 3 arrays holding RGB values of it.
So I did loadsprite and am pasting it on 640x480 screen.
I have the required dim variables at r(640x480), g(640x480) and same for b.

What I´m not getting it how to use the GETPIXEL command in a for/next loop to fill up those arrays.
I´m probably missing something here, is this possible in the first place?

mentalthink

Hi Erico yes the problem it's when you get the colors you get all the channels at the same time, you have to make a "division" in 2^8,2¹16 and 2²4....

I think in sample forlders we have a project doing this... leave I search beacuse I don't know how doing too  :nana:

Here it's Erico...
http://www.glbasic.com/forum/index.php?topic=1637.msg11177#msg11177


erico

Quote from: mentalthink on 2014-Aug-21
...you have to make a "division" in 2^8,2¹16 and 2²4....

What? :O You got to be jocking?

I went to check the link, code is a bit complex on that r,g or b function for me.
But that gives a head on how to approach it, I will check further, thanks! :good:

I must admit I didn´t do much before on checking this, I always thought the GETPIXEL command would deliver something like that but I have never used it.
I did a quick try on 123 basic a couple days ago and I could not work it out, I haven´t checked further but I thought to ask first.

The main reason for knowing how to pull this, is to try write gfx filters. Is that a good approach at all?
It also seems to me that MEM2SPRITE command might be important speed wise somewhere within, but I haven´t used it either.

Anyways, thanks for the answer, the thread is from 2008 so maybe if I just study it I may figure it out.
I wonder if it is possible to read a common shader stuff into GLB, even if it is PC only.
Like read shaders from here maybe?
https://www.shadertoy.com/


kanonet

Sounds like MEM2SPRITE is exactly what you need.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

fuzzy70

MEM2SPRITE/SPRITE2MEM will do what you require, however you will suffer a big performance hit. Somewhere on the forum is a Mandelbrot generator I posted that uses them commands to simulate colour cycling & the frame rate drops to around 30 fps & all that's doing is rotating a table of 256 colours in an array, nothing complex. Both commands add overheads from copying the data from sprite to an array & again back from array to a sprite.

If you want to try & go down that route & need code on the above commands to convert to your array format then let me know but that will incur a performance hit converting the sprite array into the 3 separate arrays you mentioned. If possible it's best to work on the actual array that the sprite commands generate.

GLB doesn't provide support for locked buffer operations hence why SETPIXEL/GETPIXEL are slow, if your could read/write directly to a locked buffer then all manner of pixel effects open up. I know it can be done in SDL but I'm not 100% GLB uses SDL on all platforms & if so how to access it, other than possibly with inline.
Lee

EDIT, found my forum post http://www.glbasic.com/forum/index.php?topic=8670.msg73590#msg73590. Give that a go & see what your FPS does.
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

kanonet

Actually you di not need SPRITE 2MEM every frame. Just do it once and and then keep it in memory. so just do your manipulations on it and MEM2SPRITE each frame. Still a performance hit, but less then using both commands each time (classic trade memory for performance).
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

fuzzy70

True, that was accounting for worse case scenario as don't know exactly what needs to be accomplished.

My mandelbrot prg doesn't use SPRITE2MEM at all as it creates the set directly into the array & MEM2SPRITE is called after the colours have been cycled.

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

erico

Thanks for all answers.

What I want to do is to have control at each image pixesl on a per RGB base.
Simple things first, to write some code to desaturate an image.

Later I think I would like to try some sort of filters, like detect borders and threshold PB image.
That is for image analysis.

spacefractal

if you want to do that run time, then its can been very slow, and on some systems, its might not even working.

SPRITE2MEM is what you looking for.
Genius.Greedy Mouse - Karma Miwa - Spot Race - CatchOut - PowerUp Elevation - The beagle Jam - Cave Heroes 2023 - https://spacefractal.itch.io/

Moru

Quote from: erico on 2014-Aug-21
Quote from: mentalthink on 2014-Aug-21
...you have to make a "division" in 2^8,2¹16 and 2²4....

What? :O You got to be jocking?


I'm affraid not :-)

Colours are stored in one word, 32 bit. Usually something like this in hexadecimal. Not sure about the colour order though but that you can find out in some example or the documentation or just try it out :-)

0xAARRGGBB
A = Alpha channel
R = Red
G = Green
B = Blue

To separate out the different colours from the combined value you need to divide by 256 for each value and then isolate it.

I'm sure you have figured this out already by now but here it is anyway:

To get the separate colour channels you just use a bitmask like this: (untested...)

Code (glbasic) Select

colour% = 0xffdd99
blue% = bAND( colour%, 0xFF)
green% = bAND( (colour% / 0x100), 0xFF)
red% = bAND( (colour% / 0x10000), 0xFF)
alpha% = bAND( (colour% / 0x1000000), 0xFF)


Dividing with hexadecimal 256 (0x100) is just like when we divide decimal 100 to move the decimal point two steps to the left.
Try it out with the windows calculator in programmer mode and you see what I mean :-)

fuzzy70

Here's some example code for you erico that both do the same thing, the 1st uses GETPIXEL & SETPIXEL & the 2nd MEM2SPRITE. All they do is reset the red value to zero so nothing complicated but shows the difference in speed other the 2 methods. I've tried to keep the code as simple as possible with comments & it's intentionally laid out that way so you can see how it works rather than optimal way.

If you don't understand the bitwise operations on modifying the MEM2SPRITE array (bAND) I can explain that in more detail with other examples as to how they work, just PM me or post here & I'll see what I can do.

Example 1, using GET/SETPIXEL, btw the GETPIXEL part takes a long time (~20 seconds on my machine) so don't think the program has crashed just be patient  :D
Code (glbasic) Select
GLOBAL sw%=800,sh%=600
GLOBAL loop%
GLOBAL red%[],green%[],blue%[],alpha%[]
GLOBAL pixel_value%
GLOBAL x%,y%
GLOBAL timer,timetaken

DIM   red[sw][sh]
DIM green[sw][sh]
DIM  blue[sw][sh]
DIM alpha[sw][sh] // Pretty pointless as setpixel has no alpha

SETSCREEN sw,sh,FALSE

// Create some random coloured boxes
FOR loop = 0 TO 1000

DRAWRECT RND(300),RND(300),RND(500),RND(500),RGB(RND(255),RND(255),RND(255))

NEXT

// Loop through the entire screen & read the pixel values into an array
timer = GETTIMERALL()

FOR x=0 TO sw-1
FOR y=0 TO sh-1

// read the pixel value at x,y
pixel_value=GETPIXEL(x,y)

// GLB stores pixels in 32bit alpha,blue,green,red format
// 1st byte is alpha, 2nd byte green & so on
// Read each colour into its respective array
  red[x][y] = bAND(pixel_value, 0xff)
green[x][y] = bAND(ASR(pixel_value,8), 0xff)
blue[x][y] = bAND(ASR(pixel_value,16), 0xff)
alpha[x][y] = bAND(ASR(pixel_value,24), 0xff)

NEXT
NEXT

timetaken = GETTIMERALL()-timer

PRINT "Pixel colours copied to Array",0,0
PRINT "Time taken = "+timetaken,0,8
PRINT "Press any key to continue",0,16

SHOWSCREEN
KEYWAIT

// Now to modify the array by removing all the red colour values
timer = GETTIMERALL()

FOR x=0 TO sw-1
FOR y=0 TO sh-1

red[x][y] = 0

NEXT
NEXT

timetaken = GETTIMERALL()-timer
PRINT "Colours modified, Press any key to view the result",0,0
PRINT "Time taken = "+timetaken,0,8

SHOWSCREEN
KEYWAIT

//Now to draw the array back to screen
timer = GETTIMERALL()

FOR x=0 TO sw-1
FOR y=0 TO sh-1

SETPIXEL x,y,RGB(red[x][y],green[x][y],blue[x][y])

NEXT
NEXT

timetaken = GETTIMERALL()-timer
PRINT "All done, press any key to exit",0,0
PRINT "Time taken = "+timetaken,0,8

SHOWSCREEN
KEYWAIT



Example 2, using MEM2SPRITE
Code (glbasic) Select
GLOBAL sw%=800,sh%=600
GLOBAL loop%
GLOBAL x%,y%
GLOBAL timer,timetaken
GLOBAL memsprite%[]

DIM memsprite[sw*sh]

SETSCREEN sw,sh,FALSE

// Create some random coloured boxes
FOR loop = 0 TO 1000

DRAWRECT RND(300),RND(300),RND(500),RND(500),RGB(RND(255),RND(255),RND(255))

NEXT

// Grab the screen as a sprite then load it into memsprite array
// Grab must be done before showscreen as gets the current backbuffer
// If using virtual screens then grabsprite is not required as you
// just pass the screen sprite number to the SPRITE2MEM call
timer = GETTIMERALL()

GRABSPRITE 1,0,0,sw,sh
SPRITE2MEM(memsprite[],1)

timetaken = GETTIMERALL()-timer

PRINT "Screen grabbed to Array",0,0
PRINT "Time taken = "+timetaken,0,8
PRINT "Press any key to continue",0,16

SHOWSCREEN
KEYWAIT

// Now to modify the array by removing all the red colour values
// Since the mem2sprite array is just one dimension you would normally
// loop from 0 to the end of the array. Here I am doing it the same way
// as the getpixel method for consistancy & illustraion purposes
timer = GETTIMERALL()

FOR x=0 TO sw-1
FOR y=0 TO sh-1

// GLB pixel format is 0xAABBGGRR so as we are just changing the red
// value we bAND 0xffffff00 with the current value in array
// & that will set only the last byte (in this case the red byte) to 0
// leaving the rest untouched
memsprite[x + y * sw] = bAND(memsprite[x + y * sw],INTEGER(0xffffff00))

NEXT
NEXT

timetaken = GETTIMERALL()-timer

PRINT "Colours modified, Press any key to view the result",0,0
PRINT "Time taken = "+timetaken,0,8

SHOWSCREEN
KEYWAIT

//Now to draw the array back to screen
timer = GETTIMERALL()

// Put the array into a sprite then draw the sprite
MEM2SPRITE(memsprite[],2,sw,sh)
DRAWSPRITE 2,0,0

timetaken = GETTIMERALL()-timer

PRINT "All done, press any key to exit",0,0
PRINT "Time taken = "+timetaken,0,8

SHOWSCREEN
KEYWAIT



Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

Hemlos

cool stuff on this thread...

hey erico, look inside my program "image2object"
it has routines for dealing with the colors, and scanning images.

http://www.glbasic.com/showroom.php?site=games&game=Image2Object


ps. yes getpixel is slow...its also inacurate!
Bing ChatGpt is pretty smart :O

erico

SUPER! Thanks you for the hand, that is probably something that would take me quite a while to figure out my own if ever.

Hey Fuzzy, I will experiment them on this weekend and post back here the results, thanks again! :good:

erico

heck, haven´t give it a go yet...I must at some point these months.
Thanks all for the help.

Damn those hex crack my mind.

fuzzy70

Quote from: erico on 2014-Nov-09
Damn those hex crack my mind.

HEX is one of those odd things to get going with, but when "The Penny Drops" so to speak it can make a lot of things easier. Binary is another one, however it can become a bit of a handful when dealing larger numbers as the more digits used the more chance of making a typo & like HEX it makes certain things a lot easier then working in human "Decimal" lol

Lee
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)