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.
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)
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
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 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.
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)