I'm trying to convert a sample from objective C to Monotouch, and I have run into some difficulties.
Basically I want to read a video file, and decode the frames one by one to an opengl texture.
The key to doing this is to use the AVAssetReader, but I am not sure how to set this up properly in Monotouch.
This is my code:
AVUrlAsset asset=new AVUrlAsset(NSUrl.FromFilename(videoFileName),null);
assetReader=new AVAssetReader(asset,System.IntPtr.Zero);
AVAssetTrack videoTrack=asset.Tracks[0];
NSDictionary videoSettings=new NSDictionary();
NSString key = CVPixelBuffer.PixelFormatTypeKey;
NSNumber val=0x754b9d0; //NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; - Had to hardcode constant as it is not defined in Monotouch?
videoSettings.SetNativeField(key,val);
//**The program crashes here:
AVAssetReaderTrackOutput trackOutput=new AVAssetReaderTrackOutput(videoTrack,videoSettings);
assetReader.AddOutput(trackOutput);
assetReader.StartReading();
The program crashes on the line indicated above, with an invalid argument exception, indicating that the content of the NSDictionary is not in the right format? I have checked the video file, and it loads well, "asset" contains valid information about the video.
This is the original Objective C code:
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
AVAssetReaderTrackOutput *trackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:videoTrack outputSettings:videoSettings];
[_assetReader addOutput:trackOutput];
[_assetReader startReading];
I'm not that into Objective C, so any help is appreciated.
EDIT: I used the code suggested below
var videoSettings = NSDictionary.FromObjectAndKey (
new NSNumber ((int) MonoTouch.CoreVideo.CVPixelFormatType.CV32BGRA),
MonoTouch.CoreVideo.CVPixelBuffer.PixelFormatTypeKey);
And the program no longer crashes. By using the following code:
CMSampleBuffer buffer=assetReader.Outputs[0].CopyNextSampleBuffer();
CVImageBuffer imageBuffer = buffer.GetImageBuffer();
I get the image buffer which should contain the next frame in the video file. By inspecting the imageBuffer object, I find it has valid data such as the width and height, matching that of the video file.
However, the imageBuffer BaseAddress is always 0, which indicates the image has no data? I tried to do this as a test:
CVPixelBuffer buffer=(CVPixelBuffer)imageBuffer;
CIImage image=CIImage.FromImageBuffer(buffer);
And image is always returned as null. Does this mean the actual image data is not present, and my imageBuffer object only contains the frame header info?
And if so, is this a bug in Monotouch, or am I setting this up wrong?
I had an idea that I may need to wait for the image data to be ready, but in that case, I do not know how either. Pretty stuck now...
You need to create the NSDictionary like this:
var videoSettings = NSDictionary.FromObjectAndKey (
new NSNumber ((int) MonoTouch.CoreVideo.CVPixelFormatType.CV32BGRA),
MonoTouch.CoreVideo.CVPixelBuffer.PixelFormatTypeKey);
SetNativeField is something completely different (you're setting the field named CVPixelBuffer.PixelFormatTypeKey to 0x754b9d0, not adding a key/value pair to the dictionary).
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; - Had to hardcode constant as it is not defined in Monotouch?
You should be able to replace this with:
CVPixelFormatType.CV32BGRA
Note that MonoTouch defines this value as 0x42475241 which differs from yours. That could be your error. If not I suggest you to make a small, self contained, test case and attach it to a bug report on http://bugzilla.xamarin.com and we'll have a look at it.
A link to the objective-c sample, if available, would be helpful too (here to an update to your question or on the bug report).
Related
I'm using AdvancedSharpAdbClient, and I'm trying to take a screenshot of the device's screen and have it return to the program as an image, but for whatever reason it errors, even those I'm using the same as used in the documentation here:
private static AdbClient client = new AdbClient();
public Bitmap Screenshot()
{
Image i = client.GetFrameBufferAsync(device, CancellationToken.None).GetAwaiter().GetResult();
return (Bitmap)i;
}
I get the below error when I call this method:
System.ArgumentException( The buffer is not associated with this pool and may not be returned to it. (Parameter 'array') )
The issue is known and someone already provided a fix, check these links:
https://github.com/yungd1plomat/AdvancedSharpAdbClient/issues/29
https://github.com/yungd1plomat/AdvancedSharpAdbClient/pull/35
Here is a link to the fixed version: https://github.com/ilamp/AdvancedSharpAdbClient
The error didn't happen for me anymore when I used this version. Good luck!
I am using Hashids to hide database IDs in the URL. Following is my initialization of Hashids:
public static Security.Hashids HashOps = new Security.Hashids("Sl212", 5);
Security is my project's namespace inside which I copied Hashids.cs file. The encoding is working correctly but decoding is throwing IndexOutOfRangeException exception. This is how I am decoding:
int fileID=HashOps.Decode(FileID)[0];
I tried it on many salts and without salt, but its throwing the same exception again and again. I am using the original code from the file. Except namespace I changed nothing.
Please tell me what to do? After trying for 12 hours my mind is stuck at dead end.
UPDATE
A test code I am running in Console app also throwing exception:
Hashids HashOps = new Hashids();
string hash = HashOps.Encode(212);
Console.WriteLine("Encoded: " + hash);
Console.WriteLine("Decoded: " + HashOps.Decode(hash)[0]);
Finally, with the help of #Heinzi I was able to detect what was really going on. The problem was with my web application's URL detection system. Which detects the URL and loads the content in a DIV. That system was making the complete URL lower cased. Hence, changing the hash containing the capital letter. I just used the actual URL instead of lowered one when detecting IDs.
I've been working with OpenCV before for C++ work and It was working great. Now, I'm developing a C# project and using EMGU CV for gender recognition. I've got problem with predict function. Every time I ran it, program crashed on Predict function, when I erased predict line, it is running. Here's my code:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
FaceRecognizer face = new FisherFaceRecognizer(0, 3500);
face.Load("colorFisherFaceModel.yml");
Image<Bgr, Byte> img1 = new Image<Bgr, Byte>("C:\\Users\\sguthesis\\Pictures\\me.jpg");
cascade = new CascadeClassifier("C:\\Users\\sguthesis\\documents\\visual studio 2013\\Projects\\EmguCV FFR with Image\\EmguCV FFR with Image\\haarcascade_frontalface_alt_tree.xml");
FaceRecognizer.PredictionResult predictedLabel = face.Predict(img1);
}
Also, I want to get an output, 1 or 2. 1 for male and 2 for female. I have trained many data that saved on colorFisherFaceModel.yml. It was run well on OpenCV. But I don't know how to use it in EMGU CV.
I'm also working on EmguCV, so I guess I can point few things here,
So first thing is you load "yml" file, Is this file you saved after recognizer is trained or you obtained from somewhere. Because my understanding is first you have to train your Recognizer, what is the structure of the yml file. Why do you load the cascade, where are you going to use it? (normally this is used to detect the face)
If you're saying that program crashed most probably because there are no items in the trained set. (in this case i guess it would be yml file) or as what I've read you need minimum of two faces in training set in order to use Fisher recognizer.
this happens because the FaceRecognizer wants to be trained before the Predict method can be called.
You can even load an existing xml Training file by the face.Load(yourTrainingFile.xml) method or by face.Train(yourImages.ToArray, imageIds.ToArray()) method.
Place your FaceRecognizer.PredictionResult predictedLabel = face.Predict(img1); code part within a trycatch block the the debugger wont close and you will catch the error message.
PS : if the number of pictures have been changed since the last Training.xml file has been created, then it's recommended to call the face.Train method instead of face.Load method!
I am not an experienced programmer, just need to add a DICOM viewer to my VS2010 project. I can display the image in Windows Forms, however can't figure out how to change the window center and width. Here is my script:
DicomImage image = new DicomImage(_filename);
int maxV = image.NumberOfFrames;
sbSlice.Maximum = maxV - 1;
image.WindowCenter = 7.0;
double wc = image.WindowCenter;
double ww = image.WindowWidth;
Image result = image.RenderImage(0);
DisplayImage(result);
It did not work. I don't know if this is the right approach.
The DicomImage class was not created with the intention of it being used to implement an image viewer. It was created to render preview images in the DICOM Dump utility and to test the image compression/decompression codecs. Maybe it was a mistake to include it in the library at all?
It is difficult for me to find fault in the code as being buggy when it is being used for something far beyond its intended functionality.
That said, I have taken some time to modify the code so that the WindowCenter/WindowWidth properties apply to the rendered image. You can find these modifications in the Git repo.
var img = new DicomImage(fileName);
img.WindowCenter = 2048.0;
img.WindowWidth = 4096.0;
DisplayImage(img.RenderImage(0));
I looked at the code and it looked extremely buggy. https://github.com/rcd/fo-dicom/blob/master/DICOM/Imaging/DicomImage.cs
In the current buggy implementation setting the WindowCenter or WindowWidth properties has no effect unless Dataset.Get(DicomTag.PhotometricInterpretation) is either Monochrome1 or Monochrome2 during Load(). This is already ridiculous, but it still cannot be used because the _renderOptions variable is only set in a single place and is immediately used for the _pipeline creation (not giving you chance to change it using the WindowCenter property). Your only chance is the grayscale _renderOptions initialization: _renderOptions = GrayscaleRenderOptions.FromDataset(Dataset);.
The current solution: Your dataset should have
DicomTag.WindowCenter set appropriately
DicomTag.WindowWidth != 0.0
DicomTag.PhotometricInterpretation == Monochrome1 or Monochrome2
The following code accomplishes that:
DicomDataset dataset = DicomFile.Open(fileName).Dataset;
//dataset.Set(DicomTag.WindowWidth, 200.0); //the WindowWidth must be non-zero
dataset.Add(DicomTag.WindowCenter, "100.0");
//dataset.Add(DicomTag.PhotometricInterpretation, "MONOCHROME1"); //ValueRepresentations tag is broken
dataset.Add(new DicomCodeString(DicomTag.PhotometricInterpretation, "MONOCHROME1"));
DicomImage image = new DicomImage(dataset);
image.RenderImage();
The best solution: Wait while this buggy library is fixed.
UPDATE2: I got it working completely now! Scroll way down to find out how...
UPDATE: I got it working! Well... partially. Scroll down for the answer...
I'm trying to get my FO file to show an external image upon transforming it to PDF (or RTF for that matter, but I'm not sure whether RTFs are even capable of displaying images (they are)) with FOP, but I can't seem to get it working. (The question asked here is different than mine.)
I am using IKVM 0.46.0.1 and have compiled a FOP 1.0 dll to put in .NET; this code worked fine when I didn't try to add images:
private void convertFoByMimetype(java.io.File fo, java.io.File outfile, string mimetype)
{
OutputStream output = null;
try
{
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired
// Setup outputput stream. Note: Using BufferedOutputStream
// for performance reasons (helpful with FileOutputStreams).
output = new FileOutputStream(outfile);
output = new BufferedOutputStream(output);
// Construct fop with desired output format
Fop fop = fopFactory.newFop(mimetype, foUserAgent, output);
// Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(fo);
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
}
catch (Exception ex)
...
}
However, when I (or rather a DocBook2FO transformation) added the following code:
<fo:external-graphic src="url(images/interface.png)" width="auto" height="auto" content-width="auto" content-height="auto" content-type="content-type:image/png"></fo:external-graphic>
into the FO file, the image did not show. I read through a bit of the FAQ on Apache's site, which says:
3.3. Why is my graphic not rendered?
Most commonly, the external file is not being found by FOP. Check the
following:
Empty or wrong baseDir setting.
Spelling errors in the file name (including using the wrong case).
...
Other options did not seem to be my case (mainly for the reason below - "The Weird Part"). I tried this:
...
try
{
fopFactory.setBaseURL(fo.getParent());
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
foUserAgent.setBaseURL(fo.getParent());
FOURIResolver fourir = fopFactory.getFOURIResolver();
foUserAgent.setURIResolver(fourir);
// configure foUserAgent as desired
...
with no avail.
The Weird Part
When I use the command-line implementation of FOP, it works fine and displays my image with no problem. (I don't want to go the run-command-line-from-program route, because I don't want to force the users to install Java AND the .NET framework when they want to use my program.)
The png file is generated from GDI+ from within my application (using Bitmap.Save). I also tried different png files, but none of them worked for me.
Is there anything I might be missing?
Thanks a bunch for getting this far
UPDATE and possible answer
So I might have figured out why it didn't work. I put some time into studying the code (before I basically just copypasted it without thinking about it much). The problem is indeed in the wrong basedir setting.
The key is in this chunk of code:
// Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(fo);
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
What happens here is an identity transformation, which routes its own result into an instance of FOP I've created before. This effectively changes the basedir of the routed FO into that of the application's executable. I have yet to figure out how to do this without a transformation and route my input directly into FOP, but for the moment I worked around this by copying my images into the executable's directory.
Which is where another problem came in. Now whenever I try to execute the code, I get an exception at the line that says transformer.transform(src, res);, which confuses the pants out of me, because it doesn't say anything. The ExceptionHelper says:
java.lang.ExceptionInInitializerError was caught
and there is no inner exception or exception message. I know this is hard to debug just from what I wrote, but I'm hoping there might be an easy fix.
Also, this e-mail seems vaguely related but there is no answer to it.
UPDATE2
Finally, after a few sleepless nights, I managed to get it working with one of the simplest ways possible.
I updated IKVM, compiled fop with the new version and replaced the IKVM references with the new dlls. The error no longer occurs and my image renders fine.
I hope this helps someone someday
I'm using very similar code, although without the FOUserAgent, Resolvers, etc. and it works perfectly.
Did you try setting the src attribute in the XSLT without the url() function?
What might help you diagnose the problem further are the following statements:
java.lang.System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog")
java.lang.System.setErr(New java.io.PrintStream(New TraceStream(TraceStream.Level.Error)))
java.lang.System.setOut(New java.io.PrintStream(New TraceStream(TraceStream.Level.Info)))
Where TraceStream is a .NET implementation of a java.io.OutputStream which writes to your favorite logger.
I posted a version for the Common.Logging package at http://pastebin.com/XH1Wg7jn.
Here's a post not to leave the question unanswered, see "Update 1" and "Update 2" in the original post for the solution.