Cvb.Image.GetImageVPA

Hello,

I am making a program by Python, I wonder how I can have access to the information I could get from Cvb.Image.GetImageVPA(image, 0, out pnt, out pnt2) when I was codding in C#.

Thank you in advance

Hi @Fatemeh

The pixel access in CvbPy is as follows:

    1 # CVBpy Example Script
    2 #
    3 # 1. Loads an image from file.
    4 # 2. Converts it to a numpy array without copying
    5 # 3. Modify pixel values through numpy
    6 # 4. Save the image. 
    7 #
    8 # Requires: numpy
    9 
   10 import os
   11 import cvb
   12 
   13 image = cvb.Image(os.path.join(cvb.install_path(), "tutorial", "Clara.bmp"))
   14 
   15 # copy=Fasle is default, but just a request
   16 np_array = cvb.as_array(image, copy=False)
   17 
   18 if np_array.flags["OWNDATA"]:
   19     raise RuntimeError("cannot map to numpy array")
   20 
   21 # pixel access
   22 print("Modifining pixel data via numpy array.")
   23 np_array[83 : 108, 48 : 157] = 0
   24 
   25 print("Saving: ./ClaraUnknown.bmp")
   26 image.save("ClaraUnknown.bmp")
   27 

2 Likes

Thanks for your answer.

This solution did not give me the data I needed, I need exactly the equivanet of Cvb.Image.GetImageVPA() in Python.
The data that I read from camera is in nonlinear format.

Hi @Fatemeh

There is no VPAT functionality in Cvpy. It is not possible to convert all C# implementation and functionality exactly into Python. Knowing pixel coordinate you can also get its value using get_pixel function:

List[float] get_pixel (self,  cvb.Point2D  position )  

Please let us know what exactly you plan to do.

Hi @Fatemeh

the information returned by GetImageVPA is only usable when working with pointers (basically the VPAT is a set of two tables with offsets that can be added to a base pointer in order to determine the address of a pixel (x, y):

p_{pixel} = p_{base} + vpat_{x}[x] + vpat_{y}[y]

To actually make use of the pointer p_{pixel} the language you are working with must support the notion of pointers. Python does not directly support the notion of pointers, making it hard and very error-prone to actually work with VPAT information, which is why we never ported GetImageVPA into that realm.

If the fact that you are dealing with a nonlinear VPAT is causing issues, you might want to make a deep copy of the image: The VPAT of an image that is the result of a deep copy of a :cvb: image is always linear.

1 Like

Thank you @MandanaS and @illusive

Let me explain more, I have this code in C#

image = _stream.Wait(out status);
var buffer = new long[_width];
IntPtr pnt;
IntPtr pnt2;
bool success = Cvb.Image.GetImageVPA(new SharedImg(image.Handle), 0, out pnt, out pnt2); 
Marshal.Copy(pnt, buffer, 0, buffer.Length);

although my image data at first is 8bpp

I could have access to 64 bpp data by using the code above

I want to do exactly the same thing in Python, because I need information in 64 bpp format.

@Fatemeh

Your image has only 1 byte information I do not know why you want to convert it to 8 bytes. You can do this conversion in python as it shows below:

np_array_64 = np_array.astype(int64,copy=False)

@MandanaS As you see my numbers are greater than 255 but in python the max is 255.
I need the rest of information so I need a real value in 8 bytes, not just converting a 1 byte number to 8 bytes.
It shows 1 byte, but we read the rest of information in C# in 8 bytes

@Fatemeh

The screenshot from your code shows that the actual image pixel hat one byte information that means in original image each pixel can have a maximum decimal value of 255. by defining an array with the type of long (int64) you are trying to convert one byte Information to 8 byte and end up with strange pixel values.

Hi @Fatemeh,

I am sorry, but the code you posted may potentially produce undefined behavior. If it does what you expected, then this is by chance more than anything else. Your snippet was:

image = _stream.Wait(out status);
var buffer = new long[_width];
IntPtr pnt;
IntPtr pnt2;
bool success = Cvb.Image.GetImageVPA(new SharedImg(image.Handle), 0, out pnt, out pnt2); 
Marshal.Copy(pnt, buffer, 0, buffer.Length);

in Marshal.Copy(pnt, buffer, 0, buffer.Length); all you do is use the base pointer returned by the GetImageVPA call. This pointer is not guaranteed to point to the address of pixel (0, 0). The address of pixel (0, 0) must be calculated as

Cvb.Image.VPAEntry* pVPAT = (Cvb.Image.VPAEntry*)pnt2[0].ToPointer();
var pPixel = (byte*)pBase[0] + pVPAT[0][y].YEntry.ToInt64() + pVPAT[0][x].XEntry.ToInt64() 

Only if XEntry and YEntry in the above code happen to be zero (which is for example not the case for a loaded bitmap file) will the Marshal.Copy actually copy the first line. If, on the other hand, XEntry and YEntry are both non-zero, then the Marshal.Copy will sooner or later raise an access violation.

In you case, the image is linearly arranged and 1 pixel high, so XEntry and YEntryare very likely to be zero, but it would be good to safeguard versus the possibility that they are not.

As for the original task and question:

  • As stated before, CVBpy does not give access to image data pointers. Python, as a language, does not have a means to work with pointers and exposing these pointers would do more harm than good.
  • This also means that you will not be able to read out the pixel data as 64 bit numbers in a way similar to what has been done in C#.
  • The closest fit you can achieve would be through the get_pixel member of the image plane you are working on. This returns the pixel values as float values. Cast them to int, then combine 8 of them (upshifted by 0, 8, 16, 24, 32, 40, 48, 56) by adding their values and you will have the 64 bit representation:
pixels = [None] * 8
for x in range(0, 7):
  pixels[x] = int(myImg.planes[0].get_pixel(Point2D(x, 0)))
val64 = pixels[0] + pixels[1] << 8 + pixels[2] << 16 + pixels[3] << 24 ... + pixels[7] << 56

Python seamlessly switches from plain 64 bit integers to long (unbound) integers if the range [-sys.maxsize - 1 ... sys.maxsize] is exceeded - which will most likely be the case for your calculations. So altogether the performance will probably not be great.

2 Likes