简体   繁体   English

Emgucv转换 <Hsv, Byte> () 图片

[英]Emgucv Convert<Hsv, Byte>() image

I am having a problem with EmguCV. 我对EmguCV有问题。 I used a demo application, and edited it to my needs. 我使用了演示应用程序,并根据需要对其进行了编辑。 It involves the following function: 它涉及以下功能:

public override Image<Gray, byte> DetectSkin(Image<Bgr, byte> Img, IColor min, IColor max)
        {
            Image<Hsv, Byte> currentHsvFrame = Img.Convert<Hsv, Byte>();
            Image<Gray, byte> skin = new Image<Gray, byte>(Img.Width, Img.Height);
            skin = currentHsvFrame.InRange((Hsv)min,(Hsv)max);
            return skin;
        }

In the demo application, the Image comes from a video. 在演示应用程序中,图像来自视频。 The frame is capured from the video like this: 像这样从视频中捕获帧:

 Image<Bgr, Byte> currentFrame;
grabber = new Emgu.CV.Capture(@".\..\..\..\M2U00253.MPG");            
            grabber.QueryFrame();
currentFrame = grabber.QueryFrame();

In my application, the Image comes from a microsoft kinect stream. 在我的应用程序中,图像来自Microsoft kinect流。

I use the following function: 我使用以下功能:

private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame != null)
                {
                    // Copy the pixel data from the image to a temporary array
                    colorFrame.CopyPixelDataTo(this.colorPixels);

                    // Write the pixel data into our bitmap
                    this.colorBitmap.WritePixels(
                        new Int32Rect(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight),
                        this.colorPixels,
                        this.colorBitmap.PixelWidth * sizeof(int),
                        0);

                    Bitmap b = BitmapFromWriteableBitmap(this.colorBitmap);
                    currentFrame = new Image<Bgr, byte>(b);
                    currentFrameCopy = currentFrame.Copy();
                    skinDetector = new YCrCbSkinDetector();

                    Image<Gray, Byte> skin = skinDetector.DetectSkin(currentFrame, YCrCb_min, YCrCb_max);


                }
            }
        }
private static System.Drawing.Bitmap BitmapFromWriteableBitmap(WriteableBitmap writeBmp)
        {
            System.Drawing.Bitmap bmp;
            using (System.IO.MemoryStream outStream = new System.IO.MemoryStream())
            {
                BitmapEncoder enc = new BmpBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create((BitmapSource)writeBmp));
                enc.Save(outStream);
                bmp = new System.Drawing.Bitmap(outStream);
            }
            return bmp;
        }

Now, the demo application works, and mine doesn't. 现在,该演示应用程序可以工作了,而我的不起作用。 Mine gives the following exception: 我的给出以下例外: 例外

And, the image here, contains the following: 并且,此处的图像包含以下内容: 在此处输入图片说明

I really don't understand this exception. 我真的不明白这个例外。 And, now, when I run the demo, working aplication, the image, contains: 而且,现在,当我运行演示时,应用程序,图像包含: 在此处输入图片说明

Which is, in my eyes, exactly the same. 在我看来,这是完全一样的。 I really don't understand this. 我真的不明白。 Help is very welcome! 非常欢迎帮助!

To make things easier I've uploaded a working WPF solution for you to the code reference sourceforge page I've been building: 为了使事情变得更容易,我已经为您上传了一个有效的WPF解决方案到我正在构建的代码参考sourceforge页面中:

http://sourceforge.net/projects/emguexample/files/Capture/Kinect_SkinDetector_WPF.zip/download https://sourceforge.net/projects/emguexample/files/Capture/ http://sourceforge.net/projects/emguexample/files/Capture/Kinect_SkinDetector_WPF.zip/download https://sourceforge.net/projects/emguexample/files/Capture/

This was designed and tested using EMGU x64 2.42 so in the Lib folder of the project you will find the referenced dlls. 这是使用EMGU x64 2.42设计和测试的,因此在项目的Lib文件夹中,您将找到引用的dll。 If you are using a different version you will need to delete the current references and replace them with the version you're using. 如果您使用的是其他版本,则需要删除当前参考并将其替换为您使用的版本。

Secondly the project is design like all projects from the code reference library to be built from the Emgu.CV.Example folder into the ..\\EMGU 2.XXX\\bin.. global bin directory where the opencv compiled libraries are within a folder either x86 or x64. 其次,该项目的设计与代码参考库中的所有项目一样,都是从Emgu.CV.Example文件夹构建到.. \\ EMGU 2.XXX \\ bin ..全局bin目录中,其中opencv编译的库位于一个文件夹中x86或x64。

If you struggle to get the code working I can provide all components but I hate redistributing all the opencv files that you already have so let me know if you want this. 如果您难以使代码正常工作,我可以提供所有组件,但是我讨厌重新分发您已经拥有的所有opencv文件,所以请告知我是否需要这样做。

You will need to resize the Mainwindow manually to display both images as I didn't spend to much time playing with layout. 您将需要手动调整Mainwindow的大小以显示两个图像,因为我没有花太多时间在布局上。

So the code... 所以代码...

In the form initialisation method I check for the kinect sensor and set up the eventhandlers for the frames ready. 在表单初始化方法中,我检查kinect传感器并设置事件处理程序以准备就绪的帧。 I have left the original threshold values and skinDetector type although I don't use the EMGU version I just forgot to remove it. 我没有使用原始的阈值和skinDetector类型,但我没有使用EMGU版本,只是忘了删除它。 You will need to play with the threshold values and so on. 您将需要使用阈值,依此类推。

            //// Look through all sensors and start the first connected one.
            //// This requires that a Kinect is connected at the time of app startup.
            //// To make your app robust against plug/unplug, 
            //// it is recommended to use KinectSensorChooser provided in Microsoft.Kinect.Toolkit (See components in Toolkit Browser).
            foreach (var potentialSensor in KinectSensor.KinectSensors)
            {
                if (potentialSensor.Status == KinectStatus.Connected)
                {
                    this.KS = potentialSensor;
                    break;
                }
            }

            //If we have a Kinect Sensor we will set it up
            if (null != KS)
            {
                // Turn on the color stream to receive color frames
                KS.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                //Turn on the depth stream to recieve depth frames
                KS.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);

                //Start the Streaming process
                KS.Start();
                //Create a link to a callback to deal with the frames
                KS.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(KS_AllFramesReady);

                //We set up a thread to process the image/disparty map from the kinect
                //Why? The kinect AllFramesReady has a timeout if it has not finished the streams will simply stop
                KinectBuffer = new Thread(ProcessBuffer);

                hsv_min = new Hsv(0, 45, 0);
                hsv_max = new Hsv(20, 255, 255);
                YCrCb_min = new Ycc(0, 131, 80);
                YCrCb_max = new Ycc(255, 185, 135);

                detector = new AdaptiveSkinDetector(1, AdaptiveSkinDetector.MorphingMethod.NONE);
                skinDetector = new YCrCbSkinDetector();
            }

I always play with the kinect data in a new thread for speed but you may want to advanced this to a Background worker if you plan to do any more heavy processing so it is better managed. 我总是在新线程中处理kinect数据,以提高速度,但是如果您打算进行更多繁重的处理,以便更好地进行管理,则可能需要将此作为高级后台处理程序。

The thread calls the ProcessBuffer() method you can ignore all the commented code as this is the remanence of the code used to display the depth image. 该线程调用ProcessBuffer()方法,您可以忽略所有注释的代码,因为这是用于显示深度图像的代码的剩余部分。 Again I'm using the Marshall copy method to keep things fast but the thing to look for is the Dispatcher.BeginInvoke in WPF that allows the images to be displayed from the Kinect thread. 再次使用Marshall复制方法来保持速度快,但是要寻找的是WPF中的Dispatcher.BeginInvoke,它允许从Kinect线程中显示图像。 This is required as I'm not processing on the main thread. 这是必需的,因为我不在主线程上进行处理。

        //This takes the byte[] array from the kinect and makes a bitmap from the colour data for us
        byte[] pixeldata = new byte[CF.PixelDataLength];
        CF.CopyPixelDataTo(pixeldata);
        System.Drawing.Bitmap bmap = new System.Drawing.Bitmap(CF.Width, CF.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
        BitmapData bmapdata = bmap.LockBits(new System.Drawing.Rectangle(0, 0, CF.Width, CF.Height), ImageLockMode.WriteOnly, bmap.PixelFormat);
        IntPtr ptr = bmapdata.Scan0;
        Marshal.Copy(pixeldata, 0, ptr, CF.PixelDataLength);
        bmap.UnlockBits(bmapdata);
        //display our colour frame
        currentFrame = new Image<Bgr, Byte>(bmap);


        Image<Gray, Byte> skin2 = skinDetector.DetectSkin(currentFrame, YCrCb_min, YCrCb_max);
        ExtractContourAndHull(skin2);

        DrawAndComputeFingersNum();

        //Display our images using WPF Dispatcher Invoke as this is a sub thread.
        Dispatcher.BeginInvoke((Action)(() =>
            {
                ColorImage.Source = BitmapSourceConvert.ToBitmapSource(currentFrame);
            }), System.Windows.Threading.DispatcherPriority.Render, null);
        Dispatcher.BeginInvoke((Action)(() =>
            {
                SkinImage.Source = BitmapSourceConvert.ToBitmapSource(skin2);
            }), System.Windows.Threading.DispatcherPriority.Render, null);

I hope this helps I will at some point neaten up the code I uploaded, 希望这对我有所帮助,可以整理一下我上传的代码,

Cheers 干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM