Converting ushort pointer to something I can use to display images
I have a pointer, knowing height and width what is the best way to display said image? I am not contrary to converting it to 8 bit. Just trying to understand how I can use said pointer since obviously no image processing extension in c# can deal with it
136 Replies
I am open to using any extension btw
Span
has a ctor that takes a pointer and a length, so you can construct one using a pointer, and then go from there to an array, or construct an image directly if you have a method that can take a span.What is "one" here? Sorry I don't get it
You can make a Span using a pointer and a length. Which you will then be more easily able to manage within C#.
Is it as simol as Span <ushort> array = image?
Knowing ushort * image is the pointer
mmm... more like...
Presuming you have some library that takes a span to construct an image. Alternatively you might need to do something like...
It depends on what format data you have, what format of data you need, and what library you are using to manage the images in. The BCL doesn't really have a standard "image" type.
Okay, I'll try with emgu
Okay the problem is I don't see an extension that uses span, an alternative would be to use two nested for loops and copying the data from the pointer but that may take too long
what library are you using?
Emgu at the moment
I started with Imageshaep but it doesn't handle grayscale well so I turned to Emgu
looks like this method takes a ptr, though I imagine you'll need to be careful with the depth and what not https://emgu.com/wiki/files/3.0.0/document/html/c0cc246f-7c2a-e2c9-7b98-f2a98beef077.htm
looks kind of dangerous though.
What's your endgoal here?
Being able to display and save said image, it can be displayed at lower quality though. That isn't as important
so like WPF to display?
Yeah, can be on a win form too if it's better. Learning c# so I don't exclude anything
WPF has a bunch of methods for handling this as well. https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.bitmapsource.create?view=windowsdesktop-8.0
BitmapSource.Create Method (System.Windows.Media.Imaging)
Creates a new BitmapSource that has the specified properties and options.
note that like the method that takes a pointer also doesn't copy so you need to be careful with the unmanged memory.
ultimately if you want to copy and/or transform the data, looping through all the end points and copying/translating them may be necessary with a for loop at some point. I wouldn't worry about the performance of this unless and untill you identify it as a bottleneck.
you'll need to say what exactly the the format of the data is
i assume this is the same library as the other question
Yeah it's the same library, UINT_16 grayscale
In c# ushort
Yes, this is what I have so far
unsafe public void button1_Click(object sender, EventArgs e)
{
var device = new NativeMethods.StnDevice();
device.ImageAcquired += Device_ImageAcquired;
device.connect();
device.StartAcquisition();
unsafe void Device_ImageAcquired(ushort bank, ushort frame, int width, int height, ushort* image, bool moreAvailable)
{
int i, j, counter; counter = 0; Image<Gray, UInt16> img = new Image<Gray, UInt16>(width, height); // if i find a way to convert the pointer into an array with Marshal maybe i can use the code below for now i copy uint16 by uint16 // Buffer.BlockCopy(image, 0, img.Data, 0, width*height * sizeof(ushort)); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { img.Data[i, j, 0] = image[counter]; counter++; } } try { imageBox1.Image = img; textBox1.AppendText("we're in there"); } catch (Exception ex) { MessageBox.Show(ex.Message); }
} device.disconnect(); }
int i, j, counter; counter = 0; Image<Gray, UInt16> img = new Image<Gray, UInt16>(width, height); // if i find a way to convert the pointer into an array with Marshal maybe i can use the code below for now i copy uint16 by uint16 // Buffer.BlockCopy(image, 0, img.Data, 0, width*height * sizeof(ushort)); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { img.Data[i, j, 0] = image[counter]; counter++; } } try { imageBox1.Image = img; textBox1.AppendText("we're in there"); } catch (Exception ex) { MessageBox.Show(ex.Message); }
} device.disconnect(); }
is there more you can say about what "UINT_16 grayscale" is? does that mean that each pixel is one from 65536 different shades of gray?
it is very very difficult to write this code without knowing what exactly the pixels are
Yes
In c++ the pixels were a const uint16_t*
That's why it's a ushort* in c# now
what is this Image<Gray, UInt16> thing that you are trying to use
is it from a library that you have?
Yeah i'm trying to display it by using emgu. I can use other libraries though
what is imageBox1
It's the picturebox given by emgucv
is it the thing from emgu
i see
is there something about this code which is not working
It's not showing anything on screen. I used append text to check if it even ran Device_ImageAcquired and it doesn't
ok, well, if it's not running Device_ImageAcquired then that is an issue
Yeah when I click the button on the form it doesn't show anything
Oh wait when I ran in debug it didn't show any errors but in release I get the error System.BadImageFormatException
HRESULT: 0x8007000B
when you built the C++ DLL, what configuration did you use when building it
X86
And I'm using that when I'm still using x86 now
Yeah i saw that online
so, you don't have "Prefer 32-bit" disabled in your Release configuration in the C# project properties
Oh i did have the planfrom target as x64
Still doesn't show an image though
when you said that you used append text to check if it even ran Device_ImageAcquired what does that mean exactly
if it really is not running it is going to be extremely difficult to debug this
i do not know at all how this C++ library works or is supposed to be used
Okay so device.ImageAcquired += Device_ImageAcquired should automatically call Device_ImageAcquired every time
well, yes, it's certainly supposed to do that
i don't know why it is not doing that
private unsafe void OnImageAcquired(ushort bank, ushort frame, int width, int height, ushort* image, bool moreAvailable)
{
Task.Run(() => ImageAcquired?.Invoke(bank, frame, width, height, image, moreAvailable));
}
Is there an error here?
i do not think there is an error in the code that i wrote, no
that is why it is hard to figure it out
if you put a MessageBox.Show inside of OnImageAcquired does it show anything?
I put message box.show in private unsafe void OnImageAcquired and it didn't show anything
Wait, when is OnImageAcquired supposed to be used in the code?
it is what the C++ calls
Ok
Check dm I sent a libeshare so you can see all the code
Either way if you'd rather not do that I can just Share the library to you
Oh now I know why it doesn't work
@reflectronic "don't call any st::stn_device method from this callback, result of such a call is undefined"
Well they could have been more explicit with that but yeah that's probably why
Also while that may be the problem there is also another issue, wether the panel is connected or not connect and start acquisition don't give back exceptions which means everything else may be correct and the connection and acquisition part are the issue
Ok yeah the callback is very dangerous
sorry, i went to bed
i don't think this is the problem--we don't use anything from the C++ object in the callback
I can send it again when I have the PC on hand it's not mine
The only advice that I've found online regarding this is this "Create a byte array of sufficient size, use" "fixed" to get a pointer to the byte array, and call Buffer.MemoryCopy to copy the actual data, You could also create a pool of buffers to reuse"
@reflectronic
this doesn't help because the Device_ImageAcquired is not called in the first place
Maybe it is called, messagebox doesn't work quite as well in program.cs it should be used in the form from what I understand
What code would I use to see if its actually called?
you would usually use a debugger and set a breakpoint
Nvm Device_ImageAcquired isn't called I'm talking
About the task.run
Meant to say that OnImageAcquired maybe is called and Device_ImageAcquired is the problem. Though I have no idea why that would be the case
i would doubt it
I'm using visual studio 2019,judt specifying in case that could change anything
Ok it's almost 2 am that's all from me for now, thank you for your help as always
ifdef _WIN32
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
WSADATA wsa_data;
if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0)
{
sync_print(L"WSAStartup failed");
return 1;
}
#endif
sync_print(program_name, " started. ", configuration, " ", platform);
sync_print(" SDK version ", stn::stn_device::get_sdk_version());
device dev;
if(!set_parameters(dev)) return 1;
if(!connect(dev)) return 1;
Bool result = acquire_images(dev);
disconnect(dev);
return (result? 0 : 1); // 0 - success, 1 - failure
This was the actual main before it was modified
@reflectronic
ok. so. when you showed me the code before and i asked "is that all you need to do" and you said "yes" the answer was not actually "yes"
As i said connect and start acquisition don't give errors even when I don't have the pal. Comnect
what does set_parameters do
because you did not show me this set_parameters last time
I already added set parameters
It sets the general and advanced parameters
I do apologised though. The code isn't mine and I'm trying to help a person
declspec(dllexport) bool set_parameters_general(dotnet_device* device) {
try {
return &dotnet_device::set_general_parameters;
}
catch (...) {
return false;
}
}
declspec(dllexport) bool set_parameters_advanced(dotnet_device* device) {
try {
return &dotnet_device::set_advanced_parameters;
}
catch (...) {
return false;
}
}
declspec(dllexport) bool set_parameters_logging(dotnet_device* device) {
try {
return &dotnet_device::set_logging_parameters;
}
catch (...) {
return false;
}
}
declspec(dllexport) bool set_parameters_acquisition(dotnet_device* device) {
try {
return &dotnet_device::set_acquisition_parameters;
}
catch (...) {
return false;
}
}
internal static extern bool SetGeneralParameters(StnDeviceHandle device);
[DllImport("Dll2.dll", EntryPoint = "set_parameters_advanced")]
internal static extern bool SetAdvancedParameters(StnDeviceHandle device);
[DllImport("Dll2.dll", EntryPoint = "set_parameters_logging")]
internal static extern bool SetLoggingParameters(StnDeviceHandle device);
[DllImport("Dll2.dll", EntryPoint = "set_parameters_acquisition")]
internal static extern bool SetAcquisitionParameters(StnDeviceHandle device);
public void SetGenParameters()
{
if (!NativeMethods.SetGeneralParameters(handle))
{
throw new Exception("couldn't set parameters");
}
}
public void SetLogParameters()
{
if (!NativeMethods.SetLoggingParameters(handle))
{
throw new Exception("couldn't set parameters");
}
}
public void SetAdvParameters() etc
Already put this code
The problem is even before that as when I try to connect it does not give any error when it should when there is no connectiin
your
set_parameters_general
is not implemented correctly
it does not do anything
it just returns true
always
to be clear: the C++ program works, right?Yes the c++ program runs
if you delete
set_parameters
from your C++ program does it still work?No
ok. so. this is very good
it means that, it's very likely that the problem is this
which means that, the fix is probably very easy
can you show the C++ code for set_parameters
bool set_parameters(device& dev)
{
if (!set_general_parameters(dev)) return false;
if (!set_advanced_parameters(dev)) return false;
if (!set_logging_parameters(dev)) return false;
if (!set_acquisition_parameters(dev)) return false;
return true;
}
bool set_general_parameters(device& dev)
{
stn::general_parameters p;
if (!dev.get_general_parameters(p))
{
sync_print(utilities::stn_error_to_string("get_general_parameters"));
return false;
}
// In most cases, general_parameters default values are OK.
// You may need to change something in general_parameters, for example,
// if you want to use non-default device IP address.
// Uncomment the following code fragment to get this functionality.
#if 0
p.address = "192.168.100.100";
// Change other parameters if necessary, see details in general_parameters definition.
if (!dev.set_general_parameters(p))
{
sync_print(utilities::stn_error_to_string("set_general_parameters");
return false;
}
#endif
sync_print(FUNCTION, " Device IP address: ", p.address);
return true;
}
bool set_advanced_parameters(device& dev)
{
stn::advanced_parameters p;
if (!dev.get_advanced_parameters(p))
{
sync_print(utilities::stn_error_to_string("get_advanced_parameters"));
return false;
}
// For better performance, change default advanced parameters.
p.use_non_paged_buffer = true;
p.image_socket_input_buffer = stn::image_socket_input_buffer_max;
p.table_socket_output_buffer = stn::image_socket_output_buffer_max;
p.host_eth_speed = stn::ethernet_speed::h1g;
if (!dev.set_advanced_parameters(p))
{
sync_print(utilities::stn_error_to_string("set_advanced_parameters"));
return false;
}
sync_print(FUNCTION, " Ethernet speed: ", stn::stn_names::ethernet_speed_to_string(p.host_eth_speed));
return true;
}
can you show what e.g.
dotnet_device::set_general_parameters
is? did you basically just copy set_general_parameters
, but replaced dev
with this
?Yes
Btw i did send you the live share link
yeah, so, you need to replace
return &dotnet_device::set_general_parameters;
with return device->set_general_parameters();
does the live share have the C++ in it tooYeah
can you go to the file with dotnet_device in it
oh, it's this one
Yeah
you need to copy the code that you just pasted in
like, this whoel set_parameters thing needs to be pasted in here
Done
Or do you mean it needs to be pasted inside the "try"?
i will move them into dotnet_device
oh, i can't edit this file
can you move these functions inside of dotnet_device
put them right below
dotnet_device(image_acquired_callback* dotnet_callback) : dotnet_callback(dotnet_callback) {}
for each of these functions,
delete the parameter device& dev
then, everywhere it does something like dev.get_advanced_parameters(...)
, replace it with get_advanced_parameters(...)
like, just delete dev.
ok. you changed all of these functions to make them not work
return &dotnet_device::connect;
is the exact same as return true;
your connect function does nothing. none of them do anything
does return device->connect();
not work?Yeah i mentioned it
.
instead of
return &dotnet_device::connect;
ok. so. it seems to work
and now you need to do this for every other thing you changedI get the errors dotnetdevice::set... Function does not take 1 arguments
And non standard syntax; use & to create a pointer to member
no, those are old errors. try rebuilding again
Still get function does not take 1 arguments 233 261 305
The lines
Trying to give you writing privileges but it doesnt seem to work
hold on
if you move your cursor to line 176
put it on the "stn_device"
then, press F12 on your keyboard
Done
ok, i understand what needs to happen
can you try building the C++ dll
@nope
Ok
Done
ok, well, now it's failing to connect
Does it have to do with the first part of this code maybe?
i think i already did that
can you try building and running it again
i added some more things so maybe it will print out an error
It's not doing anything this time
Not sure you see the form
no i don't see the form
can you try running it again
Nvm it works one moment
It got into a messagebox loop
Okay, now it shows an image, though it's all black
ok. can you try running it again
Is that you doing something right now?
yeah
Oh my bad
i am just looking at what it thinks the picture is
can you try running again
ok. well. there seems to be a picture...
i can see it's reading pixels
and, like, the pixels are not 0, they are not the same, it seems like it might be working
i don't know why it's showing all black for you
ok let me try something
i am going to try displaying it in a window using a different drawing library
Ok
Oh it may be that the pixel by pixel of emgu is too slow, looked it up online and people were complaining about that
ok. i have tried something
can you try running the application
i am not sure if it works
Dispatcher and monitor do not exist
Gotta add a couple "using"?
can you try again
again
and again
ok, i made a mistake, please hold
try again
hm
is there a place you can have the code save a png file
Is that the right form to save an image?
you need to put a path
it needs to be somewhere that you can open it
Yeah that's a path
ok try running it
ok. can you open the png
It's blank
Yeah i can open it
hm
Goddammit
When the data is saved in c++
can you try again @nope
Orig does not exist
try it again
Above the name space is how the file is saved in c++
No image is being saved
yes, but you can't look at the image that makes to see if it's correct so that does not help
can you press the button
Pressed
did it ask you to reload the project
No
It didn't say I need to stop debugging like before
The first time with only the emgu code the imagebox was all black now it doesn't load an image
Saying that in case that wasn't part of the plan
ok let me try something else
can you try re-running
Yeah there were some errors in the form
is it showing anything
No I mean in the code
The form code is kinda messed up now
which form code
Just a}
Missing somewhere now
can you try rebuilding
Ok now the imagebox is all black
Says form1.o is never used ad a warning btw
can you try again
Cannot implicitly convert ushort to emgu cv structure gray
ok hold on
can you try running it again
still black?
Still all black
try running it again
if you hover over "one" with your mouse what does it tell you
hm actually it is sending them back to me
ok. uh. are you OK with sending one of these pictures to me
it is hard to figure out what is going on when the live share is this laggy
i will write some code to save the bytes to a file
It's because the device takes up all the connection
Okay maybe displaying it in 8bit may be the solution
can you run the program again
again
All black
Thank you for your help
ok hold
let me rejoin
if you are OK with sharing one of the pictures, can you send the "out.bin" file that is in the bin/Debug
Wait this is release not debug, one moment let me run it again then
i see it in the debug folder
Yeah that's an old out
Ok now I'll send it
and can you start the program again
Please don't upload any potentially harmful files @nope, your message has been removed
send it in DMs
Sent
and can you run the program as debug this time
Yeah i did this time
are you sure it is running as debug and not as release
I mean it it on "debug" and "x86" settings
If there are others I'm missing I can check
can you relaunch
i just need to see what the size of the image is
then i will be able to use this file on my computer and see what needs to happen to get it to show
1792
ok