Converting a Memory Address to a MemoryBlock

Hello
I have an Integer representing a memory address, and I want to get a corresponding MemoryBlock .
Based on Charles Yeomans’ tips, I wrote this function with 2 arguments the address in memory and the size I want access

GetMemoryBlockFromAddress(theAddress as Integer, pSize as integer)
  dim m as new MemoryBlock(pSize)
  m.Long(0) = theAddress
  m = m.Ptr(0)
  Return m

Under debugging this seems correct mb=GetMemoryBlockFromAddress(imAddress,sizeimg) : I can see the values associated to the pointed address, but the memoryblock.size is equal to -1 after calling the function.
Consequently Imagewell1.Image = Picture.FromData(mb) raises a NilObjectException error.
What’s wrong in the code ? Thanks a lot for your help.

Memory allocated by something outside of Xojo (say a dylib call etc) will give you a “size unknown” or -1

http://documentation.xojo.com/index.php/MemoryBlock

You’ll need some other way to know how big it is

GetMemoryBlockFromAddress(theAddress as Integer, pSize as integer) dim m as new MemoryBlock(pSize) <-- pSize is wrong here m.Long(0) = theAddress m = m.Ptr(0) <– m is assigned a different memory block here Return m

The above code could be written as:

GetMemoryBlockFromAddress(theAddress as Integer, pSize as integer) dim m1 as new MemoryBlock(4) // m is a pointer, so it will always be only 4 bytes m1.Long(0) = theAddress dim m2 as MemoryBlock = m1.Ptr(0) Return m2

Or shorter:

dim m as new MemoryBlock(4) m.Long(0) = theAddress Return m.Ptr(0)

Thanks Norman
I know the size of memory which is given by OpenCV (via a dll call)
Assuming that img is a pointer to an opencv image

img = cvLoadImage (f.NativePath, CV_LOAD_IMAGE_COLOR)  // load image with opencv
// get some values from the pointer
wimg= img.int32Value(40)
himg = img.int32Value(44)
nchannels = img.int32Value(8)
depth= img.int32Value(16)
simg = img.int32Value(72)
sizeimg = img.int32Value(64)

sizeimg gives me the exact size of the binary data
Thanks for the link

Thanks Eli
I’ll test your suggestion

To Eli
Still size= -1 with the 2 suggestions

You will need to create your own wrapper class that tracks size. Setting the MemoryBlock from a Ptr always gives it size -1, and if you try to set the size afterwards it clears the data to all 0.

Also, an easier way to create a MemoryBlock from a Ptr is just assign it

dim m As MemoryBlock = myPtr

Or if the address is as an integer then cast it

dim m As MemoryBlock = Ptr(myInteger)

That’s using the old, classic MemoryBlock. The new Xojo.Core.MemoryBlock has a constructor for this that’ll retain the size

dim m As new Xojo.Core.MemoryBlock(myPtr, theSize) //or dim m As new Xojo.Core.MemoryBlock(Ptr(myInteger), theSize)

You can use this in place of your method since your method would be

Function GetMemoryBlockFromAddress(theAddress as Integer, pSize as integer) As Xojo.Core.MemoryBlock return new Xojo.Core.MemoryBlock(Ptr(theAddress), pSize) End Function

Thanks a lot Will
Very clear explanation
I’ll test asap

[quote=212480:@FranoisJouen]To Eli
Still size= -1 with the 2 suggestions[/quote]
Of course it is -1, as Norman has already explained.

The question is: does he have a pointer pointing to a memory block or a pointer which is the start of a memory block. From the OP
I think he has the first, so this would not work:

[quote=212483:@Will Shank]Also, an easier way to create a MemoryBlock from a Ptr is just assign it

dim m As MemoryBlock = myPtr[/quote]
This would only work if the pointer is the start of the memory block.

[quote=212476:@FranoisJouen]wimg= img.int32Value(40)
himg = img.int32Value(44)
nchannels = img.int32Value(8)
depth= img.int32Value(16)
simg = img.int32Value(72)
sizeimg = img.int32Value(64)[/quote]
You would probably better use a structure instead of a memory block:

Structure IplImage int nSize As Int32 ID As Int32 nChannels As Int32 alphaChannel As Int32 depth As Int32 colorModel As Ptr channelSeq As Ptr dataOrder As Int32 origin As Int32 align As Int32 width As Int32 height As Int32 roi As Ptr maskROI As Ptr imageId As Ptr tileInfo As Ptr imageSize As Int32 imageData As Ptr widthStep As Int32 BorderMode As Ptr BorderConst As Ptr imageDataOrigin As Ptr End Structure
You then can use that directly in the declares:

Declare Function cvCloneImage Lib "..." (image As IplImage) As IplImage

And query it by the field names of the structure:

Dim clonedImage As IplImage = cvCloneImage(someIplImage) Dim nChannels As Integer = clonedImage.nChannels

[quote=212488:@Eli Ott]You would probably better use a structure instead of a memory block:

Structure IplImage int nSize As Int32 ID As Int32 nChannels As Int32 alphaChannel As Int32 depth As Int32 colorModel As Ptr channelSeq As Ptr dataOrder As Int32 origin As Int32 align As Int32 width As Int32 height As Int32 roi As Ptr maskROI As Ptr imageId As Ptr tileInfo As Ptr imageSize As Int32 imageData As Ptr widthStep As Int32 BorderMode As Ptr BorderConst As Ptr imageDataOrigin As Ptr End Structure
You then can use that directly in the declares:

Declare Function cvCloneImage Lib "..." (image As IplImage) As IplImage

And query it by the field names of the structure:

Dim clonedImage As IplImage = cvCloneImage(someIplImage) Dim nChannels As Integer = clonedImage.nChannels[/quote]

The function signature needs to stay taking a pointer and returning a pointer. The parameter can be made ‘ByRef image As IplImage’ (which will pass a pointer to the structure), but the return type can’t change.

I don’t understand the difference. A Ptr points to an address and making a MemoryBlock from it gives a MemoryBlock starting at that address. If you want the MemoryBlock to start at a different address then repoint the Ptr before making a MemoryBlock.

You’re describing a pointer to the start of a memoryblock. The other is a pointer to a 4-byte chunk of memory which contains the address of the memoryblock. Both are possible coming back from a declare and you obviously need to know which you have.

Thanks Tim, that makes sense. But to dereference a pointer to a pointer I use

[code]dim m As MemoryBlock = myPtr.Ptr(0)
//or
dim m As new Xojo.Core.MemoryBlock(myPtr.Ptr(0), theSize)

//starting with an integer address
dim m As MemoryBlock = Ptr(myInteger).Ptr(0)
//or
dim m As new Xojo.Core.MemoryBlock(Ptr(myInteger).Ptr(0), theSize)[/code]

Hi everybody
Thanks for this very interesting discussion about pointers and memoryblock
@Will: xojo.core.memoryblock works fine. Now the question is that picture.fromdata requires an old MB !
@Eli and Joe: of course I’ve implemented the IplImage structure, which also works fine for retrieving information about opencv image
You’ll find some code here https://github.com/ldci/OpenCV-Xojo that allows accessing OpenCV with Xojo
Best regards from Paris

Dim pic As Picture = Picture.FromData(newFrameworkMemoryBlock.Data)

Thanks Eli

Hello everybody
I’m back for a new interrogation

  Dim RGBBitmap as MemoryBlock
  Dim w,h as integer
  Dim imgSize as integer
  Dim nChannels as integer
  imgSize=imgOCV.Int32(64)
  w= imgOCV.int32(40)
  h= imgOCV.int32(44)
  nChannels= imgOCV.Int32(8)
  Dim imageData As New MemoryBlock(imgSize)
  RGBBitmap = new MemoryBlock(h * w * nChannels)  ' create a MemoryBlock for the OpenCV RGB format
  imageData= imgOCV.ptr(68)                                        'get OpenCV image BGR data fom pointer address
  RGBBitmap=imageData.MidB(0,imgSize)                   'Fine, we can access pointed data 
  return RGBBitmap

This function is OK and sends back a MemoryBlock with all binary values contained in OpenCV Image (imgOCV) passed as argument to the function.
Is there an easy way to update a picture with the returned MemoryBlock?
As far I understand, PictureGetData requires a memoryblock including an header.
Any suggestions are welcomed! Thanks a lot.

The easiest/fastest way I know to go from pixel data to a Picture is to use FromData with the BMP format. The header is only 54 bytes long and simple to generate.

The problem in your case is the pixel format won’t work. Uncompressed BMP is BGRA format.

Trying to process the memoryblock from RGB to BGRA might be just the same as scanning the memoryblock to RGBSurface.Pixel (the usual technique).

If you draw with OpenGL instead of Canvas/Picture then you can pass the Memoryblock directly in. OpenGL supports many raw formats and RGB is one. Plus OpenGL is usually faster.

Here’s a long discussion on various ways to get pixel data out. Many of the ideas work going the other way.
https://forum.xojo.com/5136-optimize-speed-of-picture-to-rgba-memoryblock-algorithm

Also, it looks like you instantiate imageData on this first line then throw that away 2 lines later. If this is your actual code then I don’t think you need to new it.

Dim imageData As New MemoryBlock(imgSize) <--- new necessary? RGBBitmap = new MemoryBlock(h * w * nChannels) imageData= imgOCV.ptr(68)