I have an EmguCV.Image<Brg, Byte>() instance and another 3rd party API, that requires Stream that represents the image data.
I was able to convert the EmguCV image to the stream and pass it to the 3rd party API using System.Drawing.Bitmap.Save but that is not very efficient.
How to get the stream as afficietnly as possible?
This code works:
var image = new Image<Rgb, byte>("photo.jpg");
var bitmap = image.Bitmap// System.Drawing - this takes 108ms!
using (var ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Bmp); //not very efficient either
ms.Position = 0;
return ImageUtils.load(ms); //the 3rd party API
}
I have tried to create UnmanagedMemoryStream directly from the image:
byte* pointer = (byte*)image.Ptr.ToPointer();
int length = image.Height*image.Width*3;
var unmanagedMemoryStream = new UnmanagedMemoryStream(pointer, length);
but when i try to read from it, it throws an AccessViolationException: Attempted to read or write protected memory.
for (int i = 0; i < length; i++)
{
//throw AccessViolationException at random interation, e.g i==82240, 79936, etc
unmanagedMemoryStream.ReadByte();
}
the length is 90419328 in this case and it shoudl be correct, because it has the same value as image.ManagedArray.Length;
How to get the stream without copying the data?
Ok, there is Bytes property of type byte[] on the Image() so the answer is very easy:
new MemoryStream(image.Bytes)
Related
I'm trying to generate a Session code based on the following code from PHP in Dart/Flutter:
private $length = 32;
substr(bin2hex(random_bytes($this->length), 0, $this->length);
the problem is that I don't know how to create these random_bytes in dart and then convert them to bin2hex, using DART language.
These functions described above are from PHP (opencart system) which I must to create a hash to specify session from each user connected.
the result expected from this conversion is something like that:
"004959d3386996b8f8b0e6180101059d"
If your goal are just to generate such a hex-string using random numbers, you can do something like this:
import 'dart:math';
void main() {
print(randomHexString(32)); // 1401280aa29717e4940f0845f0d43abd
}
Random _random = Random();
String randomHexString(int length) {
StringBuffer sb = StringBuffer();
for (var i = 0; i < length; i++) {
sb.write(_random.nextInt(16).toRadixString(16));
}
return sb.toString();
}
I want to create a HttpResponse that streams a local file.
I want to use a MemoryStream, so that I can delete the file afterwards (well actually before returning the repsonse).
I always end up with an empty response although the stream seems to be valid.
Working with a FileStream in API Controller works, though.
public HttpResponseMessage GetExcelFile(Guid id)
{
// this model is needed to internally create an .xls file that represents this model
var exportModel = this.myService.GetExport(id);
// this approach does not work -> respone always empty although memory stream has content
// var stream = new MemoryStream();
// internally creates a .xls file (using lib) and returns its content as memory stream
// this.myService.ConvertToStream(exportModel, stream));
// this works fine
var stream = File.OpenRead(#"D:\test0815.xls");
var result = this.Request.CreateResponse(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = stream.Length;
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"{exportModel.Name}-Sheet.xls"
};
return result;
}
this is my method that actually converts to memorystream:
private MemoryStream SaveToStream(MemoryStream stream)
{
using (FileStream source = File.Open(
#"D:\test0815.xls",
FileMode.Open))
{
Console.WriteLine("Source length: {0}", source.Length.ToString());
// Copy source to destination.
source.CopyTo(stream);
}
return stream;
}
I also tried writing to memory stream but this did not work either.
It seems that result.Content = new StreamContent(stream); is just not working with an memory stream.
Any ideas?
finally I found a working solution:
var memoryStream = new MemoryStream((int)fileStream.Length);
fileStream.CopyTo(memoryStream);
fileStream.Close();
memoryStream.Seek(0, SeekOrigin.Begin);
HttpContent content = new StreamContent(memoryStream);
var result = this.Request.CreateResponse(HttpStatusCode.OK);
result.Content =content;
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
I'm working on a (Universal Windows) c++/cx Directx project, which builds to a dll used in a c# UWP project.
I'm using the DirectX Toolkit to load textures.
I already use it to create a texture from file, but now I need it to create a texture from a byte array that was send from the UWP project.
But when trying to use CreateWICTextureFromMemory(), the HRESULT says 0x88982F50:"The component cannot be found"
All I can find about this problem indicates the bytes are not a correct image, but I tested it in the UWP project, there I get the byte array from bingmaps (it's a static map image), and I could make a working image from these bytes.
Does annyone know what I'm doing wrong?
UWP c# download code (to get the bytes):
private async Task DownloadTexture()
{
byte[] buffer = null;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_url);
WebResponse response = await request.GetResponseAsync();
using (Stream stream = response.GetResponseStream())
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
buffer = ms.ToArray();
}
}
catch (Exception exception)
{
Logger.Error($"Could not Download Texture: {exception}");
}
_track3D.SetImage(out buffer[0], (ulong)buffer.Length);
}
Directx C++ code (that fails):
void Track3D::SetImage(uint8_t* ddsData, size_t ddsDataSize)
{
HRESULT result = CreateWICTextureFromMemory(_d3dDevice.Get(), _d3dContext.Get(), ddsData, ddsDataSize, nullptr, _Terrain.ReleaseAndGetAddressOf());
//here it goes wrong
//TODO: use the texture
}
UWP C# test code that works (displays image):
private async void setImage(byte[] buffer) //test
{
try
{
BitmapImage bmpImage = new BitmapImage();
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await stream.WriteAsync(buffer.AsBuffer());
stream.Seek(0);
await bmpImage.SetSourceAsync(stream);
}
Image image = new Image();
image.Source = bmpImage;
((Grid)Content).Children.Add(image);
}
catch (Exception exception)
{
Logger.Error($"{exception}");
}
}
EDIT:
OK, turns out the first byte in the buffer is different in the C++ code, than it was when sent from UWP. When I change that first byte to the correct value in the C++ code (as a test), the texture is correctly created.
Which raises the question, why did the value of the first byte change?
(Or what did I do wrong?)
As requested, The function setImage() looks like this in c#:
[MethodImpl]
public void __ITrack3DPublicNonVirtuals.SetImage(out byte ddsData, [In] ulong ddsDataSize);
(also, I just realised the parameter names still have 'dds' in their name, sorry about that, will change that in my code as it is misleading)
0x88982F50: “The component cannot be found”
This is WINCODEC_ERR_COMPONENTNOTFOUND which happens whenever WIC can't determine what format codec to use for a file/binary. Your problem is your transfer of the data from managed to native code is wrong.
Your interop method is set to:
[MethodImpl]
public void __ITrack3DPublicNonVirtuals.SetImage(out byte ddsData, [In] ulong ddsDataSize);
With the C++ method signature being:
void Track3D::SetImage(uint8_t* ddsData, size_t ddsDataSize)
Because of the out your first parameter is being passed as a safe array with the length in the first element.
Instead you should use:
SetImage([In] byte ddsData, [In] ulong ddsDataSize); // C#
void Track3D::SetImage(const uint8_t* ddsData, size_t ddsDataSize); // C++.
I'm using Emgu CV's SURF feature to recognize similar objects in images.
The image is drawn, showing all the key points found, in both images. The problem is that the similar points are seen in the image.
How can I save those match points in a database?
First of all, create a class SURF.cs then write the following code in it:
public void FindSURF(Image<Gray, Byte> modelImage)
{
VectorOfKeyPoint modelKeyPoints;
SURFDetector surfCPU = new SURFDetector(500, false);
//extract features from the object image
modelKeyPoints = new VectorOfKeyPoint();
Matrix<float> modelDescriptors = surfCPU.DetectAndCompute(modelImage, null, modelKeyPoints);
}
Then, in the program.cs write the following code:
SURF FindImageSURF = new SURF();
string[] filePaths = Directory.GetFiles(#"E:\folderimages\");
for (int i = 0; i < filePaths.Length; ++i)
{
string path = filePaths[i];
using (Image<Gray, Byte> modelImage = new Image<Gray, byte>(path))
{
FindImageSURF.FindSURF(modelImage);
}
}
I have seen lots of DataSnap examples in Delphi, but fewer in C++ Builder, and have not figured out how to specify that a TStream should be returned to the calling client.
I am using a simple configuration, similar to the tutorials I have seen. An example server method is:
System::UnicodeString GetData(int PatientID, int& count, TStream* stream);
I have no trouble calling that method from my client. Because count is passed as a reference, the DataSnap server knows to send it back to the client. Generate Client Classes, on the TSQLConnection in the client, connects to the server, and generates the following:
System::UnicodeString __fastcall TServerMethods1Client::GetData(int PatientID, int &count, TStream* stream)
{
if (FGetDataCommand == NULL)
{
FGetDataCommand = FDBXConnection->CreateCommand();
FGetDataCommand->CommandType = TDBXCommandTypes_DSServerMethod;
FGetDataCommand->Text = "TServerMethods1.GetData";
FGetDataCommand->Prepare();
}
FGetDataCommand->Parameters->Parameter[0]->Value->SetInt32(PatientID);
FGetDataCommand->Parameters->Parameter[1]->Value->SetInt32(count);
FGetDataCommand->Parameters->Parameter[2]->Value->SetStream(stream, FInstanceOwner);
FGetDataCommand->ExecuteUpdate();
count = FGetDataCommand->Parameters->Parameter[1]->Value->GetInt32();
System::UnicodeString result = FGetDataCommand->Parameters->Parameter[3]->Value->GetWideString();
return result;
}
One can see that the generated code is setting the count from the returned parameter, indicating that the server is sending it back. However, the stream is only sent to the server, and not set back on the client.
In Delphi, I would use var to indicate that the reference should be passed back to the caller. However, using a reference on TStream does not work, either.
For this definition:
System::UnicodeString GetData(int PatientID, int& count, TStream& stream);
I get this generated code:
System::UnicodeString __fastcall TServerMethods1Client::GetData(int PatientID, int &count, TStream* &stream)
{
if (FGetDataCommand == NULL)
{
FGetDataCommand = FDBXConnection->CreateCommand();
FGetDataCommand->CommandType = TDBXCommandTypes_DSServerMethod;
FGetDataCommand->Text = "TServerMethods1.GetData";
FGetDataCommand->Prepare();
}
FGetDataCommand->Parameters->Parameter[0]->Value->SetInt32(PatientID);
FGetDataCommand->Parameters->Parameter[1]->Value->SetInt32(count);
FGetDataCommand->Parameters->Parameter[2]->Value->SetStream(stream, FInstanceOwner);
FGetDataCommand->ExecuteUpdate();
count = FGetDataCommand->Parameters->Parameter[1]->Value->GetInt32();
stream = FGetDataCommand->Parameters->Parameter[2]->Value->GetStream(FInstanceOwner);
System::UnicodeString result = FGetDataCommand->Parameters->Parameter[3]->Value->GetWideString();
return result;
}
Which throws an access violation in the ExecuteUpdate() call.
Is there a way I can pass a pointer to the server method and mark it in some way that the stream should be passed back to the calling client?
Remy's response was correct.
The server method is
System::UnicodeString TServerMethods1::GetData(int PatientID, int& count,
TStream*& stream) {
count = 10;
String newSimpleString = "New Simple String";
TByteDynArray theBytes;
theBytes.Length = newSimpleString.Length();
for (int i = 0; i < newSimpleString.Length(); i++) {
theBytes[i] = newSimpleString[i + 1];
}
TDBXBytesStream* newStream =
new TDBXBytesStream(theBytes, newSimpleString.Length());
stream = newStream;
return "StringResult";
}
and the client method is
void __fastcall TForm1::Button2Click(TObject *Sender) {
int count = 1;
TStringStream* stringStream = new TStringStream(String("Passed In"));
TStream* str = stringStream;
String result = ClientModule1->ServerMethods1Client->GetData(1, count, str);
int len = str->Size;
ShowMessage("Result is: '" + result + "' and " + String(count) +
", and stream is " + String(len) + " bytes long");
}
With FInstanceOwner at true (the default as generated), the stream passed in as a client method gets freed the next time the method is called.
On the server, the newly created TDBXBytesStream gets freed the next time the server method is called.
TDBXBytesStream is not a fully functional stream - for example, I could not get CopyFrom to copy from a TStringStream (for example), which is why I use the TByteDynArray.
Also, I could not modify the stream passed in to the server method by writing to it, which is why I needed to assign a new TDBXBytesStream to the passed in reference.
Thanks, Remy, for helping me with this.