SyntaxBomb - Indie Coders

Languages & Coding => BlitzMax / BlitzMax NG => Topic started by: Hardcoal on February 28, 2020, 15:22:10

Title: ReadPixel WritePixel speed
Post by: Hardcoal on February 28, 2020, 15:22:10
Hi, Im using Xors3D and I use Writepixel and readpixel commands.
the writepixel is much slower than readpixel.. in xors3d
is it the same in blitzmax read write pixel?

also is there anything that can be done to make it faster?

Cheers
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 01, 2020, 13:59:40
I guess no one has a clue
Title: Re: ReadPixel WritePixel speed
Post by: TomToad on March 01, 2020, 14:22:34
ReadPixel and WritePixel commands themselves are actually quite fast.  The problem comes when you need to display the imgae.  The image is modified in the CPU's memory, so must be transfered over the bus to the GPU's memory before it can be displayed.  This actually takes time.  That is why it takes so much longer to write to an image than read from it.
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 01, 2020, 16:56:56
But when im writing pixel i dont display it..
so i dont understand why its slow
Title: Re: ReadPixel WritePixel speed
Post by: Matty on March 01, 2020, 17:58:36
How many pixels are you writing?

A full screen or a handful?

How many functions, calculations are you doing per pixel?

Are you performing any slow operations per pixel such as square roots or trig functions?

Are you calculating rgb values with a function call or a calculation?
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 01, 2020, 19:52:23
I do no function calculation on the pixel i just read a pixel from one image and and write on another and it can start from 1000 and get to million approx..

Title: Re: ReadPixel WritePixel speed
Post by: Matty on March 01, 2020, 21:22:23
Well if there are no calculations or processing why not use a copyrect method instead of pixel writing and reading?
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 01, 2020, 22:22:00
because i need to read pixel by pixel for what im doing.. :)
but thanks for the suggestion :) here is what  im working on https://1drv.ms/u/s!ArSvOuhm7L3ko51b1gpP7GPIeBy8bw?e=HXdnj7
Title: Re: ReadPixel WritePixel speed
Post by: Matty on March 01, 2020, 23:47:06
Okay.  Here is another suggestion.

Do all your readpixels in one set.

Then all the writepixels.

In otherwords dont alternate between reading 1 pixel then writing 1 pixel.

Do them all at once.

Also if you can do multithreading then read each channel r g b and a in a thread each and process each colour channel on a separate thread.
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 02, 2020, 04:44:09
very interesting idea! ill give it a try! thanks

i have no clue about multi threading.. never dealed with it
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 02, 2020, 07:27:59
Have a data portion to work on ... and use a Mutex to protect write accesses to it. Unlock the mutex everytime you are done.

For "numbers" this is not problematic as you can simple have threads eg do
pixels 0-99
pixels 100-199
pixels 200-299
...

So none of these groups overlap. They do not change memory addresses - but straight content of "numbers" in the number array (a pixmap is a row of integers containing RGB(A)).

So perfect for threaded processing.


Yet it is better to describe what you actually are doing - as a pixmap of 2k*2k is not that "slow" to compute each frame, but if you compute a 8k*8k 20 times a frame, then you might run into trouble.


Another idea is to make it "async" - so give it to a thread to process and use the old one until the thread is done (so it might be there in the same frame - or 1000 seconds later).


bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: TomToad on March 02, 2020, 09:06:59
Unfortunately your link is asking me for a password for some reason.  But is it possible to do what you want using shaders?  This will allow you to process your images directly on the GPU, which means fast.
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 02, 2020, 10:23:42
I clicked on the link and it downloaded a PNGSplitter.rar (automatically) and it was able to unpack it.

According to the name he wants to read parts from a pixmap and create a new pixmap out of it. But maybe it is for some live preview or so.

Would be good to know in "abstract" what Hardcoal wants to do exactly.


bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 02, 2020, 10:59:07
Ill fix the link soon

What im doing is taking a tile set single png and turning it into separate pngs
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 02, 2020, 11:13:12
Yes - and this should be "blazing fast" - exception is if you need to find the sprites on your own (eg minimum island size) and then do auto-crop etc.

But this is not strictly readpixel/writepixel slowness then but also the algorithm you use.


So ... assume we have 10 sprites on an image - and you know the coords + dimension of each. Extracting this data into new PNGs, is this then slow for you? I doubt it.

As said _read_ access to TPixmap can be multithreaded without much hassle.


Next to classic "threading" you could use what @Brucey once wrote: some "Workers" (you then just pass your task "split images" to the workers and they spawn as much as required, and once done they spawn new ones if there are still images to strip from the image). Means you do not have a fixed amount of threads you send out to strip image slices but a flexible amount of runners utilizing threads - more on this if interested.

So the more you explain (without loosing yourself in too much implementation details) the more easily we could help and spot issues.


bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 02, 2020, 12:21:48
Ill simply post the code
But again it's in xors
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 02, 2020, 13:46:50
Thought you were using TPixmap (Max2D) ?

local img:TPixmap = LoadPixmap("your.png")
local otherImg:TPixmap = CreatePixmap(tileW, tileH, img.format)
otherImg.WritePixel(x,y, img.ReadPixel(x - offsetX, y - offsetY))


bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 02, 2020, 16:54:42
ok here is part of my code.

Derron Hi.. I dont need it to be blazing fast just normally fast :)

i didnt read all replies well im on a hurry ill go through them later..

mean while here is part of my code..

also a new link to my demo https://drive.google.com/file/d/1kugyDoI-uF_XwkHDkiu_lE2yWnJkOvzU/view?usp=sharing

Method ReadPNG(ImageHandle, CurrentX = 0, CurrentY = 0, Pixel[,] Var)
Local X, Y, StartX, StartY, NewPixel[ximagewidth(imagehandle), ximageheight(imagehandle)]
Local LeftX, RightX, UpY, DownY

   'Start
Local Coords:Coords_Class = New Coords_Class
Coords = GetFirstEmptyPoint(ImageHandle, Pixel)
If Coords.X = -1 Then Return 'End Of Trace
StartX = Coords.X
StartY = Coords.Y
LeftX = StartX
RightX = StartX
UpY = StartY
DownY = StartY
    NewPixel[StartX, StartY] = OccupiedPix 'A Must
    Pixel[StartX, StartY] = OccupiedPix    'Not Certain
Coords = Null

   'Left To Right
For Y = StartY To xImageHeight(ImageHandle) - 1

For X = 0 To xImageWidth(ImageHandle) - 1

   'Is UnChecked
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return

TimedUpdateGraphics()

Next

Next

   'Right To Left And Down To Up
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1

For X = xImageWidth(ImageHandle) - 1 To 0 Step - 1

   'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()

Next

Next

   'Up To Down  [All Seems To Work]
For X = 0 To xImageWidth(ImageHandle) - 1

For Y = 0 To xImageHeight(ImageHandle) - 1

   'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()

Next

Next

   'Down To Up
For X = 0 To xImageWidth(ImageHandle) - 1

For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1

   'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()

Next

Next

   'Write The Image
Local NewImage = Xcreateimage (RightX - LeftX, DownY - UpY)
For Y = UpY To DownY
For X = LeftX To RightX

If NewPixel[X, Y] = OccupiedPix Then
  xWritePixel(X - LeftX, Y - UpY, xReadPixel(X, Y, xImageBuffer(ImageHandle)), xImageBuffer(NewImage))
  End If

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()

Next
Next

Return NewImage
End Method
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 02, 2020, 19:38:17
So ... you want to split tiles from a tilemap. What happens if you have "islands" in the tile?.
Eg. There is a "sky tile" which has some separate clouds.

How to handle this?

You can only automate this if then the tiles are in a "grid" layout - so you define tile width and other stuff (like grid spacing). If you have dynamically sized tiles then you cannot have "islands" (or they will end up becoming separate sprites).

Edit: also important - certain image editors (GIMP!) do not set RGB information when deleting stuff - they just set the alpha value to 0. So when exporting your tileset and then compare against a color like "0" (rgba(0,0,0,0)) this will ignore these "only made transparent" pixels. So better compare for the alpha value.


Edit2: http://www.spritecow.com/ (js sources available) might be interesting to check out. So the interesting part is this: https://github.com/jakearchibald/sprite-cow/blob/master/www/assets/script/SpriteCanvas.js

If your tilemaps are always in a grid layout it is just a matter of cutting out the tiles and then removing all rows/cols with all pixels' alpha values being 0 ("auto cropping").


Edit3: https://github.com/bmarwane/spriteSplitter/blob/master/app/js/loader.js this does it a bit more "verbose".


bye
Ron


Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 02, 2020, 20:28:25
My program does exactly what I desired it to do..
In some cases it may not be suitable for some people, but in 99% of the times It will be fine..
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 02, 2020, 20:36:27
I still do not know what it should do - compared to what it actually does (there is a missing function in your sample too).

This is why I asked for an abstract of what it should do - not an implementation of what you do.


bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 02, 2020, 22:07:47
Sorry Derron.. I was so busy today in so many things.. i didnt have time to really look through the posts.. into details..

Ive added a Tileset in the folder of the Program like this one.. (https://i.imgur.com/Z5UexG8.png)
Press LoadTileSet Button and choose this png.. than press ConverToPNGS
After a while it will turn from a single Image to a multiple PNG Images.
It was made for my Editor use at first..
So I wont need to use photo shop to seperate tiles and save them one by one.

Yea its a work in progress..
so I dont blame you if youre confused..

Anyway.. its all going fine for me besides the speed thing..
but ill fix it later.. for now all is ok..
I prefer to deal with progressing this , instead of messing with the speed issue atm.

im gonna open a new thread soon . only for this little software.. and add the latest Demo

Thanks Derron for your Care

Title: Re: ReadPixel WritePixel speed
Post by: Matty on March 02, 2020, 22:18:33
That looks nice Hardcoal.

However, if I understand you want a program to extract the individual square tiles from that tileset, or any tileset.

Perhaps a faster way would be the following algorithm.

1. Get width and height of image.
2. Find first non transparent pixel in a column.
3. Find first non transparent pixel in a row.
4. Find shortest distance in rows and columns to next transparent pixel.
5. Combining knowledge from points 2 to 4 you have the size of each tile plus its initial offset.
6. Grab rectangles of size defined in 5 and spit them out.
7. If there is transparency issues with resulting image then store transparency in greyscale image and recombine later.

Ignore if I'm completely off base.
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 02, 2020, 23:12:28
Matty its all working fine.. I just tried to make it faster lol thats all..
Ill put the latest version of my App Soon.
Title: Re: ReadPixel WritePixel speed
Post by: Matty on March 03, 2020, 05:01:08
Exactly, hence I suggested a faster algorithm than reading and writing every individual pixel.
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 03, 2020, 06:48:58
What happens if you replace that xors commands with some pure tpixmap commands? Maybe this is the speed culprit?


Bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: TomToad on March 03, 2020, 12:18:50
Quote from: Hardcoal on March 02, 2020, 22:07:47

Ive added a Tileset in the folder of the Program like this one.. (https://i.imgur.com/Z5UexG8.png)
Press LoadTileSet Button and choose this png.. than press ConverToPNGS
After a while it will turn from a single Image to a multiple PNG Images.

Challenge Accepted, and accomplished https://www.syntaxbomb.com/index.php/topic,7474.msg347040328.html#msg347040328 (https://www.syntaxbomb.com/index.php/topic,7474.msg347040328.html#msg347040328) :)

Uses Pixmaps and directly accesses the pixels instead of using Read/WritePixel for faster access.  You can save the resulting tiles with SavePixmapPNG command if you want.
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 03, 2020, 12:59:21
@TomToad
Nice job - I changed the "show" portion to quickly draw all sprites ... which exposes a flaw in the dark green tile at the bottom right (above the "plus") of the original (see following picture):
(https://i.imgur.com/tli0mzj.png)

result of your algo:
(https://i.imgur.com/QtBuWAK.png)

This is what I by the way was talking about ("island detection")


You _could_ somehow circumvent it by increasing the "lookup" range for blank lines ("end of tile"). So if you knew that all tiles are at least X pixels away from each other (padding?) then you could use this to keep these tiles intact. But I do not see a way to "automate" this in all situations. So eg. your algorithm could check distance betwen tiles - and after this quick scan uses the most used distance as "minimum distance" between tiles.

bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: TomToad on March 03, 2020, 13:23:00
Quote from: Derron on March 03, 2020, 12:59:21
@TomToad
Nice job - I changed the "show" portion to quickly draw all sprites ... which exposes a flaw in the dark green tile at the bottom right (above the "plus") of the original (see following picture):

Are you refering to the four corner square part?  My version requires that all pixels be connected continuously.  There are 0 alpha pixels between each corner, so each one is extracted into its own tile.  I guess you could create a "reach" variable, defined how close a pixel needs to be to be part of the same tile, and search through a grid of pixels instead of just left/right/up/down.
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 03, 2020, 13:31:01
I did not want to say your code is not working - it just seems to not be what Hardcoal is trying to achieve (at least not 100%).

So yes, I was talking about it - and also knew in advance why it fails and that your code does not try to cope with it.


This aside your code is very helpful and I am tempted to add it to my Dig framework (once we matured/optimized it even more :D - maybe one could add borders to sprites and the extractor then just skips the border)

bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: TomToad on March 03, 2020, 13:34:40
Ok, I just added a "reach" parameter to the code.  Now it will extract the tiles correctly. :) :)
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 03, 2020, 16:08:11
Here is my last version..
Im planning to add more PNG Tools..
Also Im about to make Also Option to Turn a non Transparent Tile Set that will turn it into a PNG.
Thats pretty easy to do now that main thing is done..

Im simply too busy lately to put a lot of coding effort.. so ill take my time..

but its definitely gonna be faster than my damn game editor.

I started this process because i needed that for my editor..

https://drive.google.com/file/d/158pkbR3xtRHDXpUgcWjJJXCTooK5x3x2/view?usp=sharing

Ive Started with Xors so im not about to move the normal blitzmax..
I dont have the powers..


if anyone improved that code that i posted ill be glad to have it :)

This is the last code..


Type TilesSpliter_Section

    Field TitleuN_bt = alCreateGScrollArea(alDesktop, "", 0, 30, 300, 30, 0)
Field Title_bt = Alba.CreateButtonWithImage_al(alDesktop, AppURL + "Media\TileSetSplitter.png", -2, 27, 300, 30)

Field Roller_Area = alCreateGScrollArea(alDesktop, "", 300, 30, 480, 30, 0)
Field LoadTileSet_bt = alCreateGButton(Roller_Area, "LoadTileSet", -2, -3, 100, 30)
Field Convert_bt = alCreateGButton(Roller_Area, "ConvertToPNGS", 128, -3, 115, 30)
    Field SelectEmptySpace_bt = alCreateGButton(Roller_Area, "SelectBackGroundPixel", 270, -3, 170, 30)

   'Versions
   'Field Version_roller = alCreateGScrollArea(alDesktop, "", 780, 30, 130, 30, 0)
Field LiteVersion_Logo = Alba.CreateButtonWithImage_al(alDesktop, "Media/LiteVersion.png", 780, 30, 100, 30, True)
Field FullVersion_Logo = Alba.CreateButtonWithImage_al(alDesktop, "Media/FullVersion.png", 780, 30, 100, 30, True)

Field ForceStop_bt = alCreateGButton(alDesktop, "ForceStop", xsize / 2 - 50, ysize / 2 - 50, 130, 30)

Field Original_Win = alCreateGScrollArea(alDesktop, "", 0, 60, 880, 410)
Field ImageButton

   'Field OutPut_win = alCreateGScrollArea(alDesktop, "", 880, 60, 400, 560)

Field OutputURL:String = "Output\"

Field PNGTileSETURF:String
Field TilesetImageHandle
Field TempNegativeImageHandle
Field Pixel[,]
Field Images[]
Field NewImageName:String

Const UnChecked = 0
Const OccupiedPix = 1

   '----------------'
    Field CurrentSection = Section_Normal
Const Section_Normal = 0
Const Section_ChoosePixel = 1

Method New()

alHide(ForceStop_bt)

Alba.SetElementColorBack(Original_Win, Alba.Color_Gray1)
Alba.SetElementColorBack(TitleuN_bt, Alba.Color_Brown)
Alba.SetElementColorBack(ForceStop_bt, Alba.Color_red)

Alba.SetRemark(LoadTileSet_bt, "Load A Tileset Single PNG and Turn it to Seperate PNGS")
Alba.SetRemark(Convert_bt, "Convert The Loaded Image To Seperate PNG's")

   'Version Logo
If DemoVersion_flg = False Then
alHide(LiteVersion_Logo)
Else
alHide(FullVersion_Logo)
End If

End Method

Method Play()

Select CurrentSection

Case Section_Normal

       'Load PNG TileSet
If alTestClick(TS.LoadTileSet_bt) Then
Local TmpImageHandle
PNGTileSETURF = RequestFile("Select PNG TileSet")
NewImageName = StripAll(PNGTileSETURF)
TmpImageHandle = xLoadImage(PNGTileSETURF)
If TmpImageHandle > 0 Then
ClearAll()
TilesetImageHandle = TmpImageHandle
alShow(Convert_bt)
ImageButton = Alba.CreateButtonWithImage_al(Original_Win, TS.PNGTileSETURF, 5, 5, 850, 540, True) ; UpdateGraphics()
If IsPNG(TmpImageHandle) = False Then PixelSelectProcess()
End If
End If

   'Convert to Seperated Pngs
    If alTestClick(Convert_bt) Then
If TS.TilesetImageHandle > 0 Then

ClearConsol()
ConsoleMessage("Converting Began, Please Wait")
alShow(ForceStop_bt) ; alOnTop(ForceStop_bt)

    'Free! Variables

TS.Pixel = Null
  TS.Pixel = New Int[xImageWidth(TS.TilesetImageHandle) , xImageHeight(TS.TilesetImageHandle)]

ClearFolder(OutputURL)
 
For Local Image = EachIn images
xFreeImage(Image)
Next

     Images = Null
     Images = New Int[0]

'Create Negative Mask
ConsoleMessage("Creating Negative")
TempNegativeImageHandle = xCreateImage(xImageWidth(TS.TilesetImageHandle), xImageHeight(TS.TilesetImageHandle))
BuildEmptySpacesField(TS.TilesetImageHandle,,, True)

'Read PNGS
ConsoleMessage("Extracting PNGS")
Images = TS.ReadAllPngs(TS.TilesetImageHandle, TS.Pixel)
ConsoleMessage("~nConvertion Over")

    'Save Images
Local URL:String = OutputURL, Counter
For Local Image = EachIn Images
Counter = Counter + 1
xSaveImage(Image, URL + NewImageName + " " + Counter + ".png")
xFreeImage(Image)
Next

alHide(Convert_bt)
alHide(ForceStop_bt)

OpenURL(OutputURL)

End If
    End If

   'Open OutputURL
If alTestClick(GotoFolder_TA) Then OpenURL(OutputURL)

Case Section_ChoosePixel

End Select

End Method

'------------------------------Sub Commands------------------------------------'

Method ReadPNG(ImageHandle, CurrentX = 0, CurrentY = 0, Pixel[,] Var)
Local X, Y, StartX, StartY, NewPixel[ximagewidth(imagehandle), ximageheight(imagehandle)]
Local LeftX, RightX, UpY, DownY

   'Start
Local Coords:Coords_Class = New Coords_Class
Coords = GetFirstEmptyPoint(ImageHandle, Pixel)
If Coords.X = -1 Then Return 'End Of Trace
StartX = Coords.X
StartY = Coords.Y
LeftX = StartX
RightX = StartX
UpY = StartY
DownY = StartY
    NewPixel[StartX, StartY] = OccupiedPix 'A Must
    Pixel[StartX, StartY] = OccupiedPix    'Not Certain
Coords = Null

   'Left To Right
For Y = StartY To xImageHeight(ImageHandle) - 1

For X = 0 To xImageWidth(ImageHandle) - 1

   'Is UnChecked
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return

TimedUpdateGraphics()

Next

Next

   'Right To Left And Down To Up
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1

For X = xImageWidth(ImageHandle) - 1 To 0 Step - 1

   'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()

Next

Next

   'Up To Down  [All Seems To Work]
For X = 0 To xImageWidth(ImageHandle) - 1

For Y = 0 To xImageHeight(ImageHandle) - 1

   'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()

Next

Next

   'Down To Up
For X = 0 To xImageWidth(ImageHandle) - 1

For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1

   'Is Empty
If Pixel[X, Y] = UnChecked Then
If HasAnOccupiedPointAroundHim(ImageHandle, X, Y, NewPixel) = True Then
If X < LeftX Then LeftX = X
If X > RightX Then RightX = X
If Y < UpY Then UpY = Y
If Y > DownY Then DownY = Y
Pixel[X, Y] = OccupiedPix
NewPixel[X, Y] = OccupiedPix
End If
End If

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics()

Next

Next

   'Write The Image
Local NewImage = Xcreateimage (RightX - LeftX, DownY - UpY)
For Y = UpY To DownY
For X = LeftX To RightX

If NewPixel[X, Y] = OccupiedPix Then xWritePixel(X - LeftX, Y - UpY, xReadPixel(X, Y, xImageBuffer(ImageHandle)), xImageBuffer(NewImage))

   'ForceStop
If ForceStopFlg = True Then Return
TimedUpdateGraphics(50)

Next
Next

Return NewImage
End Method

Method ReadAllPngs[] (ImageHandle, Pixel[,] Var)
Local Image[], NewImage, Counter

Repeat

NewImage = ReadPNG(ImageHandle,,, Pixel)
If NewImage = 0 Then
Return Image 'End Of Cycles
Else
Image = Image +[NewImage]
End If

Counter = Counter + 1
    ConsoleMessage("Image Num " + Counter, False)
If Counter > 500 Then Return 'Max Limit

   'Demo Version
If DemoVersion_flg = True Then
If Counter >= LimitingOutput_Val Then
Notify ("Free Version allows only up to 10 Images extraction")
Return Image
End If
End If

   'Force Stop
If ForceStopFlg = True Then Return Image

Forever

End Method

Method HasAnOccupiedPointAroundHim(ImageHandle, X, Y, Pixel[,] Var)

   'Checks Left Pixel
If X > 0 And Pixel[X - 1, Y] = OccupiedPix Then Return True

   'Checks Right Pixel
If X < xImageWidth(ImageHandle) - 1 And Pixel[X + 1, Y] = OccupiedPix Then Return True

   'ChecksUpPixel
If Y > 0 And Pixel[X, Y - 1] = OccupiedPix Then Return True

   'ChecksDownPixel
If Y < xImageHeight(ImageHandle) - 1 And Pixel[X, Y + 1] = OccupiedPix Then Return True

   'LeftUpPixelIsOccupied
If X > 0 And Y > 0 And Pixel[X - 1, Y - 1] = OccupiedPix Then Return True

   'RightUpPixelIsOccupied
If X < xImageWidth(ImageHandle) - 1 And Y > 0 And Pixel[X + 1, Y - 1] = OccupiedPix Then Return True

   'DownLeftPixelIsOccupied
If X > 0 And Y < xImageHeight(ImageHandle) - 1 And Pixel[X - 1, Y + 1] = OccupiedPix Then Return True

   'DownRightPixelIsOccupied
If X < xImageWidth(ImageHandle) - 1 And Y < xImageHeight(ImageHandle) - 1 And Pixel[X + 1, Y + 1] = OccupiedPix Then Return True

End Method

Method GetFirstEmptyPoint:Coords_Class(ImageHandle, Pixel[,] Var)
Local X, Y, CRDS:Coords_Class

CRDS = New Coords_Class

For Y = 0 To xImageHeight(ImageHandle) - 1
For X = 0 To xImageWidth(ImageHandle) - 1
If Pixel[X, Y] = UnChecked Then
CRDS.X = X
CRDS.Y = Y
Return CRDS
End If
Next
Next

   'NotFound
CRDS.X = -1
End Method

Method BuildEmptySpacesField(ImageHandle, CurrentX = 0, CurrentY = 0, Start = False)
Local X, Y, StartX, StartY

   'Start
If Start = True Then
Local Coords:Coords_Class = New Coords_Class
Coords = GetFirstEmptyPixel(ImageHandle)
StartX = Coords.X
StartY = Coords.Y
Pixel[StartX, StartY] = OccupiedPix
Coords = Null
End If

   'Left To Right
For Y = StartY To xImageHeight(ImageHandle) - 1

For X = StartX To xImageWidth(ImageHandle) - 1

   'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If

TimedUpdateGraphics()

Next

Next

   'Right To Left
For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1

For X = xImageWidth(ImageHandle) - 1 To 0 Step - 1

   'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If

TimedUpdateGraphics()

Next

Next

   'Up To Down
For X = 0 To xImageWidth(ImageHandle) - 1

For Y = 0 To xImageHeight(ImageHandle) - 1

   'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If

TimedUpdateGraphics()

Next

Next

   'Down To Up
For X = 0 To xImageWidth(ImageHandle) - 1

For Y = xImageHeight(ImageHandle) - 1 To 0 Step - 1

   'Is Empty
If PixelIsOccupied(xReadPixel(X, Y, xImageBuffer(ImageHandle))) = False Then
If HasAnEmptyPixelAroundHim(ImageHandle, X, Y) = True Then
Pixel[X, Y] = OccupiedPix
End If
End If

Next

TimedUpdateGraphics()

Next

End Method

Method HasAnEmptyPixelAroundHim(ImageHandle, X, Y)

   'Checks Left Pixel
If LeftPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X - 1, Y] = OccupiedPix Then Return True

   'Checks Right Pixel
If RightPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X + 1, Y] = OccupiedPix Then Return True

   'ChecksUpPixel
If UpPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X, Y - 1] = OccupiedPix Then Return True

   'ChecksDownPixel
If DownPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X, Y + 1] = OccupiedPix Then Return True

   'LeftUpPixelIsOccupied
If LeftUpPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X - 1, Y - 1] = OccupiedPix Then Return True

   'RightUpPixelIsOccupied
If RightUpPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X + 1, Y - 1] = OccupiedPix Then Return True

   'DownLeftPixelIsOccupied
If DownLeftPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X - 1, Y + 1] = OccupiedPix Then Return True

   'DownRightPixelIsOccupied
If DownRightPixelIsOccupied(ImageHandle, X, Y) = False And Pixel[X + 1, Y + 1] = OccupiedPix Then Return True

End Method

'------------------Check If Pixel Is Occupied----------------------'

'LeftPixelIsOccupied
Method LeftPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX - 1, CurrentY, xImageBuffer(ImageHandle)))
Else
Return - 1
End if
End Method

'RightPixelIsOccupied
Method RightPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX < xImageWidth(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method

'UpPixelIsOccupied
Method UpPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentY > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX, CurrentY - 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method

'DownPixelIsOccupied
Method DownPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentY < xImageHeight(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX, CurrentY + 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method

'LeftUpPixelIsOccupied
Method LeftUpPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX > 0 And CurrentY > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX - 1, CurrentY - 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End if
End Method

'RightUpPixelIsOccupied
Method RightUpPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX < xImageWidth(ImageHandle) And CurrentY > 0 Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY - 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End if
End Method

'DownLeftPixelIsOccupied
Method DownLeftPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX > 0 And CurrentY < xImageHeight(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY + 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method

'DownRightPixelIsOccupied
Method DownRightPixelIsOccupied(ImageHandle, CurrentX, CurrentY)
If CurrentX < xImageWidth(ImageHandle) And Currenty < xImageHeight(ImageHandle) Then
Return PixelIsOccupied(xReadPixel(CurrentX + 1, CurrentY + 1, xImageBuffer(ImageHandle)))
Else
Return - 1
End If
End Method

'----------------------------------------'

Method GetFirstOccupiedPoint:Coords_Class(Image)
Local I, J, CRDS:Coords_Class, Pixel

CRDS = New Coords_Class

For I = 0 To xImageWidth(Image) - 1
For J = 0 To xImageHeight(Image) - 1
Pixel = xReadPixel(I, J, xImageBuffer(Image))
If Pixel <> PNGPixelValue And Pixel <> 0 Then
CRDS.X = I
CRDS.Y = J
Return CRDS
End If
Next
Next

End Method

Method GetFirstEmptyPixel:Coords_Class(Image)
Local I, J, CRDS:Coords_Class, Pixel

CRDS = New Coords_Class

For I = 0 To xImageWidth(Image) - 1
For J = 0 To xImageHeight(Image) - 1
Pixel = xReadPixel(I, J, xImageBuffer(Image))
If Pixel = PNGPixelValue Or Pixel = 0 Then   'Or Pixel = 3750201  'not sure about the 0
CRDS.X = I
CRDS.Y = J
Return CRDS
End If
Next
Next

End Method

Method PixelIsOccupied(Pixel)
Return Pixel <> PNGPixelValue And Pixel <> 0 'And Pixel <> 3750201
End Method

Method ClearAll()
   'Alba.ClearElement(Consol_Win)
If TilesetImageHandle > 0 Then xFreeImage(TilesetImageHandle) ;TilesetImageHandle = 0
If ImageButton > 0 Then alFreeElement(ImageButton) ; ImageButton = 0
End Method

'------------------------------------------------------------'

    Field ZoomPixImage = xcreateimage(15, 15)

Method PixelSelectProcess()
Repeat
   'Local X, Y
   'xWritePixel(X, Y, $ffffffff, xImageBuffer(ZoomPixImage) xImageColor(
   'xImageColor(ZoomPixImage, $ff, $ff, $ff)
    If Alba.MouseOverElementArea(Original_Win) Then ShowThisIcon = Cross_Ico
BlinkQuickMessage("PLEASE SELECT BACKGROUND PIXEL")
   'ConsoleMessage("[This Image is not a PNG, Please Select a background Pixel]")
UpdateGraphics()
If xKeyHit(xKEY_ESCAPE) Then Exit
Forever

   'Add Zoom Pixel So You can Choose Well

End Method

End Type

Type Coords_Class
Field X
Field Y
End Type

Type PixelCounter_Class
Field Value
Field Amount
End Type






Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 03, 2020, 16:26:07
You can simply use the code of TomToad without affecting your Xors-stuff.

Just
Import brl.pixmap

and you gain access to LoadPixmap and TPixmap. if you need to load a PNG: import brl.pngloader


bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 03, 2020, 17:54:57
Ok derron ill check it thanks
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 09, 2020, 19:29:58
hi.. can anyone have to algorithm of turning a color pixel into a gray pixel in order to turn a color image into black and white image?
Im experimenting as we speak.. but im not sure im doing the algorithm right, so better ask.

when i read a pixel value i sometimes get a negative number..
so whats that means? and can i overcome it and turn all numbers into positive values for comparison
Title: Re: ReadPixel WritePixel speed
Post by: Derron on March 09, 2020, 20:08:39
Read the integer value of the pixel color - split it into RGBA and use the algorithm of your choice to create grayscale versions of it.

There are different approaches as the conversion is using a kind of "perceived color" approach.
You could for example convert RGB into HSL and then set the "S" (saturation) to 0 and convert back your HSL to RGB.

Or you can use CIE_Lab colors which use a more psychological/pereceived color approach for "color distances". Easiest bet with satisfying results though, is the HSL<->RGB thing.

Algorithms can be found here:
https://github.com/GWRon/Dig/blob/master/base.util.color.bmx

It also lists the "not so good but still working":
Code (BlitzMax) Select

'faster than using the RGB-HSL-RGB conversion
'but results are not exactly the same
Method AdjustSaturationRGB:TColor(percentage:Float = 0.0)
'convert relative param to absolute param
percentage = 1.0 + percentage
'long
local luminance:float = sqr(0.299 * r*r + 0.587 * g*g + 0.114 * b*b)
r = Min(255, Max(0, luminance + (r - luminance) * percentage))
g = Min(255, Max(0, luminance + (g - luminance) * percentage))
b = Min(255, Max(0, luminance + (b - luminance) * percentage))
return self
End Method



bye
Ron
Title: Re: ReadPixel WritePixel speed
Post by: Matty on March 10, 2020, 03:09:37
The absolute easiest way once you split the rgb into components is to do this:

(R + G + B)/3 is the new value for r,g and b.
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 10, 2020, 07:01:46
ok.. Thanks Derron and Matty
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 10, 2020, 20:55:27
Ok ive solved my write pixel speed problem..
all i needed to do is to use lockbuffer than use command called writepixelfast and than unlock buffer again..

that was all the issue. cheers
Title: Re: ReadPixel WritePixel speed
Post by: takis76 on March 15, 2020, 00:17:18
@Hardcoal

Hello,
I saw your little program and I have one unrelated question.
Which library are you using for your GUI? I am interested in the GUI library if I will use it for my game.
Is this supposed to be programmed with BlitzMax?

Thank you.
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 15, 2020, 03:51:45
this gui only works under Xors3D engine under blitzmax
so only if you are planning to use Xors3D you can use this GUI.
other than that, you better find another GUI . Cheers :)
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 15, 2020, 03:58:54
I finally DId picture hidden in picture..
the hidden picture is on black and white but i can also make it colored in the future if i like.

You load two pictures and than press process and you will get the image inside image new image..

Note: if you transfer this image using whatsup or some medias that process the pixels this wont work..

I did anyway just for experimenting.. i was wondering if its possible.

I simply steal some bits from the main image and use it as gray scales for the hidden image..

please choose a bigger image as the visible image.. because if not it will get stuck..
i didnt fix this yet

https://drive.google.com/file/d/10vPfCDd73soh4_9nwqCy2FA4fcuSZnb4/view?usp=sharing

(https://i.imgur.com/UTdGVu4.jpg)

Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 20, 2020, 04:38:14
Ok i made the hidden Image In Color..
it was more complicated but i managed..

I only do this as a type of excersize ..

i learnt a lot from it..

now that i finished it  can move on with life :)

https://drive.google.com/file/d/1qOWXd_3vUDjW-UmifU9dl3Ev7Fj29Ybg/view?usp=sharing

Title: Re: ReadPixel WritePixel speed
Post by: fielder on March 22, 2020, 21:41:04
the main exacutable (supermain.exe) is not doing anything on my pc (Windows 10 64)
Title: Re: ReadPixel WritePixel speed
Post by: Hardcoal on March 22, 2020, 21:46:19
weird.. i got also windows 10 .. 64

maybe i missed one DLL .. ill check it

because it wont show you that it misses a dll , it just wont run..
checking..

ok i checked it. and all seems fine.. I have no idea at this point why its not working for you..
ill ask a friend to download it and see if he has issues too.

ok he had no issues..
but he uses windows 7 so.. I dont know ;)