My first GAMBAS Program and MemoryManagement

Post

Posted
Rating:
#1 (In Topic #1553)
Regular
DIYTinkerer is in the usergroup ‘Regular’
Hi all, my first ever GAMBAS program is coming along great - thanks in no small part to this forums members replying to my questions and those of others - its a great resource

My code is a bit messy (I hope you will forgive this as it is my first try and I am very much an occasional hobby programmer) so I'm not sharing it yet - but I thought I'd share some results.
My program loads an image of the Sun or Moon, works out (with the users help) where the centre of the Moon would be in the image (or outside the image) and the radius of the moon in pixels, it then allows the user to select any part of the moon and re-displays a 'rectified' image that shows what that part of the Moon would look like if you were looking down directly above the selected feature. See image.

Image

(Click to enlarge)


I'm amazed how fast the results are created 0-10s depending on the size of the image) (this one a 6 Mega Pixel image is very quick - you can imagine there is a small amount of maths being performed for exery pixel) .

One problem I'm encountering is a memory issue. The software can take images that are just parts of the Moon (or Sun) so long as some of the limb (edge) of the object is in the image, if the image had been of the whole Sun it would result in an image of say 600Mega Pixels (gulp) and when I try to create image objects at say 24000x24000 I get an 'out of memory' error….

you can simulate it with this code

Code

Public Sub Form_Open()

  Dim f As Integer
  For f = 1000 To 200000 Step 1000
    Debug "Image Dimentions (" & f & "," & f & ")"
    Dim I As New Image(f, f)
  Next

End

But when I look at how much memory is free in my system its huge, ~56GB Free, so I'm wondering if this is an internal limit or if there is some parameter I can add to increase memory allocation?

I suspect given enough head banging I can optimise my code to be less memory hungry, but I hope you can appreciate converting from screen coords to spherical coords, to cartesian coord and back to screen  coords leaves me with a headache! And this is my first GAMBAS program…

You suggestions very welcome  :)
Online now: No Back to the top

Post

Posted
Rating:
#2
Regular
DIYTinkerer is in the usergroup ‘Regular’
Ok so no takers… :(

Here's what I have done to try and resolve the memory problem…
1) I have a lot of functions that return manipulations to the image (things like rotation in X and z axis, cropping etc. these were nested, I moved these to not being nested - I think this helped a little - although its not conclusive

2) because of the un-nesting of functions I ended up with a lot of different images which I needed to store the results of the functions from - so once I'm done with them I'm forcing them to release their memory (I assume) by making them equal to null

3) I started saving the result of each function that returns an image to SSD - what this has turned up is that

Code

 Dim tempImage As New Image(imageToRotate.width, imageToRotate.Height)
 tempImage = (imageToRotate.Rotate(rotAngle)).Copy()
 tempImage.Save(FMain.imageLocation & "tempImage.jpg")
throws an error for very large images e.g.(10820x10820) and refuses to save them and I get an error like 'unable to save image' , or a full crash 'Segmentation error(11)' or 'out of memory' error

For smaller images everything works fine Any suggestions?
Online now: No Back to the top

Post

Posted
Rating:
#3
Avatar
Administrator
gbWilly is in the usergroup ‘unknown’

DIYTinkerer said

3) I started saving the result of each function that returns an image to SSD - what this has turned up is that

Code (gambas)

  1.  Dim tempImage As New Image(imageToRotate.width, imageToRotate.Height)
  2.  
  3.  tempImage = (imageToRotate.Rotate(rotAngle)).Copy()
  4.  tempImage.Save(FMain.imageLocation & "tempImage.jpg")
  5.  
throws an error for very large images e.g.(10820x10820) and refuses to save them and I get an error like 'unable to save image' , or a full crash 'Segmentation error(11)' or 'out of memory' error

For smaller images everything works fine Any suggestions?
I have no idea what you are trying to achieve as I'm not really into image stuff in Gambas.
And a few lines of code for a whole project is impossible to troubleshoot.
But you say it works with smaller images, so I suppose the code is okay and it comes down to memory trouble causing this.

So here is a suggestion:
Have you tried Picture (https://gambaswiki.org/wiki/comp/gb.qt4/picture) instead of Image.
Image uses memory, Picture uses display server (like x11).

If big images cause memory problems, Picture might be your friend.

On a side note:
I beautified your code in my reply to show you that this forum supports Gambas highlighting.
Below screenshot shows you where in toolbar you find the proper button (gb) to do so.  ;)
Image

(Click to enlarge)


gbWilly
- Gambas Dutch translator
- Gambas wiki content contributor
- Gambas debian/ubuntu package recipe contributor
- GambOS, a distro for learning Gambas and more…
- Gambas3 Debian/Ubuntu repositories


… there is always a Catch if things go wrong!
Online now: No Back to the top

Post

Posted
Rating:
#4
Regular
DIYTinkerer is in the usergroup ‘Regular’
thanks GBWilly, I've been using images throughout I'll see if I can change to picture, sounds like sage advice.

There is a lot of code - quite a complex project for my first program… LOL that fact it works at all amazes me. Hence I didn't want to share it all.
I'm certain it isn't the code per-say because even a scaled version of the same image works.  

Didn't know about the 'gb' button, I will try that in future - that's a good tip :).
Online now: No Back to the top

Post

Posted
Rating:
#5
Regular
DIYTinkerer is in the usergroup ‘Regular’
So I tried moving some of my image objects to Picture objects and this was relatively straight forward for some of the functions but not for others, for instance there isn't an equivalent of Image.Rotate for picture objects, and the picturebox doesn't have a zoom where the ImageView does (just 2 examples) also accessing pixel data is done differently, Images use a 2D array whereas Picture uses a 1D array and whilst I could get round many of these programs it started to become a real headache…

So I built a small gambas program to see if I could replicate what is happening with a simple piece of code - and I think I can…

Code (gambas)

  1. Public Sub Form_Open()
  2.   Dim largeImage As Image = Image.Load("LargeImage.jpg")
  3.   Dim savedImage As Image
  4.   savedImage = LargeImage.Rotate(Pi() / 2).Copy()
  5.   savedImage.Save("LargeImageRotated.jpg")

If LargeImage.jpg is large enough - say 15000px x 15000px this crashes with the following error…
(org.gambas.47508:47508): GdkPixbuf-CRITICAL **: 21:08:00.790: gdk_pixbuf_savev: assertion 'GDK_IS_PIXBUF (pixbuf)' failed

which means very little to me, but I think the GDK pixel Buffer (whatever that is) is over flowing?
Online now: No Back to the top

Post

Posted
Rating:
#6
Avatar
Administrator
gbWilly is in the usergroup ‘unknown’

DIYTinkerer said

So I tried moving some of my image objects to Picture objects and this was relatively straight forward for some of the functions but not for others, for instance there isn't an equivalent of Image.Rotate for picture objects, and the picturebox doesn't have a zoom where the ImageView does (just 2 examples) also accessing pixel data is done differently, Images use a 2D array whereas Picture uses a 1D array and whilst I could get round many of these programs it started to become a real headache…
Just do all you want to in Image and next:

Code (gambas)

  1. Public Sub Form_Open()
  2.  
  3.   Dim myImage As Image
  4.   Dim myPicture As Picture
  5.  
  6.   myImage = Image.Load("~/Desktop/SimpleImage.png")
  7.   myPicture = myImage.Picture
  8.  
  9.   'you can even convert format if needed
  10.   myPicture.Save("~/Desktop/SimplPicture.jpg")
  11.  
  12.  
Convert image to picture  :arrow: https://gambaswiki.org…comp/gb.qt4/image/picture
Convert picture to image  :arrow: https://gambaswiki.org…comp/gb.qt4/picture/image

In your example:

Code (gambas)

  1. Public Sub Form_Open()
  2.  
  3.   Dim largeImage As Image = Image.Load("LargeImage.jpg")
  4.   Dim savedImage As Image
  5.   Dim savedPicture As Picture
  6.  
  7.   savedImage = LargeImage.Rotate(Pi() / 2).Copy()
  8.  
  9.   'now your done convert to picture for the saving part
  10.   savedPicture = savedImage.Picture
  11.   savedPicture.Save("LargeImageRotated.jpg")
  12.  
  13.  

DIYTinkerer said

If LargeImage.jpg is large enough - say 15000px x 15000px this crashes with the following error…
(org.gambas.47508:47508): GdkPixbuf-CRITICAL **: 21:08:00.790: gdk_pixbuf_savev: assertion 'GDK_IS_PIXBUF (pixbuf)' failed

which means very little to me, but I think the GDK pixel Buffer (whatever that is) is over flowing?
The error you get is not from Gambas but from underlying gtk.
Have a look at this page on wiki  :arrow:  https://gambaswiki.org/wiki/doc/imageconv It says:
Each image conversion has a performance cost, which is proportional to the image size.
The conversion routines are optimized (but do not use assembly at all, so maybe they could be faster), but that cost cannot be neglected if the image is huge.
Especially with gb.gtk, that uses two different pixel formats (one for its images, another one when drawing with them): for example, if you load an image from the disk and draw it on the screen, a conversion will occur.
As stated in quote above especially gtk can have a big performance cost. Try running the project with qt5 and see what happens.

Just a few suggestions

gbWilly
- Gambas Dutch translator
- Gambas wiki content contributor
- Gambas debian/ubuntu package recipe contributor
- GambOS, a distro for learning Gambas and more…
- Gambas3 Debian/Ubuntu repositories


… there is always a Catch if things go wrong!
Online now: No Back to the top

Post

Posted
Rating:
#7
Regular
DIYTinkerer is in the usergroup ‘Regular’
Thanks again gbWilly, I know I can convert between picture and image objects and back, but I was trying to avoid Image all together - following your suggestion to use picture only - that's when I bumped into the differences between them.
Thanks for the suggestion to run in QT5 - this hadn't occurred to me, alas it makes no difference to the program behaviour, the error I get varies from…
<LIST>
  • <LI>no crash but a blank screen - this blank screen is the result of a rotation - the image is there before the rotation but not afterwards.</LI>
</LIST>
<LIST>
  • <LI>'Segmentation error(11)'</LI>
</LIST>
<LIST>
  • <LI>'Out of memory' error</LI>
</LIST>
Thanks for your help
Online now: No Back to the top

Post

Posted
Rating:
#8
Regular
DIYTinkerer is in the usergroup ‘Regular’
Well I went back to the drawing board. I spoke to a mathematician friend of mine, explained the problem, they provided a single mathslab script that did all the maths in a single script (I was rotating, cropping, translating and rectifying all as separate functions.   The new function - which I've included here works without any memory issues :-) Interestingly none of the trigonometry actually needs calculating…   
So thanks to my friend (John H) and to gbWilly for their support.

Code (gambas)

  1. Public Function DoRectification(imageToRectify As Image, xint As Integer, yint As Integer) As Image
  2.   '' Function To adjust forshortening where
  3.   ' (xint, yint) is the point of interest
  4.  
  5.   Dim rectifiedImage As New Image(imageToRectify.width, imageToRectify.height)
  6.   rectifiedImage.Fill(Color.DarkGreen)' Area outside Of moon's disc will be dark green
  7.  
  8.   Dim centreX As Float = FOrig.centerx
  9.   Dim centreY As Float = FOrig.centery
  10.   Dim top As Integer = 0
  11.   Dim bottom As Integer = imageToRectify.height - 1
  12.   Dim right As Integer = imageToRectify.width
  13.  
  14.   Dim radius As Float = FOrig.radius
  15.   Dim z As Float = Sqr((xint - centreX) ^ 2 + (yint - centreY) ^ 2)
  16.   Dim cospsi As Float = -(xint - centreX) / z
  17.   Dim sinpsi As Float = (yint - centreY) / z
  18.   Dim radius2z2 As Float = Sqr(radius ^ 2 - z ^ 2)
  19.  
  20.   Dim x, y As Integer
  21.   For y = top - centreY To bottom - centreY
  22.     Dim xrange As Integer = Floor(Sqr(radius ^ 2 - y ^ 2))
  23.     Debug "Y= " & y ' display y On Each iteration Of y so we know program Is Working!
  24.     For x = -xrange To xrange
  25.       ' find the coordinates Of the point whose colour we are populating, (x, y),
  26.       ' in coords where the object Of interest lies On the x - axis
  27.       Dim xrot As Float = x * cospsi - y * sinpsi
  28.       Dim yrot As Float = x * sinpsi + y * cospsi
  29.       Dim xrotrange As Float = Floor(Sqr(radius ^ 2 - yrot ^ 2))
  30.       Dim xrotlim As Float = xrotrange * radius2z2 / radius
  31.       ' we plan To populate the point With a colour taken From the original image,
  32.       ' but With the condition that the point that we have found actually lies On
  33.       ' the original image, Not round the back Of it
  34.       If xrot > -xrotlim Then
  35.         ' Now look along the New X axis To remove foreshortening
  36.         ' note that the abs was needed at the extreme Of the image, probably
  37.         ' because the area scanned was Not perfectly circular
  38.         Dim x1rot As Float = (xrot * radius2z2 - z * Sqr(Abs(radius ^ 2 - xrot ^ 2 - yrot ^ 2))) / radius
  39.         Dim y1rot As Float = yrot
  40.         ' jump To where the point would be back In the original coordinates
  41.         Dim x1 As Float = x1rot * cospsi + y1rot * sinpsi
  42.         Dim y1 As Float = -x1rot * sinpsi + y1rot * cospsi
  43.         rectifiedImage[x + centreX, y + centreY] = imageToRectify[Floor(x1) + centreX, Floor(y1) + centreY]
  44.       Else
  45.         rectifiedImage[x + centreX, y + centreY] = Color.DarkRed ' area beyond limb will be dark red
  46.       Endif
  47.     Next
  48.   Next
  49.  
  50.   Return rectifiedImage
  51.  

The code still needs some tweaks, and probably highlights my beginner knowledge of Gambas…
Online now: No Back to the top

Post

Posted
Rating:
#9
Avatar
Administrator
gbWilly is in the usergroup ‘unknown’

DIYTinkerer said

Well I went back to the drawing board. I spoke to a mathematician friend of mine, explained the problem, they provided a single mathslab script that did all the maths in a single script (I was rotating, cropping, translating and rectifying all as separate functions.   The new function - which I've included here works without any memory issues :-) Interestingly none of the trigonometry actually needs calculating…   
So thanks to my friend (John H) and to gbWilly for their support.
Back to the drawing board is always a good solution if completely stuck ;)  I'm glad you got it all worked out now and working.

gbWilly
- Gambas Dutch translator
- Gambas wiki content contributor
- Gambas debian/ubuntu package recipe contributor
- GambOS, a distro for learning Gambas and more…
- Gambas3 Debian/Ubuntu repositories


… there is always a Catch if things go wrong!
Online now: No Back to the top
1 guest and 0 members have just viewed this.