Page 1 of 2

Reading POINTs from an image, to draw on another.

Posted: Sat Aug 28, 2021 11:25 pm
by matalog
Is it possible, to say load a previously made image, it does not have to be viewable on screen. Then read POINT colours of that image, and then use that information to draw on another new blank image?

The help file says that POINT will return the colour of a pixel in the current output.

Would it just be a matter of pretending that the source image is the current output (how do you switch to it?) and then reading the POINT, and afterwards switching to the actual output image (again, how do you switch between images?)?

Thanks for any help.

Re: Reading POINTs from an image, to draw on another.

Posted: Sun Aug 29, 2021 12:07 am
by matalog
I got it, Startdrawing() sets the 'current output'.

Code: Select all

UseJPEGImageDecoder()

OpenWindow(0,0,0,800,560, "ImageCopyCols")
CreateImage(1,800,560)
ImageGadget(0, 0, 0,800, 560, ImageID(1))

LoadImage(0,"F:\PureBasic\502.jpg")
For y=0 To 559
  For x=0 To 799
     StartDrawing(ImageOutput(0))
f=Point(x,y)

StopDrawing()
StartDrawing(ImageOutput(1))
Plot(x,y,f)
StopDrawing()
SetGadgetState(0,ImageID(1))

Next
Next



Repeat
  windowevent=WaitWindowEvent()
  Until windowevent=#PB_Event_CloseWindow

Re: Reading POINTs from an image, to draw on another.

Posted: Sun Aug 29, 2021 12:30 am
by matalog
So it seems that using Startdrawing() and Stopdrawing() is very slow aswell, not just Setgadgetstate().

If I want to take this a pixel at a time, instead of storing many values in memory, how could I make it faster?

I will eventually be editing the value of f before it is output to image(1).

Code: Select all

UseJPEGImageDecoder()

OpenWindow(0,0,0,800,560, "ImageCopyCols")
CreateImage(1,800,560)
ImageGadget(0, 0, 0,800, 560, ImageID(1))

LoadImage(0,"F:\PureBasic\502.jpg")

For y=0 To 559
  For x=0 To 799
     StartDrawing(ImageOutput(0))
f=Point(x,y)
StopDrawing()

StartDrawing(ImageOutput(1))
Plot(x,y,f)
StopDrawing()

Next
Next

SetGadgetState(0,ImageID(1))

Repeat
  windowevent=WaitWindowEvent()
  Until windowevent=#PB_Event_CloseWindow

Re: Reading POINTs from an image, to draw on another.

Posted: Sun Aug 29, 2021 1:49 am
by netmaestro
For one thing, your StartDrawing() should be done before your For loops to avoid doing it for every pixel. Btw, have you considered GrabImage()?

Re: Reading POINTs from an image, to draw on another.

Posted: Mon Aug 30, 2021 6:31 pm
by matalog
netmaestro wrote: Sun Aug 29, 2021 1:49 am For one thing, your StartDrawing() should be done before your For loops to avoid doing it for every pixel. Btw, have you considered GrabImage()?
But, if I want to read each point, then it requires 2 calls of start and stop drawing each loop, one to read each pixel, and one to draw each pixel - assuming that I do not want to use extra memory and store the information as an array.

The use of Start and Stop drawing is very slow here, and I cannot see a way around it, without using an array or some other way of storing to memory.

Re: Reading POINTs from an image, to draw on another.

Posted: Mon Aug 30, 2021 7:15 pm
by wilbert
matalog wrote: Mon Aug 30, 2021 6:31 pmThe use of Start and Stop drawing is very slow here, and I cannot see a way around it, without using an array or some other way of storing to memory.
Is there any reason you don't want to use an array ?
You can free the source image as soon as you have read all pixel colors into an array.
That way it shouldn't use more memory.

Re: Reading POINTs from an image, to draw on another.

Posted: Mon Aug 30, 2021 10:07 pm
by matalog
wilbert wrote: Mon Aug 30, 2021 7:15 pm
matalog wrote: Mon Aug 30, 2021 6:31 pmThe use of Start and Stop drawing is very slow here, and I cannot see a way around it, without using an array or some other way of storing to memory.
Is there any reason you don't want to use an array ?
You can free the source image as soon as you have read all pixel colors into an array.
That way it shouldn't use more memory.
Well, the source image is 12800x8000 and it seems to use a gigabyte of memory within the program as an array, whereas it is 788kb as a jpg.

If I was able to work at a decent speed from the image itself, instead of an array, I would be saving a gigabyte of memory.

Re: Reading POINTs from an image, to draw on another.

Posted: Mon Aug 30, 2021 11:25 pm
by FourthStone
I can't imagine loading an image would take up 1gb, counting too many 000's?

The way I read points from images is to load them into memory and directly read the RGB values.

Reading data to an array and processing before outputting to another image is magnitudes faster than trying to read an image pixel by pixel.

Let me know if you want an example.

Re: Reading POINTs from an image, to draw on another.

Posted: Mon Aug 30, 2021 11:45 pm
by matalog
FourthStone wrote: Mon Aug 30, 2021 11:25 pm I can't imagine loading an image would take up 1gb, counting too many 000's?

The way I read points from images is to load them into memory and directly read the RGB values.

Reading data to an array and processing before outputting to another image is magnitudes faster than trying to read an image pixel by pixel.

Let me know if you want an example.
Well, by definition alone, 12800x8000x 4 bytes(32bit compiler integer array) or 8 bytes (64 compiler integer array)

= 12800x8000x4=409,600,000 bytes.
Or 12800x8000x8=819,200,000 bytes.

I had defined an integer array in 64 bit PB.

Re: Reading POINTs from an image, to draw on another.

Posted: Mon Aug 30, 2021 11:47 pm
by Demivec
matalog wrote: Mon Aug 30, 2021 10:07 pmWell, the source image is 12800x8000 and it seems to use a gigabyte of memory within the program as an array, whereas it is 788kb as a jpg.

If I was able to work at a decent speed from the image itself, instead of an array, I would be saving a gigabyte of memory.
Don't mistake the space required to store the compressed image on disk with the memory requirements to view it or operate on it in memory once it's loaded.

I calculate that your image would take at a minimum 12800 x 8000 x 4 bytes [i.e. 32-bits] = 409600000 bytes = 390.625 mb of storage in memory. That doesn't included additional spacing on each line that may be used to pad and align things for faster memory access.

If speed is important and memory is freely available create an array copy of the source image. If speed is not important and memory is scarce then do things pixel by pixel. I would think even if memory was limited you would be better off to create an array big enough to hold the pixel data for one line and just switch back and forth once for each line to be read and plotted. That should speed up things up to 12800 times and would only require 12800 x 4 bytes = 52200 bytes = 50 kb.

Based on the obscurity of your goals it is hard to suggest much more. There may be ways of improving things in other ways outside of the individual read point, plot point cycle.

Re: Reading POINTs from an image, to draw on another.

Posted: Tue Aug 31, 2021 12:02 am
by FourthStone
Ah I see the image size has an extra 0 on the end making it rather large.

You could use GrabImage to grab a region and copy it to another working image to process or display.

Re: Reading POINTs from an image, to draw on another.

Posted: Tue Aug 31, 2021 6:10 am
by collectordave
If I understand correctly you want to read one image, process the individual pixels and write them to a second image.

I would break it down to two steps.

First process the source image colours

Second write the source image to the second image.

Maybe code like this:-

Code: Select all

UseJPEGImageDecoder()

OpenWindow(0,0,0,800,560, "ImageCopyCols")
CreateImage(1,800,560)
ImageGadget(0, 0, 0,800, 560, ImageID(1))

LoadImage(0,"F:\PureBasic\502.jpg")
StartDrawing(ImageOutput(0))
For y=0 To 559
  For x=0 To 799
     f=Point(x,y)
     
     ;Process F here
     
     Plot(x,y,f)
   Next y
 Next x
   
 StopDrawing()

 
;Now you have your original image all processed
;Draw the whole thing to the next image
 
     
StartDrawing(ImageOutput(1))
;DrawImage(ImageID(0),x,y) ;etc.
StopDrawing()
SetGadgetState(0,ImageID(1))

Repeat
  windowevent=WaitWindowEvent()
  Until windowevent=#PB_Event_CloseWindow
I have not completed the draw image line as I do not know what you want.

StartDrawing/Stopdrawing only called twice

Re: Reading POINTs from an image, to draw on another.

Posted: Tue Aug 31, 2021 6:34 am
by collectordave
Just another idea.

If the second image is simply the first image processed then you do not need to draw the processed image onto a second image just display the processed image.

Start/Stop Drawing only called once.

Also if the original Image is to be used again so you do not wish to change the original then use CopyImage()

Code: Select all


Global DisplayImage.i

DisplayImage = CopyImage(ImageID(0),#PB_Any)
ImageID(0) being the original Image

Re: Reading POINTs from an image, to draw on another.

Posted: Tue Aug 31, 2021 12:47 pm
by Mijikai
Isnt the DrawingBuffer() for images static?
The device context isnt but the buffer should be.

Code: Select all

EnableExplicit
 
Procedure.i ImageBuffer(Image.i)
  Structure IMAGE_BUFFER_STRUCT
    size.POINT
    *bits
    pitch.i
    depth.i
  EndStructure
  Protected *imgbuffer.IMAGE_BUFFER_STRUCT
  *imgbuffer = AllocateMemory(SizeOf(IMAGE_BUFFER_STRUCT),#PB_Memory_NoClear)
  If *imgbuffer
    If StartDrawing(ImageOutput(Image))
      *imgbuffer\size\x = OutputWidth()
      *imgbuffer\size\y = OutputHeight()
      *imgbuffer\bits = DrawingBuffer()
      *imgbuffer\pitch = DrawingBufferPitch()
      *imgbuffer\depth = OutputDepth()
      StopDrawing()
      ProcedureReturn *imgbuffer
    EndIf
    FreeMemory(*imgbuffer)
    ProcedureReturn #Null
  EndIf
EndProcedure

Procedure.i ImageCopyColor(*Dst.IMAGE_BUFFER_STRUCT,*Src.IMAGE_BUFFER_STRUCT,X.i,Y.i)
  Protected depth.i
   depth = *Dst\depth >> 3
  *Dst = *Dst\bits + (Y * *Dst\pitch) + (X * depth)
  *Src = *Src\bits + (Y * *Src\pitch) + (X * depth)
  ProcedureReturn CopyMemory(*Src,*Dst,depth)
EndProcedure

Procedure.i Main()
  Protected img_1.i
  Protected img_2.i
  Protected *img_b1.IMAGE_BUFFER_STRUCT
  Protected *img_b2.IMAGE_BUFFER_STRUCT
  Protected x.i
  Protected y.i
  Protected w.i
  Protected h.i
  Protected color.i
  img_1 = CreateImage(#PB_Any,32,32,24,#Red)
  img_2 = CreateImage(#PB_Any,32,32,24,#Blue)
  *img_b1 = ImageBuffer(img_1)
  *img_b2 = ImageBuffer(img_2)
  w = *img_b1\size\x - 5
  h = *img_b1\size\y - 5
  For y = 4 To h
    For x = 4 To w
      ImageCopyColor(*img_b1,*img_b2,x,y)
    Next
  Next
  SaveImage(img_1,"dummy.bmp")
  ProcedureReturn #Null
EndProcedure

Main()

End

Re: Reading POINTs from an image, to draw on another.

Posted: Tue Aug 31, 2021 1:58 pm
by Demivec
Mijikai wrote: Tue Aug 31, 2021 12:47 pm Isnt the DrawingBuffer() for images static?
The device context isnt but the buffer should be.
Fred's response in the thread Fred does image buffer remain static after StopDrawing()?:
StopDrawing() invalidate all drawing operations including DrawingBuffer(). It's not safe to use it after StopDrawing() (it can work by luck, but it's not supported. I will update the doc to make it clear.
PureBasic help file under DrawingBuffer() wrote:Once StopDrawing() has been called, the buffer is invalidated and can no more be used.