Reversed bitmap when creating AVI container - c#

I have a list of images in my program, and I am generating an AVI video from them. For that purpose I use avifilewrapper_src library that handles the creation of video.
The process of creating is:
Bitmap bitmap;
//load the first image
bitmap = (Bitmap)imageSequence[0];
//create a new AVI file
AviManager aviManager = new AviManager(paths.outputVideo, false);
//add a new video stream and one frame to the new file
VideoStream aviStream =
aviManager.AddVideoStream(true, (double)nud_picturePerSec.Value, bitmap);
if(chb_audio.Checked)
aviManager.AddAudioStream(paths.sampleAudio, 0);
int count = 0;
for (int n = 0; n < imageSequence.Count; n++) {
bitmap = (Bitmap)imageSequence[n];
aviStream.AddFrame(bitmap);
bitmap.Dispose();
count++;
}
aviManager.Close();
If I keep giving different images, it works fine. If I however, put two similar images, than the video shows second image upside down (left/right side is correct). By two similar images I mean creating second image and copying it from the first one.
I have a feeling that this is somehow related to streams, but I can't find why the images are inverted.

Well I didn't managed to find the cause of that behavior. But fliping it between each use does the correction well.
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);

Related

How can we capture and save in local disk with Aforge video?

I want to save video which capturing from webcam into local disk. I wrote code it shows webcam but It can't save into local disk. The error is Failed creating compressed stream.. What should I do in here?
writer = new AVIWriter("wmv3");
writer.FrameRate = 30;
writer.Open("video.avi", Convert.ToInt32(640), Convert.ToInt32(480)); // ERROR İS HERE **Failed creating compressed stream.**
//Create NewFrame event handler
//(This one triggers every time a new frame/image is captured
videoSource.NewFrame += new AForge.Video.NewFrameEventHandler(videoSource_NewFrame);
//Start recording
videoSource.Start();
}
}
void videoSource_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
{
//Cast the frame as Bitmap object and don't forget to use ".Clone()" otherwise
//you'll probably get access violation exceptions
pictureBoxVideo.BackgroundImage = (Bitmap)eventArgs.Frame.Clone();
writer.AddFrame((Bitmap)eventArgs.Frame.Clone());
}
Have you ever consider the size of the stream of your webcam? I have the same problem, too. I know you set your video size into 640 and 480, but the video stream size which comes from your webcam(I guess) would be never the same. I also guess you set your container such as picturebox or imagebox into 640 and 480, but that doesn't mean the video stream would be the same. I use savedialog to check the video stream that comes out of my webcam, and guess what? The size would be (648, 486). Who would ever set such a strange number set? But I set my code into this :
writer.Open("video.avi", Convert.ToInt32(648), Convert.ToInt32(486));
And it works fine!
I do not know the rest of your code is correct or not, but I'm sure my bug is in the set of size :)
Four years later I'm having this same issue. After hours I figured out if I didn't specify wmv3 for the codec and just left it blank writer = new AVIWriter(); then everything worked.
AVIWriter write = new AVIWriter();
write.Open("newTestVideo.avi", Convert.ToInt32(320), Convert.ToInt32(240));
Bitmap bit = new Bitmap(320, 240);
for (int tt = 0; tt < 240; tt++) {
bit.SetPixel(tt, tt, System.Drawing.Color.FromArgb((int)(UnityEngine.Random.value * 255f), (int)(UnityEngine.Random.value * 255f), (int)(UnityEngine.Random.value * 255f)));
write.AddFrame(bit);
}
write.Close();

How can i add two animated gif's on one bitmap?

I have two animated gifs i created.
I want to add them to a new bitmap side by side so i will see both animated gifs animation.
Not as stil image but two animation side by side.
This code is in the top of form1 im using now:
public static class BitmapExtensions
{
public static Bitmap DoubleBitmap(this Bitmap bm)
{
Bitmap bitmap = new Bitmap(bm.Width * 2, bm.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(bm, Point.Empty);
g.DrawImage(bm, new Point(bm.Width, 0));
return bitmap;
}
}
public static Bitmap AppendBitmap(this Bitmap bm, Bitmap rightBitmap)
{
Bitmap bitmap = new Bitmap(bm.Width + rightBitmap.Width, Math.Max(bm.Height, rightBitmap.Height));
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(bm, Point.Empty);
g.DrawImage(rightBitmap, new Point(bm.Width, 0));
return bitmap;
}
}
}
Then i use it like this:
private void CreateNewImage(string DirOfUrls)
{
List<string> files = Directory.GetFiles(DirOfUrls, "RainImage*.*").ToList();
List<string> files1 = Directory.GetFiles(DirOfUrls, "SatelliteImage*.*").ToList();
Bitmap bmp = new Bitmap(#"d:\localpath\RainMapGif");//files1[i]);
Bitmap bmp1 = new Bitmap(#"d:\localpath\SatelliteMapGif");//files[i]);
//Use it
//Double the same image
Bitmap doubledBitmap = bmp1.DoubleBitmap();
//Append new image
Bitmap appendedBitmap = bmp1.AppendBitmap(bmp);
appendedBitmap.Save(#"d:\localpath\newbitmapGif", System.Drawing.Imaging.ImageFormat.Gif);
}
RainMapGif and SatelliteMapGif are animated gif's.
But when i tried to do it this way i get one new bitmap with two stills images and not two animtions of the two animated gifs.
How can i add both animated gifs to one bitmap and when i open the bitmap on internet explorer for example i will see both animations moving of the two gifs side by side ?
EDIT**
This is how i used it before :
private void CreateNewImage(string DirOfUrls)
{
int newImageCounter = 0;
List<string> files = Directory.GetFiles(DirOfUrls, "RainImage*.*").ToList();
List<string> files1 = Directory.GetFiles(DirOfUrls, "SatelliteImage*.*").ToList();
for (int i = 0; i < files.Count; i++)
{
if (newImageCounter == 9)
{
CreateNewGif(DirOfUrls);
//break;
}
Bitmap bmp = new Bitmap(files1[i]);
Bitmap bmp1 = new Bitmap(files[i]);
//Use it
//Double the same image
Bitmap doubledBitmap = bmp1.DoubleBitmap();
//Append new image
Bitmap appendedBitmap = bmp1.AppendBitmap(bmp);
appendedBitmap.Save(#"d:\localpath\newbitmap" + newImageCounter.ToString("D6"), System.Drawing.Imaging.ImageFormat.Gif);
newImageCounter++;
}
So i have 9 images of both of them the RainMap images and the SatelliteMap images.
And the rest of the SatelliteMap images are singles.
Then im using CreateNewGif:
private void CreateNewGif(string urlsdirs)
{
List<string> files = Directory.GetFiles(urlsdirs, "RainImage*.*").ToList();
List<string> files1 = Directory.GetFiles(urlsdirs, "SatelliteImage*.*").ToList();
List<string> test = files;
test.RemoveRange(0, files1.Count);
List<string> newbitmap = Directory.GetFiles(localdir, "newbitmap*.*").ToList();
for (int i = 0; i < test.Count; i++)
{
newbitmap.Add(test[i]);
}
uf.MakeGIF(newbitmap, localdir + "newbitmapGif", 50, true);
}
And make new animated gif:
uf.MakeGIF(newbitmap, localdir + "newbitmapGif", 50, true);
But the new animated gif is not good since the rain images ending before the satellite images so the new animated gif show both animation and after 9 frames only one is continue.
How can i make that the one with the 9 images will keep continue animated over and over again and the second one will keep animated untill the end ?
This is the problem veljkoz wrote about before. One animation count is shorter then the other one. But how can i solve it ?
Only gif can have animation. Bitmap doesn't and never will.
Furthermore, there's the issue of extracting all of the gif slides (see this answer), putting them side by side in another gif (see this answer), and deciding what will you do if the slide count isn't a match (which would most probably be the case).
Personally, I would go with what #Mike W is suggesting in the comment...
Edit:
You have to have in mind that the resulting gif will have a single number of frames after which it repeats itself. So, both gifs you're trying to add have to somehow fit there. There's only a few options here:
Repeat inserting all frames of both gifs until they reach at the end at the same time (e.g. if one has 6 frames and the other 9 - the result will have 18 frames. The the first one would repeat itself 3 times, the other 2). This is (obviously) prolonging the length & size of the gif, which is probably not something you want, but it would give you best results. When the numbers are prime numbers you'd get the worst count - e.g. 53 & 59 frame gifs when joined will last for 3127 frames.
Change the timing of the frames so they end at the same time. This would of course speed-up / slow down parts of the gifs. (e.g. 6&9 frames gifs: the result has 9 slides - you could repeat the first 3 slides of 1st gif to last two frames - which means 1st slide will last 2 frames (#1 & #2), second one also (#3 & #4) as well as third (#5 & #6). Then copy the rest of the slides - frame 4 displayed at #7, 5->#8, 6->#9 and that's the end).
Remove some of the slides - shorten the gifs by removing some of the slides so the count matches...

gdi+ generic error when drawing image on Graphics object

Consider the following code running in a windows service.
Graphics g = Graphics.FromImage(printImage);
for (int rows = 1; rows <= thumbRows; rows++) {
for (int cols = 1; cols <= thumbColumns; cols++) {
using (Image thumbImage = new Bitmap(resourceQueue.Peek()))
{
g.DrawImage(thumbImage, targetRect, sourceRect, GraphicsUnit.Pixel);
resourceQueue.Dequeue();
if (resourceQueue.Count == 0) break;
}
}
}
The code draws a list of images after making them smaller onto another image.
It works fine most of the time but sometimes an exception is thrown in the middle of the loop on the Image thumbImage = new Bitmap. The exception is "A generic error occurred in GDI+". It always happens after the 13th image is created no matter what images are used.
After googling it seems that this a common problem when saving files but the difference here is that no file is saved. An image is drawn on a Graphics object.
Does anyone know how to fix this?
Most likely the stream used to create the Bitmap (if that is what it is) is closed. They have to stay open for the life of the Bitmap. You can copy the stream into a new MemoryStream, then close the original.

Recording RGB stream from the kinect sensor

I'm doing a WPF application and one of the functions is to record video (Only RGB stream) from Kinect sensor (using Aforge and SDK 1.5).
In my application, i have a button that when clicked, it should save the video stream into an avi file.
I've added the references and I copied all the .dll files into my projects folder (as was explained on other forums) but for some reason I receive this error:
{"Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.":null}
So inside private void button4_Click(object sender, RoutedEventArgs e) is the following code:
int width = 640;
int height = 480;
// create instance of video writer
VideoFileWriter writer = new VideoFileWriter();
// create new video file
writer.Open("test.avi", width, height, 25, VideoCodec.MPEG4);
// create a bitmap to save into the video file
Bitmap image = new Bitmap (width, height, DrawingColor.PixelFormat.Format24bppRgb);
for (int i = 0; i < 1000; i++)
{
image.SetPixel(i % width, i % height, Color.Red);
writer.WriteVideoFrame(image);
}
writer.Close();
}
I will really appreciate your help and also im flexible with the way to record RGB stream(if you recommend another way), as long a its not complicated because im new with C#
The reason the video is red is because you are turning it red with
for (int i = 0; i < 1000; i++)
{
image.SetPixel(i % width, i % height, Color.Red);
writer.WriteVideoFrame(image);
}
What you should do is convert the BitmapSource/WritableBitmap* (assuming you are displaying Kinect's data with a BitmapSource or WritableBitmap Then you can just add that bitmap to your Video frame. Hope this helps!
**If you are using a WritableBitmap, convert it to a BitmapImage, then convert that to a Bitmap*

save png image with custom quality or color depth in C# [duplicate]

I am supposed to write a program that gets some PNG images from the user, does some simple edits like rotation and saves them inside a JAR file so that it can use the images as resources. The problem is when I open, say an 80kb image and then save it with C#, I get an image with the same quality but for 130kb space. And because it has to go inside a J2ME jar file I really need lower sizes, at least the original size. I tried the code below but later found out that it only works for Jpeg images.
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
int j = 0;
for (j = 0; j < codecs.Length; j++)
{
if (codecs[j].MimeType == "image/png") break;
}
EncoderParameter ratio = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 10L);
EncoderParameters CodecParams = new EncoderParameters(1);
CodecParams.Param[0] = ratio;
Image im;
im = pictureBox1.Image;
im.Save(address , codecs[j], CodecParams);
This is where the image is loaded to a picture box:
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
string address = openFileDialog1.FileName;
address.Replace("\\", "\\\\");
Image im = Image.FromFile(address);
pictureBox1.Image = im;
}
}
And this is where it's being saved back with no edits:
private void generateToolStripMenuItem_Click(object sender, EventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
int j = 0;
for (j = 0; j < codecs.Length; j++)
{
if (codecs[j].MimeType == "image/png") break;
}
EncoderParameter ratio = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 10L);
EncoderParameters CodecParams = new EncoderParameters(1);
CodecParams.Param[0] = ratio;
string address = folderBrowserDialog1.SelectedPath;
address = address + "\\";
address.Replace("\\", "\\\\");
Image im;
im = pictureBox1.Image;
im.Save(address + imageFileNames[1], codecs[j], CodecParams);
Note: imageFileNames[] is just a string array that has some of the the file names to which the images must be saved with.
Any ideas will be appreciated and thanks in advance.
Sorry for bringing up an old question, but I were solving the same problem today and found this page on MSDN: "Listing Parameters and Values for All Encoders". I hope it might be useful to refer to it there.
The article contains a sample program which outputs EncoderParameters supported by stock GDI+ image encoders, and PNG encoder supports no parameters according to it.
I'm not sure thought if one can take this for granted, or in some future version of gdiplus.dll the PNG encoder might grow more support, and so one is supposed to check the encoder's capabilities at runtime.
In any case applying some explicit transformation on a source image appears to be more fruitful approach; I did not explore it yet though.
I have taken 4 different PNGs, ranging in sizes from 2KB to 2.6MB. Using your code, I load them up and save them out. I do not modify the image by rotating or flipping. All 4 PNGs, when re-saved, have exactly the same size.
In addition, I have taken the 2.6MB PNG, opened it in Photoshop and saved two copies of it, one interlaced (reduced to 2.06MB), one non-interlaced (reduced to 1.7MB.) I then took each of those, ran them through your code and saved them. The resulting sizes of both were back to the original 2.6MB.
So, my guess is that the original images were created with a piece of software (like photoshop) and that piece of software has an optimized compression algorithm it is using for the PNG spec that .NET does not employ.
I've messed around with the EncoderParameter for Compression, but it seems to have no impact.

Categories

Resources