I'm using this method to display in pictureBox1 animated gif i created.
The animated gif is already have it's own speed. For example 1 frame per second or i can set it to 1 frame each ms.
public void pictureBoxImage(string pbImage)
{
Image img2 = null;
try
{
using (img = Image.FromFile(pbImage))
{
Image i = this.pictureBox1.Image;
this.pictureBox1.Image = null;
if (i != null)
i.Dispose();
MemoryStream m = _memSt;
_memSt = new MemoryStream();
img.Save(_memSt, System.Drawing.Imaging.ImageFormat.Gif);
if (m != null)
m.Dispose();
img2 = Image.FromStream(_memSt);
}
if (img2 != null)
pictureBox1.Image = img2;
label2.Text = numberOfFiles.ToString();
label6.Text = nameOfStartFile.ToString();
label4.Text = nameOfEndFile.ToString();
}
catch (Exception err)
{
Logger.Write("Animation Error >>> " + err);
}
}
For example pbImage contain:
C:\previewDirectory\preview.gif
My question is that if there is any way to change the MemoryStream variable speed maybe so it will display the animated gif in a different speed ? Or if the animated speed file gif on my hard disk saved as speed of 1ms for example so that is the speed and can't be changed ?
I want to in pictureBox1 using hScrollBar to change the speed of the animated gif that is displayed in the pictureBox1.
You are confusing things. The animation speed is defined in the GIF file itself. I.e. a display time for each frame is defined. This has absolutely nothing to do with MemoryStreams or the speed of MemoryStreams.
If you want to change the animation speed, change it in the GIF-file by using a graphics or animation application capabale of doing it.
You can do it here: http://ezgif.com/speed
Related
I use Accord.Video.FFMPEG to extract images every 10 frames from a video. Total frames for this video is 38194 frames. First run is good, I can save image every 10 frames but after run of about 38185 frames i got null return from this code Bitmap bmpBaseOriginal = vReader.ReadVideoFrame();, if I see in the video there is no problem at the end of video.
I do something like this
using (var vReader = new VideoFileReader())
{
vReader.Open(files[0]);
TotalFrame = vReader.FrameCount;
countin = Convert.ToInt32(TotalFrame / Convert.ToDouble(countAsset));
Fps = vReader.FrameRate.Value;
int a = 0;
for (int i = 0; i < vReader.FrameCount; i++)
{
if(i < vReader.FrameCount - 1)
{
Bitmap bmpBaseOriginal = vReader.ReadVideoFrame();
if (i%10 == 0)
{
a++;
bmpBaseOriginal.Save(string.Format("{0}\\{1}.jpeg", dirVideo.FullName, a), ImageFormat.Jpeg);
}
bmpBaseOriginal.Dispose();
}
else
{
a++;
Bitmap bmpBaseOriginal = vReader.ReadVideoFrame();
bmpBaseOriginal.Save(string.Format("{0}\\{1}.jpeg", dirVideo.FullName, a), ImageFormat.Jpeg);
bmpBaseOriginal.Dispose();
}
}
vReader.Close();
}
this problem occurs again on another video if the video has a lot of frames, but no problem if the video has a less frames.
How to solve it?
I am importing a picture into my application and rotating the image according to the EXIF metadata. After this I am saving the rotated image to my disk, but as I have still left the rotated image metadata on the image and windows thinks it should rotate it again... basically meaning my image ends up upside down.
So far I have got:
using (Stream sourceStream = File.Open(dlg.FileName, FileMode.Open, FileAccess.Read))
{
BitmapDecoder sourceDecoder = BitmapDecoder.Create(sourceStream, createOptions, BitmapCacheOption.OnLoad);
// Check source is has valid frames
if (sourceDecoder.Frames[0] != null && sourceDecoder.Frames[0].Metadata != null)
{
sourceDecoder.Frames[0].Metadata.Freeze();
// Get a clone copy of the metadata
BitmapMetadata sourceMetadata = sourceDecoder.Frames[0].Metadata.Clone() as BitmapMetadata;
ImportedPhotoMetaData = sourceMetadata;
}
}
and
using (var image = Image.FromFile(dlg.FileName))
{
foreach (var prop in image.PropertyItems)
{
if (prop.Id == 0x112)
{
if (prop.Value[0] == 6)
rotate = 90;
if (prop.Value[0] == 8)
rotate = -90;
if (prop.Value[0] == 3)
rotate = 180;
prop.Value[0] = 1;
}
}
}
but the prop.Value[0] = 1; line does not seem to reset the image metadata. I need to reset the image orientation on the ImportedPhotoMetaData property
Got it...
Replace
prop.Value[0] = 1;
with
ImportedPhotoMetaData.SetQuery("System.Photo.Orientation", 1);
I'm having issues opening multiple image files from the users desktop and then converting those images to a scaled down size which then gets displayed on the UI (after all the converting is done). I can't find what the issue is exactly but what I've observed is that there seems to be a 5 second limit between hitting the "Open" button on the "OpenFileDialog" box control and how much time I have to read those File(s). I've used 6 files ranging in size of 9-11MB, and in another case I've used 50 1-2MB files and in all cases the process will read up until 5 seconds have expired. It never fails on the same image either so the image isn't causing the issue which would further make me believe its not a file count issue. If I test this process with only a few small sized files it happens under 1 second and there is not failure and I see all images on the UI. That is why I'm guessing its a timing issue. I know silverlight has a security exception between when the user interacts with a control (button) and how much time can elapse before displaying the "OpenFileDialog" box but this time limit seems to be different but I can't find any documentation.
Here is the code I'm using. It seems to be a pretty common recipe used everywhere but posting for completeness. The error happens on the line
var bitmap = new WriteableBitmap(bitmapImage);
The reason it fails is because the bitmapImage pixelWidth/Height == 0. Here is the full code.
private const int MaxPixelSize = 500;
public byte[] Convert(FileInfo fileInfo, FileTypes fileType, DateTime startTime)
{
byte[] result = null;
using (var stream = fileInfo.OpenRead())
{
DateTime EndTime = DateTime.Now;
if (fileType == FileTypes.JPG || fileType == FileTypes.BMP || fileType == FileTypes.PNG)
{
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
double scaleX = 1;
double scaleY = 1;
if (bitmapImage.PixelWidth > MaxPixelSize)
{
scaleX = MaxPixelSize / (double)bitmapImage.PixelWidth;
}
if (bitmapImage.PixelHeight > MaxPixelSize)
{
scaleY = MaxPixelSize / (double)bitmapImage.PixelHeight;
}
var scale = Math.Min(scaleX, scaleY);
var bitmap = new WriteableBitmap(bitmapImage);
var resizedBitmap = bitmap.Resize((int)((double)bitmapImage.PixelWidth * scale), (int)((double)bitmapImage.PixelHeight * scale), WriteableBitmapExtensions.Interpolation.Bilinear);
using (var scaleStream = new MemoryStream())
{
var encoder = new JpegEncoder();
var image = resizedBitmap.ToImage();
encoder.Encode(image, scaleStream);
result = scaleStream.GetBuffer();
}
}
else
{
result = new byte[stream.Length];
stream.Read(result, 0, (int)stream.Length);
}
}
return result;
}
Any help or suggestions are welcomed.
Thanks,
Dean
if bitmapImage.ImageOpened event is executed, you can get valid pixelWidth and height.
when bitmapImage.SetSource(stream) is excuted, this event will be invoked.
I have a Kinect WPF Application that takes images from the Kinect, does some feature detection using EmguCV (A C# opencv wrapper) and displays the output on the using a WPF image.
I have had this working before, but the application now refuses to update the screen image when the imagesource is written to, but I have not changed the way it works.
the Image(called video) is written to as such:
video.Source = bitmapsource;
in the colorframeready event handler.
This works fine until I introduce some opencv code before the imagesource is written to. It does not matter what source is used, so I don't think it is a conflict there. I have narrowed down the offending EmguCV code to this line:
RecentKeyPoints = surfCPU.DetectKeyPointsRaw(ImageRecent, null);
which jumps straight into the opencv code. It is worth noting that:
ImageRecent has completely different origins to the bitmapsource updating the screen.
Reading video.Source returns the bitmapsource, so it seems to be writing correctly, just not updating the screen.
Let me know if you want any more information...
void nui_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
// Checks for a recent Depth Image
if (!TrackingReady) return;
// Stores image
using (ColorImageFrame colorImageFrame = e.OpenColorImageFrame())
{
if (colorImageFrame != null)
{
if (FeatureTracker.ColourImageRecent == null)
//allocate the first time
FeatureTracker.ColourImageRecent = new byte[colorImageFrame.PixelDataLength];
colorImageFrame.CopyPixelDataTo(FeatureTracker.ColourImageRecent);
}
else return;
}
FeatureTracker.FeatureDetect(nui);
//video.Source = FeatureTracker.ColourImageRecent.ToBitmapSource();
video.Source = ((Bitmap)Bitmap.FromFile("test1.png")).ToBitmapSource();
TrackingReady = false;
}
public Bitmap FeatureDetect(KinectSensor nui)
{
byte[] ColourClone = new byte[ColourImageRecent.Length];
Array.Copy(ColourImageRecent, ColourClone, ColourImageRecent.Length);
Bitmap test = (Bitmap)Bitmap.FromFile("test1.png");
test.RotateFlip(RotateFlipType.RotateNoneFlipY);
Image<Gray, Byte> ImageRecent = new Image<Gray, byte>(test);
SURFDetector surfCPU = new SURFDetector(2000, false);
VectorOfKeyPoint RecentKeyPoints;
Matrix<int> indices;
Matrix<float> dist;
Matrix<byte> mask;
bool MatchFailed = false;
// extract SURF features from the object image
RecentKeyPoints = surfCPU.DetectKeyPointsRaw(ImageRecent, null);
//Matrix<float> RecentDescriptors = surfCPU.ComputeDescriptorsRaw(ImageRecent, null, RecentKeyPoints);
//MKeyPoint[] RecentPoints = RecentKeyPoints.ToArray();
// don't feature detect on first attempt, just store image details for next attempt
#region
/*
if (KeyPointsOld == null)
{
KeyPointsOld = RecentKeyPoints;
PointsOld = RecentPoints;
DescriptorsOld = RecentDescriptors;
return ImageRecent.ToBitmap();
}
*/
#endregion
// Attempt to match points to their nearest neighbour
#region
/*
BruteForceMatcher SURFmatcher = new BruteForceMatcher(BruteForceMatcher.DistanceType.L2F32);
SURFmatcher.Add(RecentDescriptors);
int k = 5;
indices = new Matrix<int>(DescriptorsOld.Rows, k);
dist = new Matrix<float>(DescriptorsOld.Rows, k);
*/
// Match features, provide the top k matches
//SURFmatcher.KnnMatch(DescriptorsOld, indices, dist, k, null);
// Create mask and set to allow all features
//mask = new Matrix<byte>(dist.Rows, 1);
//mask.SetValue(255);
#endregion
//Features2DTracker.VoteForUniqueness(dist, 0.8, mask);
// Check number of good maches and for error and end matching if true
#region
//int nonZeroCount = CvInvoke.cvCountNonZero(mask);
//if (nonZeroCount < 5) MatchFailed = true;
/*
try
{
nonZeroCount = Features2DTracker.VoteForSizeAndOrientation(RecentKeyPoints, KeyPointsOld, indices, mask, 1.5, 20);
}
catch (SystemException)
{
MatchFailed = true;
}
if (nonZeroCount < 5) MatchFailed = true;
if (MatchFailed)
{
return ImageRecent.ToBitmap();
}
*/
#endregion
//DepthMapColourCoordsRecent = CreateDepthMap(nui, DepthImageRecent);
//PointDist[] FeatureDistances = DistanceToFeature(indices, mask, RecentPoints);
//Image<Rgb,Byte> rgbimage = ImageRecent.Convert<Rgb, Byte>();
//rgbimage = DrawPoints(FeatureDistances, rgbimage);
// Store recent image data for next feature detect.
//KeyPointsOld = RecentKeyPoints;
//PointsOld = RecentPoints;
//DescriptorsOld = RecentDescriptors;
//CreateDepthMap(nui, iva);
//rgbimage = CreateDepthImage(DepthMapColourCoordsRecent, rgbimage);
// Convert image back to a bitmap
count++;
//Bitmap bitmap3 = rgbimage.ToBitmap();
//bitmapstore = bitmap3;
//bitmap3.Save("test" + count.ToString() + ".png");
return null;
}
This is a little late, but I had a similar problem and thought I'd share my solution.
In my case I was processing the depth stream. The default resolution was 640x480, and Emgu just wasn't able to process the image fast enough to keep up with the frameready handler. As soon as I reduced the depth stream resolution to 320x240 the problem went away.
I also went a bit further and moved my image processing to a different thread which sped it up even more (do a search for ComponentDispatcher.ThreadIdle). I'm still not able to do 640x480 at a reasonable frame rate, but at least the image renders so I can see what's going on.
I've been playing around with NGif Animator for resizing animated gifs and it does resize but parts in many animated gifs I've tried get erased. I looked through the comments on that page and didn't see anyone else mention it.
To eliminate resizing as the cause I simply loop through the frames and save each one. Each frame is a System.Drawing.Image. Transparency is set to none (Color.Empty).
This is my test method currently:
GifDecoder gifDecoder = new GifDecoder();
MemoryStream memoryStream = new MemoryStream();
new BinaryWriter((Stream)memoryStream).Write(imageToResize); // byte array
memoryStream.Position = 0L;
gifDecoder.Read((Stream)memoryStream);
memoryStream.Dispose();
string filename = Guid.NewGuid().ToString().Replace("-", String.Empty) + ".gif";
string output = path + #"\" + filename;
AnimatedGifEncoder animatedGifEncoder = new AnimatedGifEncoder();
animatedGifEncoder.Start(output);
animatedGifEncoder.SetRepeat(gifDecoder.GetLoopCount());
animatedGifEncoder.SetQuality(10); // They say 20 is max quality will get, I've tried higher. Makes it a little bit better but black areas instead of gray. 10 is their default.
animatedGifEncoder.SetTransparent(Color.Empty); // This is default either way
int frameCount = gifDecoder.GetFrameCount();
int num = 0;
Image frame;
Image image = null;
for (int index = frameCount; num < index; ++num)
{
frame = gifDecoder.GetFrame(num);
animatedGifEncoder.SetDelay(gifDecoder.GetDelay(num));
string fname = #"C:\Development\images\frame_" + num.ToString() + ".gif";
if (File.Exists(fname)) { File.Delete(fname); }
frame.Save(fname);
animatedGifEncoder.AddFrame(image);
}
animatedGifEncoder.Finish();
Here's an example of what's happening:
The background is gone and it's gray.
It's supposed to look like:
Anyone have experience with NGif and know what would cause this? The first frame is always fine. It's the others after that have a problem so I'm guessing something isn't being reset from frame to frame (or re-read). I've been adding more things to their reset frame method but so far it hasn't helped. That now looks like:
protected void ResetFrame()
{
lastDispose = dispose;
lastRect = new Rectangle(ix, iy, iw, ih);
lastImage = image;
lastBgColor = bgColor;
delay = 0;
transparency = false; // I don't want transparency
lct = null;
act = null;
transIndex = -1;
}
There is actually a bug in their code, a byte array not being reset. Check the comments on their page for a solution