I am using Intel Realsense RGB camera to show live stream on WPF window as well as save the stream into a file. What I am showing on window has correct colors but when I save it, the video colors are off (more purple). Please see screenshot: https://ibb.co/txy9Sgd
I am using a EmguCV video writer to save the video. I don't have much knowledge about formats. I am guessing I am doing something wrong with Format24bppRgb format?
private Pipeline pipeline = new Pipeline(); // Create and config the pipeline to strem color and depth frames.
private CancellationTokenSource tokenSource;
private VideoWriter writer = null;
public StartTests()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
tokenSource = new CancellationTokenSource();
int fcc = VideoWriter.Fourcc('M', 'P', '4', 'V'); //'M', 'J', 'P', 'G'
float fps = 15F;
writer = new VideoWriter("testttt.mp4", fcc, fps, new System.Drawing.Size(640, 480), true);
Config cfg = new Config();
cfg.EnableStream(Stream.Color, 640, 480, format: Format.Rgb8);
PipelineProfile pp = pipeline.Start(cfg);
StartRenderFrames(pp);
}
private void StartRenderFrames(PipelineProfile pp)
{
// Allocate bitmaps for rendring. Since the sample aligns the depth frames to the color frames, both of the images will have the color resolution
using (VideoStreamProfile p = pp.GetStream(Stream.Color) as VideoStreamProfile)
{
imgColor.Source = new WriteableBitmap(p.Width, p.Height, 96d, 96d, PixelFormats.Rgb24, null);
}
Action<VideoFrame> updateColor = UpdateImage(imgColor);
Task.Factory.StartNew(() =>
{
while (!tokenSource.Token.IsCancellationRequested)
{
using (FrameSet frames = pipeline.WaitForFrames()) // Wait for the next available FrameSet
{
VideoFrame colorFrame = frames.ColorFrame.DisposeWith(frames);
// Save frames to file here...
System.Drawing.Bitmap ColorImg = new System.Drawing.Bitmap(colorFrame.Width, colorFrame.Height, colorFrame.Stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, colorFrame.Data);
Image<Bgr, Byte> imageCV = new Image<Bgr, byte>(ColorImg); //Image Class from Emgu.CV
Mat matFrame = imageCV.Mat;
writer.Write(matFrame);
// Render to WPF window here...
Dispatcher.Invoke(DispatcherPriority.Render, updateColor, colorFrame);
}
}
}, tokenSource.Token);
}
static Action<VideoFrame> UpdateImage(Image img)
{
WriteableBitmap wbmp = img.Source as WriteableBitmap;
return new Action<VideoFrame>(frame =>
{
using (frame)
{
var rect = new Int32Rect(0, 0, frame.Width, frame.Height);
wbmp.WritePixels(rect, frame.Data, frame.Stride * frame.Height, frame.Stride);
}
});
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
tokenSource.Cancel();
tokenSource.Dispose();
pipeline.Stop();
writer.Dispose();
tokenSource = new CancellationTokenSource();
}
I want to see consistent colors in the saved .mp4 file but I am seeing weird colors.
Note - My code is based on this example: https://github.com/IntelRealSense/librealsense/blob/master/wrappers/csharp/cs-tutorial-2-capture/Window.xaml.cs
OpenCV assumes BGR colour format, so if you change the RealSense stream format to Format.Bgra8 and the WriteableBitmap format to PixelFormats.Bgr24, you should be alright.
So you should have:
cfg.EnableStream(Stream.Color, 640, 480, format: Format.Bgr8);
and
new WriteableBitmap(p.Width, p.Height, 96d, 96d, PixelFormats.Bgr24, null);
I don't think you'll need to change the System.Drawing.Bitmap pixelformat as you're only using it to feed the OpenCV mat.
Related
In an attempt to create a neural network program to detect handwritten digits, I first need to capture the handwritten digit on an InkCanvas. The problem is that when I save the InkCanvas as a Bitmap, the resolution is much greater than 28x28. I'm favoring 28x28 because the input layer to my neural network will have 784 nodes. The size of my input layer will skyrocket if I use the full resolution of the InkCanvas.
As it stands, I draw the handwritten digits in a 28x28 canvas within MS Paint.
I then save the image as a bmp file in my programs project folder.
From there, my program sees the bmp file and processes it accordingly.
I just need help lowering the resolution of the UWP InkCanvas.
I do not simply want to edit the width and height, but the actual pixel count/zoom.
Main Page
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
// sets initial window size
ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(1000, 800);
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
// sets supported inking device types
inkCanvas.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse;
// sets initial ink stroke attributes
InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
drawingAttributes.Color = Windows.UI.Colors.White;
drawingAttributes.Size = new Windows.Foundation.Size(2, 2);
drawingAttributes.IgnorePressure = false;
drawingAttributes.FitToCurve = true;
inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
}
private async void saveInkCanvasBitmap()
{
RenderTargetBitmap bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(grid);
var pixelBuffer = await bitmap.GetPixelsAsync();
byte[] pixels = pixelBuffer.ToArray();
var displayInformation = DisplayInformation.GetForCurrentView();
StorageFolder pictureFolder = KnownFolders.SavedPictures;
var file = await pictureFolder.CreateFileAsync("image.bmp", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)bitmap.PixelWidth,
(uint)bitmap.PixelHeight,
displayInformation.RawDpiX,
displayInformation.RawDpiY,
pixels);
await encoder.FlushAsync();
}
}
private void clearButton_Click(object sender, RoutedEventArgs e)
{
// clears the ink canvas of any pen strokes
inkCanvas.InkPresenter.StrokeContainer.Clear();
}
private void submitButton_Click(object sender, RoutedEventArgs e)
{
saveInkCanvasBitmap(); // try to lower resolution of ink canvas to 28 x 28
// other stuff
}
}
Based on the description of BitmapEncoder.SetPixelData, the parameter called dpiX and dpiY are the resolution values for the bitmap. Please try to change your code like
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)bitmap.PixelWidth,
(uint)bitmap.PixelHeight,
28,
28,
pixels);
I want to Video File thumbnail. Get Video path and convert to Image. Then convert to bmp, and save the bmp as an image file. If this is possible, please show me a way.
private void add_Video_Image(string sFullname_Path_of_Video)
{
//*create mediaplayer in memory and jump to position
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.MediaOpened += new EventHandler(mediaplayer_OpenMedia);
mediaPlayer.ScrubbingEnabled = true;
mediaPlayer.Open(new Uri(sFullname_Path_of_Video));
mediaPlayer.Position = TimeSpan.FromSeconds(0);
}
private void mediaplayer_OpenMedia(object sender, EventArgs e)
{
MediaPlayer mediaPlayer = sender as MediaPlayer;
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawVideo(mediaPlayer, new Rect(0, 0, 160, 100));
drawingContext.Close();
double dpiX = 1 / 200;
double dpiY = 1 / 200;
RenderTargetBitmap bmp = new RenderTargetBitmap(160, 100, dpiX, dpiY, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
Image newImage = new Image();
newImage.Source = bmp;
newImage.Stretch = Stretch.Uniform;
newImage.Height = 100;
//save bmp to image
}
Please check this link. It holds the answer to your question: Easiest way of saving wpf Image control to a file
You can do the save prior to setting the 'RenderTargetBitmap' to the 'Image Control'.
I am new in SharpDX and I want to simulate code to render a 24-bit bitmap image straight from memory and display to PictureBox. *This code is to be use in later project to quickly render images from memory.
I have no issue render using standard DrawImage() method. I opt for SharpDX because DrawImage is too slow.
But when I try render using SharpDX, the image become grey in color and corrupted (see image below)
The image I want to render is in 24-bit RGB bitmap.
Using DrawImage
Using SharpDX
What is wrong with my code?
Below is my code:
using System;
using System.Windows.Forms;
using SharpDX;
using SharpDX.Direct2D1;
using System.Diagnostics;
namespace bitmap_test
{
public partial class Form1 : Form
{
private System.Drawing.Bitmap image1 = null;
private System.Drawing.Imaging.BitmapData bmpdata1 = null;
//target of rendering
WindowRenderTarget target;
//factory for creating 2D elements
SharpDX.Direct2D1.Factory factory = new SharpDX.Direct2D1.Factory();
//this one is for creating DirectWrite Elements
SharpDX.DirectWrite.Factory factoryWrite = new SharpDX.DirectWrite.Factory();
private SharpDX.DXGI.Format bmp_format = SharpDX.DXGI.Format.B8G8R8A8_UNorm;
private AlphaMode bmp_alphamode = AlphaMode.Ignore;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
InitSharpDX();
//load 24-bit depth bitmap
LoadBitmapFromFile(#"D:\lena.bmp"); //https://software.intel.com/sites/default/files/forum/351974/lena.bmp
}
private void InitSharpDX()
{
//Init Direct Draw
//Set Rendering properties
RenderTargetProperties renderProp = new RenderTargetProperties()
{
DpiX = 0,
DpiY = 0,
MinLevel = FeatureLevel.Level_10,
PixelFormat = new PixelFormat(bmp_format, bmp_alphamode),
Type = RenderTargetType.Hardware,
Usage = RenderTargetUsage.None
};
//set hwnd target properties (permit to attach Direct2D to window)
HwndRenderTargetProperties winProp = new HwndRenderTargetProperties()
{
Hwnd = this.pictureBox1.Handle,
PixelSize = new Size2(this.pictureBox1.ClientSize.Width, this.pictureBox1.ClientSize.Height),
PresentOptions = PresentOptions.Immediately
};
//target creation
target = new WindowRenderTarget(factory, renderProp, winProp);
}
//load bmp file into program memory
private void LoadBitmapFromFile(string file)
{
image1 = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(file, true);
var sourceArea = new System.Drawing.Rectangle(0, 0, image1.Width, image1.Height);
bmpdata1 = image1.LockBits(sourceArea, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
image1.UnlockBits(bmpdata1);
}
private void drawBitmap(IntPtr pBuffer, int len, int width, int height)
{
try
{
var bitmapProperties = new BitmapProperties(new PixelFormat(bmp_format, bmp_alphamode));
var size = new Size2(width, height);
int stride = width * 3; //only want RGB, ignore alpha
var bmp = new SharpDX.Direct2D1.Bitmap(target, size, new DataPointer(pBuffer, len), stride, bitmapProperties);
//draw elements
Draw(ref bmp);
bmp.Dispose();
}
finally
{
}
}
private void Draw(ref SharpDX.Direct2D1.Bitmap bmp)
{
//begin rendering
target.BeginDraw();
//clear target
target.Clear(null);
//draw bitmap
target.DrawBitmap(bmp, 1.0f, BitmapInterpolationMode.Linear);
//end drawing
target.EndDraw();
}
//draw image using SharpDX
private void cmdRender_Click(object sender, EventArgs e)
{
if (bmpdata1 != null)
{
int len = bmpdata1.Width * bmpdata1.Height * 3;
var sw = Stopwatch.StartNew();
drawBitmap(bmpdata1.Scan0, len, bmpdata1.Width, bmpdata1.Height);
sw.Stop();
Console.WriteLine("SharpDX: {0}us", sw.ElapsedTicks / (TimeSpan.TicksPerMillisecond / 1000));
}
}
//draw image using DrawImage()
private void cmdDrawImage_Click(object sender, EventArgs e)
{
if (image1 != null)
{
var g = pictureBox1.CreateGraphics();
var sourceArea = new System.Drawing.Rectangle(0, 0, image1.Width, image1.Height);
var sw = Stopwatch.StartNew();
g.DrawImage(image1, sourceArea); //DrawImage is slow
sw.Stop();
Console.WriteLine("DrawImage: {0}us", sw.ElapsedTicks/(TimeSpan.TicksPerMillisecond / 1000));
}
}
}
}
The bmp_format B8G8R8A8_UNorm doesn't match the System.Drawing lock format Format24bppRgb... also use bmpdata1.Stride instead of calculating a potential invalid stride.
Your stride is usually the width of the bitmap multipled by the byte depth.
so 512 * 4 would be a 512 wide bitmap with a 32 bit palette. Eg RGBA
I'm trying to rotate the image.. I have a pictureBox 369x276. But when I rotate, this size decrease.
The pictureBox sizeMode is PictureBoxSizeMode.StretchImage
here is my code:
Bitmap oldBitmap = (Bitmap)pictureBox1.Image;
float angle = 90;
var newBitmap = new Bitmap(oldBitmap.Width, oldBitmap.Height);
var graphics = Graphics.FromImage(newBitmap);
graphics.TranslateTransform((float)oldBitmap.Width / 2, (float)oldBitmap.Height / 2);
graphics.RotateTransform(angle);
graphics.TranslateTransform(-(float)oldBitmap.Width / 2, -(float)oldBitmap.Height / 2);
graphics.DrawImage(oldBitmap, new Point(0, 0));
pictureBox1.Image = newBitmap;
Just use RotateFlip:
Bitmap oldBitmap = (Bitmap)pictureBox1.Image;
oldBitmap.RotateFlip(RotateFlipType.Rotate90FlipNone);
pictureBox1.Image = oldBitmap;
As #Dan-o has pointed out, this allows a rotation of any of the degree's in the System.Drawing.RotateFlipType enum.
To rotate a Bitmap any angle without losing the size, you could do the following, but it's a bit convoluted!
One - Add the WriteableBitmapEx library to your project
Two - Add the XAML, WindowsBase and PresentationCore libraries to your project
Three - Use the following to rotate your Bitmap any amount of degrees:
class Program
{
static void Main(string[] args)
{
Bitmap oldBitmap = (Bitmap)pictureBox1.Image;;
var bitmapAsWriteableBitmap = new WriteableBitmap(BitmapToBitmapImage(oldBitmap));
bitmapAsWriteableBitmap.RotateFree(23);
var rotatedImageAsMemoryStream = WriteableBitmapToMemoryStream(bitmapAsWriteableBitmap);
oldBitmap = new Bitmap(rotatedImageAsMemoryStream);
}
public static BitmapImage BitmapToBitmapImage(Bitmap bitmap)
{
var memStream = BitmapToMemoryStream(bitmap);
return MemoryStreamToBitmapImage(memStream);
}
public static MemoryStream BitmapToMemoryStream(Bitmap image)
{
var memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Bmp);
return memoryStream;
}
public static BitmapImage MemoryStreamToBitmapImage(MemoryStream ms)
{
ms.Position = 0;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
}
private static MemoryStream WriteableBitmapToMemoryStream(WriteableBitmap writeableBitmap)
{
var ms = new MemoryStream();
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(writeableBitmap));
encoder.Save(ms);
return ms;
}
}
Pain in the ass, but works!
The smaller image size is to be expected. I've never figured out why, but the Graphics.DrawImage really only works if you provide it not only a start location, but also a size. One of the overloads allows you to include size.
Since I am not getting anywhere with my previous question, I would like to know, are there any ways I can create icons on the fly on WPF?
You don't need WPF.
Usign GDI+ (System.Drawing.dll), you can create a 16x16 Bitmap, then call Icon.FromHandle(bitmap.GetHicon()).
You can use WritableBitmap for this.
You can use Taskbar icon progress bar...Sure U have seen, most of the application if doing any scanning or progress things, it displays progress actions on Icon.
Do this in your main form where u included the Icon
<Window x:Class="CCTrayHelper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Icon="/CCTrayHelper;component/Images/CCTrayHelperIcon.png">
<Window.TaskbarItemInfo>
<TaskbarItemInfo />
</Window.TaskbarItemInfo>
Trig it from code behind
private void OnProgress(object sender, EventArgs args)
{
Dispatcher.Invoke(DispatcherPriority.Send, (Action)delegate() { TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None; });
// Use here your progress type
}
This is what I ended up doing, I don't fully understand the details, if you find anything that can be improved, please do comment. Thanks for all the answers and comments.
public static ImageSource GetIconWithText(int digit)
{
BitmapImage myBitmapImage = new BitmapImage(new Uri(#"Images\PomoDomo.ico",
UriKind.RelativeOrAbsolute));
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
// Draw image
drawingContext.DrawImage(myBitmapImage, new Rect(0, 0, myBitmapImage.Width,
myBitmapImage.Height));
var typeFace = new Typeface(new FontFamily("Verdana"), FontStyles.Normal,
FontWeights.ExtraBold, FontStretches.UltraCondensed);
var formatedText = new FormattedText(digit.ToString(),
CultureInfo.InvariantCulture,
FlowDirection.LeftToRight,
typeFace,
40,
System.Windows.Media.Brushes.White);
//Center the text on Image
int pointY = (int)(myBitmapImage.Height - formatedText.Height) / 2;
int pointX = (int)(myBitmapImage.Width - formatedText.Width) / 2;
drawingContext.DrawText(formatedText, new Point(pointX, pointY));
}
RenderTargetBitmap finalBitmap = new RenderTargetBitmap((int)myBitmapImage.Width,
(int)myBitmapImage.Height, myBitmapImage.DpiX, myBitmapImage.DpiY,
PixelFormats.Pbgra32);
finalBitmap.Render(drawingVisual);
return finalBitmap;
}
private static void SaveImage(RenderTargetBitmap returnBitmap, string pngFileName)
{
string fileName = string.Format("{0}.png", pngFileName)
PngBitmapEncoder image = new PngBitmapEncoder();
image.Frames.Add(BitmapFrame.Create(returnBitmap));
using (Stream fs = File.Create(fileName))
{
image.Save(fs);
}
}
You can find a method here and here to render text on writeablebitmap