การเข้าถึงข้อมูลภาพวิดีโอด้วยดัชนีของอาร์เรย์ทำได้ค่อนข้างง่ายและสะดวก แต่เมื่อมีภาพจำนวนมากและต้องประมวลผลทุกภาพ ก็จะต้องใช้พลังสูง โดยเฉพาะเมื่อใช้อาร์เรย์ เพราะ .NET framework จำเป็นต้องตรวจสอบว่าดัชนีของอาร์เรย์อยู่ในช่วงที่เป็นไปได้หรือไม่ตลอดเป็นต้น
หากต้องการให้การประมวลผลมีประสิทธิภาพมากขึ้น แลกกับความเสี่ยงในการทำให้โปรแกรมล้มเหลวหากเขียนโค้ดผิดพลาด คือปิดการตรวจสอบช่วงของอาร์เรย์ เราสามารถทำได้โดยการปรับรูปแบบการคอมไพล์ให้เป็นแบบ unsafe และใช้ pointer ในการเข้าถึงหน่วยความจำโดยตรง
ในการกำหนดให้การ build เป็นแบบ unsafe ทำได้ดังรูป
จากนั้นทำการบันทึกไฟล์นี้
ต่อไปเราก็จะมาปรับโค้ดใหม่ โดยแยกส่วนที่เป็นการแก้ไขอาร์เรย์ของภาพออกมาเป็นฟังก์ชันใหม่ ดังนี้
unsafe void updateImage(byte[] colorData) { }
จากนั้น จะต้องใช้คำสั่ง fixed เพื่อกำหนดให้อาร์เรย์ถูกล็อคไว้ในหน่วยความจำที่ตำแหน่งคงที่ ถ้าไม่ใช้คำสั่งนี้ เมื่อรันโปรแกรมอาร์เรย์อาจจะถูกสร้างไว้ที่ตำแหน่งของหน่วยความจำที่เปลี่ยนไปเรื่อยๆ ทำให้การเข้าถึงหน่วยความจำด้วย pointer เกิดความผิดพลาด
unsafe void updateImage(byte[] colorData) { //fixed pixel data array in memory, otherwise it can be moved and be inaccessible by a pointer fixed (byte* pImage = colorData) { } }
unsafe void updateImage(byte[] colorData) { //fixed pixel data array in memory, otherwise it can be moved and be inaccessible by a pointer fixed (byte* pImage = colorData) { //in this block the data array in memory will be fixed //set a start pointer to the beginning of image data byte* pStart = pImage; //set an end pointer to the end of image data byte* pEnd = pImage + colorData.Length; int newValue=0; //loop through each byte of image data while (pStart != pEnd) { //Each byte is B G R A //blue newValue = *pStart + blueOffset; //clamping if (newValue < 0) newValue = 0; else if (newValue > 255) newValue = 255; *pStart = (byte)newValue; //green //move to next byte pStart++; newValue = *pStart + greenOffset; //clamping if (newValue < 0) newValue = 0; else if (newValue > 255) newValue = 255; *pStart = (byte)newValue; //red //move to next byte pStart++; newValue = *pStart + redOffset; //clamping if (newValue < 0) newValue = 0; else if (newValue > 255) newValue = 255; *pStart = (byte)newValue; //move to next 2 bytes ->alpha then blue again pStart += 2; } } }
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 Microsoft.Kinect; namespace KinectCam { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { KinectSensor myKinect; private void Window_Loaded(object sender, RoutedEventArgs e) { //Check if there is any connecting Kinect if (KinectSensor.KinectSensors.Count == 0) { MessageBox.Show("No Kinect detected!", "Error"); //end this app Application.Current.Shutdown(); } //Try to initialize Kinect try { //Get the first Kinect connected to this computer myKinect = KinectSensor.KinectSensors[0]; //Enable the color video stream myKinect.ColorStream.Enable(); //Start the sensor myKinect.Start(); } catch { MessageBox.Show("Initialize Kinect failed!", "Error"); //end this app Application.Current.Shutdown(); } //Video event handler myKinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(myKinect_ColorFrameReady); } //------------------------- Update color value from slider ---------------------------------- //color value private int blueOffset = 0; private int greenOffset = 0; private int redOffset = 0; private void BlueSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { //get slider value blueOffset = (int)BlueSlider.Value; } private void GreenSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { //get slider value greenOffset = (int)GreenSlider.Value; } private void RedSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { //get slider value redOffset = (int)RedSlider.Value; } //-------------------------------------------------------------------------------------------- //************************ Update display when video frame is ready********************* //color data array byte[] colorData = null; WriteableBitmap imageBitmap = null; void myKinect_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e) { using (ColorImageFrame colorFrame = e.OpenColorImageFrame()) { //if get new video frame if (colorFrame == null) return; //create an array of pixel data if(colorData==null) colorData = new byte[colorFrame.PixelDataLength]; //extract pixel data from the frame to the array colorFrame.CopyPixelDataTo(colorData); //call unsafe method to modify the pixel data updateImage(colorData); //For the first video frame, no bitmap, create a writable bitmap of video size if (imageBitmap == null) { imageBitmap = new WriteableBitmap( colorFrame.Width, colorFrame.Height, 96, //dpiX 96, //dpiY PixelFormats.Bgr32, null //palette:none ); } //For other video frames, write video data to bitmap imageBitmap.WritePixels( new Int32Rect(0, 0, colorFrame.Width, colorFrame.Height), colorData, //video data colorFrame.Width * colorFrame.BytesPerPixel, //stride 0 //offset to the array ); //set bitmap to image view kinectVideo.Source = imageBitmap; } } //********************************************************************************** //unsafe method to modify pixel data //------------------------------------------------------------------------------ unsafe void updateImage(byte[] colorData) { //fixed pixel data array in memory, otherwise it can be moved and be inaccessible by a pointer fixed (byte* pImage = colorData) { //in this block the data array in memory will be fixed //set a start pointer to the beginning of image data byte* pStart = pImage; //set an end pointer to the end of image data byte* pEnd = pImage + colorData.Length; int newValue=0; //loop through each byte of image data while (pStart != pEnd) { //Each byte is B G R A //blue newValue = *pStart + blueOffset; //clamping if (newValue < 0) newValue = 0; else if (newValue > 255) newValue = 255; *pStart = (byte)newValue; //green //move to next byte pStart++; newValue = *pStart + greenOffset; //clamping if (newValue < 0) newValue = 0; else if (newValue > 255) newValue = 255; *pStart = (byte)newValue; //red //move to next byte pStart++; newValue = *pStart + redOffset; //clamping if (newValue < 0) newValue = 0; else if (newValue > 255) newValue = 255; *pStart = (byte)newValue; //move to next 2 bytes ->alpha then blue again pStart += 2; } } } //------------------------------------------------------------------------------ } }
No comments:
Post a Comment