how to stream the image using c# wpf application - c#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Web;
using System.IO;
namespace WpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public MainWindow(Stream stream)
{
InitializeComponent();
String path = #"C:\Users\Public\Pictures\Sample Pictures\Jellyfish.jpg";
var image = new BitmapImage();
try
{
image.BeginInit();
image.StreamSource = stream;
image.EndInit();
using (Stream bmpStream = System.IO.File.Open(path,System.IO.FileMode.Open))
{
Image im = Image.FromStream(bmpStream);
//Bitmap img = (Bitmap)Image.FromFile("aa.gif", true);
//var im = ImageFromStream(bmpStream);
grid1.Background = new ImageBrush(new BitmapImage(new Uri(#"im")));
}
// return image;
}
catch (Exception a)
{
// return image;
}
}
public void Window_Loaded(object sender, RoutedEventArgs e)
{
}
}
}
I am using the above code to stream the jpg image as bitmap, and set it into a grid using c#, but Image im = Image.FromStream(bmpStream); shows an error. Can someone please guide me in how to stream the jpg image as bitmap and set into grid?

The way WPF handles and displays images is a bit different from the way WinForms did this.
Most image-displaying "things" need a ImageSource and you have to search for the right one to use.
In this case you should be able to use the BitmapImage - but the last time I checked this one needs some more care to display the content of a byte-stream correctly.
This snippet shows how you should be able to get this working right BitmapImage:
private static BitmapImage LoadImage(Stream stream)
{
// assumes that the streams position is at the beginning
// for example if you use a memory stream you might need to point it to 0 first
var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.StreamSource = stream;
image.EndInit();
image.Freeze();
return image;
}
As you can see you need to tell the image to use the stream as soon as it loads (or you can get nasty things like ObjectDisposedExceptions.
You can use the returned object as your Image's source property.
So I think what you are looking for is something like this:
public MainWindow(Stream stream)
{
InitializeComponent();
grid1.Background = new ImageBrush(LoadImage(stream));
}

Related

How to solve the issue of JPEG live stream lagging?

I have written C# code of live streaming of IP camera (JPEG) in windows form application using AForge library. It is working but it's lagging too much.
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AForge.Video;
namespace CCTV_software
{
public partial class Form1 : Form
{
JPEGStream stream;
JPEGStream stream1;
public Form1()
{
InitializeComponent();
stream = new JPEGStream("ip");
stream1 = new JPEGStream("ip1");
stream.Login = "username";
stream.Password = "password";
stream1.Login = "username1";
stream1.Password = "password1";
stream.NewFrame += stream_NewFrame;
stream1.NewFrame += stream1_NewFrame1;
stream.Start();
stream1.Start();
}
void stream_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap bmp = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = bmp;
}
void stream1_NewFrame1(object sender, NewFrameEventArgs eventArgs)
{
Bitmap bp = (Bitmap)eventArgs.Frame.Clone();
pictureBox2.Image = bp;
}
}
Tried adding:
stream.FrameInterval = 0;
But it didn’t made any difference.
Kindly help me out with this issue.
Edit:
Edit 2:
#mjwills and my suggestions combined:
void stream_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
var oldImage = pictureBox1.Image
pictureBox1.Image = eventArgs.Frame; // set to new image without making a copy
oldImage?.Dispose(); // = Dispose previous image, if not null
}
This spares you a clone which is expensive and allows the gc to clean up the images timely.
Those measures combined should make it possible to improve throughput (i.e. lessen "lag"). Further countermeasures could be to make the image size smaller or reduce quality ...
NOTE: Above measures should at least improve lag, yet it is not guaranteed to make it disappear completely, since lag may be caused at other places, too.

Why do I have a compiler error (CS1503) in this Ozeki file?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Ozeki.Camera;
using Ozeki.Media;
using Ozeki;
using System.Windows.Media;
namespace BasicCameraViewer
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private VideoViewerWPF _videoViewerWPF;
private BitmapSourceProvider _provider;
private IIPCamera _ipCamera;
private WebCamera _webCamera;
private MediaConnector _connector;
public MainWindow()
{
InitializeComponent();
_connector = new MediaConnector();
_provider = new BitmapSourceProvider();
SetVideoViewer();
}
private void SetVideoViewer()
{
_videoViewerWPF = new VideoViewerWPF
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Background= Brushes.Black
};
CameraBox.Children.Add(_videoViewerWPF);
_videoViewerWPF.SetImageProvider(_provider);
}
#region IP Camera Connect/Disconnect
private void ConnectIPCamera_Click(object sender, RoutedEventArgs e)
{
var host = HostTextBox.Text;
var user = userTextBox.Text;
var pass = Password.Password;
_ipCamera = IPCameraFactory.GetCamera(host, user, pass);
if (_ipCamera == null) return;
_connector.Connect(_ipCamera.VideoChannel, _provider);
_ipCamera.Start();
_videoViewerWPF.Start();
}
private void DiconnectIPCamera_Click(object sender, RoutedEventArgs e)
{
_videoViewerWPF.Stop();
_ipCamera.Disconnect();
_ipCamera.Dispose();
_connector.Disconnect(_ipCamera.VideoChannel, _provider);
}
#endregion
}
}
Can somebody tell me what I could do? It tells me that i can not convert the _videoViewerWPF.SetImageProvider(_provider) line from Ozeki.Media.BitmapSourceProvider to Ozeki.Media.IImageProvider and i have absolutely no idea what to do that it could work.
I tried several times to do something, but I dont even know what I´m doing.
I would be thankfull if somebody could help me so I can finish this.
I came across the same issue after following the Ozeki video C# camera tutorial #3 - Camera viewer on YouTube.
It may be that the API has moved on since that video because sample code on the Ozeki Website (How to connect to an RTSP camera and display the picture in C#) uses a DrawingImageProvider instead of a BitmapSourceProvider:
...
private DrawingImageProvider _provider = new DrawingImageProvider();
...
...and then (for a WPF app):
_videoViewerWpf.SetImageProvider(_provider);
In my case, this fixed the compiler error and I can now display RTSP video in a WPF app.

C# Converting Image to BLOB and Storing Result in Textbox

I am working on (what should have been) a very simple project. It needs to
(1). Allow a user to select an image file then convert this into a format that can be stored in a database as a BLOB.
(2). Output the BLOB data into a textbox.
(3). The text that is output in the box needs to be capable of being stored into a database and then successfully converted back into an image (this conversion is handled elsewhere_.
This application here is just supposed to do the initial conversion (image to BLOB) so that the user can insert the image into an SQL database. However, whenever I run the program, it 'freezes' whenever I try opening the file. What am I doing wrong? Is there a more efficient approach to accomplish what I am trying to do?
Thanks much!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Forms;
using System.IO;
namespace Binary_Converter
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private OpenFileDialog imageDialog = new OpenFileDialog();
private FileStream imageStream;
public MainWindow()
{
InitializeComponent();
imageDialog.InitialDirectory = "c://";
imageDialog.Filter = "Image Files | *.jpg; *.gif; *.png";
imageDialog.FileOk += imageDialog_FileOk;
}
private void UI_Loaded(object sender, RoutedEventArgs e)
{}
void imageDialog_FileOk(object sender, System.ComponentModel.CancelEventArgs e)
{
if((imageStream = (FileStream)imageDialog.OpenFile()) != null) {
byte[] buffer;
using(imageStream) {
buffer = new byte[imageStream.Length];
imageStream.Read(buffer, 0, (int)imageStream.Length);
}
foreach(byte i in buffer) {
outputText.Text += buffer[i];
}
}
}
private void addFileButton_Click(object sender, RoutedEventArgs e)
{
imageDialog.ShowDialog();
}
}
}
I think that your program freezes because you haven't converted the values to hexadecimal format. You are trying to output raw byte values, and it will "harm" your textbox as it will interpret it as a string with control characters. Hexadecimal format will be needed if you want to insert the value into the database.
foreach(byte i in buffer) {
outputText.Text += buffer[i];
}
outputText.Text = "0x"; // begin the string with 0x to tell that it is hexadecimal
foreach(byte i in buffer) {
outputText.Text += buffer[i].ToString("x2"); // convert each byte to hexadecimal form
}
You don't need to pass it to a textbox and then save it to the database.
If you have an Image or Blob column you save the byte[] directly.
This article (http://www.codeproject.com/Articles/33310/C-Save-and-Load-Image-from-Database) has more information about this.

WPF/C# Updating (and disposing of) Bitmap/BitmapSource in ValueChanged event?

I have a small image editing program that opens an image and does fancy stuff to it. In this case, I'm trying to adjust the brightness of the pixels. The problem isn't getting the pixels right, its disposing the Bitmap/BitmapSources being created in the ValueChanged event for my slider.
So basically the user will click a button and it will open up a new window with a slider. This new window makes a copy of the original bitmap for later use.
When the slider's value changes, it will create a new Bitmap from the original with the corresponding brightness increase, create a new BitmapSource from this, and update the image control's source. Even though I'm using a 'using' statement, I still get an "out of memory" exception after sliding for so long.
Any idea why this is? Is there a better workaround that can achieve the same thing? I have included the code below:
using Imagin.Slideshow;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace Imagin
{
/// <summary>
/// Interaction logic for BrightnessWindow.xaml
/// </summary>
public partial class BrightnessWindow : Window
{
public int Increase;
private System.Drawing.Bitmap Bitmap;
private System.Drawing.Bitmap NewBitmap;
private MainWindow ParentWindow;
public BrightnessWindow(MainWindow m)
{
InitializeComponent();
this.ParentWindow = m;
this.Bitmap = (System.Drawing.Bitmap)this.ParentWindow.Document.Bitmap.Clone();
}
private void slider1_ValueChanged(object sender, RoutedEventArgs e)
{
using (System.Drawing.Bitmap b = (System.Drawing.Bitmap)this.ParentWindow.Document.Bitmap.Clone(new RectangleF() { Width = (int)this.ParentWindow.Document.Bitmap.Width, Height = (int)this.ParentWindow.Document.Bitmap.Height, X = 0, Y = 0 }, this.ParentWindow.Document.Bitmap.PixelFormat))
{
this.ParentWindow.SetPixels(b, AdjustmentTypes.Brightness, Convert.ToInt32(this.slider1.Value));
BitmapSource m = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(b.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
this.ParentWindow.image1.Source = m;
this.NewBitmap = (System.Drawing.Bitmap)b.Clone();
}
}
private void applyButton_Click(object sender, RoutedEventArgs e)
{
if (this.NewBitmap != null)
{
this.ParentWindow.Document.Bitmap = this.NewBitmap;
}
this.Close();
}
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
this.ParentWindow.Document.Refresh();
this.Close();
}
}
}
Another thing I was wondering is if there is a better way to alter the MainWindow's controls without having to pass it as a parameter, or is this the preferred approach for that kind of thing? Thanks!
http://msdn.microsoft.com/en-us/library/1dz311e4%28v=vs.110%29.aspx
Every time you use bitmap.GetHbitmap you create a new instance of a gdibitmap. Per the msdn link, "You are responsible for calling the GDI DeleteObject method to free the memory used by the GDI bitmap object. For more information about GDI bitmaps, see Bitmaps in the Windows GDI documentation."
I'd pull that guy out to a variable and call deleteobject on it when you're done with it, otherwise you're just creating n gdibitmaps where n = number of times you move the slider and never disposing of them.
Edit: Highlighting the line:
//Somewhere in the class
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
private void slider1_ValueChanged(object sender, RoutedEventArgs e)
{
using (System.Drawing.Bitmap b = (System.Drawing.Bitmap)this.ParentWindow.Document.Bitmap.Clone(new RectangleF() { Width = (int)this.ParentWindow.Document.Bitmap.Width, Height = (int)this.ParentWindow.Document.Bitmap.Height, X = 0, Y = 0 }, this.ParentWindow.Document.Bitmap.PixelFormat))
{
this.ParentWindow.SetPixels(b, AdjustmentTypes.Brightness, Convert.ToInt32(this.slider1.Value));
IntPtr hbitmap = b.GetHbitmap(); //create variable so we don't orphan the object
BitmapSource m = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); //use variable
this.ParentWindow.image1.Source = m;
this.NewBitmap = (System.Drawing.Bitmap)b.Clone();
DeleteObject(hbitmap); //delete gdi object
}
}

Capturing an image with Emgu - black image

I'm a newbie in emgu cv and for a major project I'm trying to capture an image from a webcam and show it in an image box, but it's showing a black image.
What is wrong with the following code?
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using Emgu.Util;
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
private Capture capture;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
if (capture == null)
capture = new Capture();
Image<Bgr,Byte> img=capture.QueryFrame();
imageBox1.Image = img;
}
}
}
I think there is a minor mistake.
Use this instead:
Declare as global variable:
Capture capture = default(Capture);
Put this in load:
capture = new Capture(0);
Control.CheckForIllegalCrossThreadCalls = false;
System.Threading.Thread t = new System.Threading.Thread(grab);
t.Start();
Create a sub grab and put in,
do {
ImageBox1.Image = capture.QueryFrame();
} while (true);
Cheers
Shreyas
Call QueryFrame() twice, it works for me:
if (capture == null)
capture = new Capture();
capture.QueryFrame();
Image<Bgr,Byte> img=capture.QueryFrame().ToImage<Bgr, Byte>();
imageBox1.Image = img.Bitmap;
In my case Kaspersky AntiVirus was blocking the access to my webcam. After changing some security settings I was able to get emgu capture back working.

Categories

Resources