cvcanny和emgu

时间:2012-01-17 14:33:14

标签: emgucv

我正在开发一个名为虚拟衣柜的应用程序,对于该应用程序,我需要知道用户的大小。我的问题是如何从边缘检测图像中获取用户的大小。我使用cvcanny进行边缘检测。 我对emgu没有太多了解。 有什么建议 。 提前谢谢

1 个答案:

答案 0 :(得分:4)

这里有两种思路,但首先必须解决一些问题。除非您使用3D成像,否则您无法获得准确的尺寸,即使这取决于分辨率,您可能需要查看使用Xbox Kinect获取3D数据。

如果您使用的是一台相机,则需要先了解规格和​​镜头类型,然后才能计算出实际尺寸。这样您就可以计算每mm值的像素。有关Homography和FOV计算的详细说明,请参阅我的答案HERE

如果您知道这一点,您可以绘制身体轮廓,并在计算预期值的大小之前让人站立以适应它。

这当然只适用于你想要拍摄用户的图像并将其与真实世界大小相匹配的情况,所以你想要告诉他们他们需要10.12,14 SML XL等等......

但将衣服拉过身体更容易接受。我参考了EMGU Directory \ EMGU.CV.Example \文件夹中的示例。

首先你需要检测身体我不建议使用边缘检测这样做可以完成你必须循环每个轮廓并找到与身体匹配的那个,然后如果你可以匹配它绘制图像服装项目。看看" ShapeDetection"例如,这使用了正方形和三角形的计数器匹配。

更快的方法是Haar分类器方法,虽然不能将其调整为可靠,但实施起来要简单得多,并且考虑到您的范围是可接受的解决方案。看看" FaceDetection"代码示例。是的,这个只能检测到脸部,但还有其他的哈尔分类器将检测这些位于EMGU Directory \ opencv \ data \ haarcascades中的身体。您正在寻找:

  • haarcascade_mcs_upperbody.xml
  • haarcascade_upperbody.xml
  • haarcascade_lowerbody.xml
  • haarcascade_fullbody.xml

使用网络摄像头运行这些并测试它们以查看它们的工作原理。谷歌上有一些例子,但我建议拼凑一下" CamerCapture"示例和" FaceDetection"举个例子来获得更好的理解。如果您遇到困难,可以在这里或在EMGU论坛上询问,我会帮助您。

使用Haar分类器将为我们提供ROI(感兴趣区域),我们知道该人的全身/顶部/底部正在使用此信息我们可以向下或向上缩放服装项目的图像将其放在投资回报率的相关位置。

至于覆盖这两个图像,有两个实际选项。第一种是将图像显示在新的图片框中,图像的背景与图片框的背景一样透明。这只需要您调整控件和内容的位置,但可能会更复杂。它可以更好地执行,因为它不会花费很长时间来显示图像。特别是如果你使用高清图像。

第二个更简单的选择更简单,它假设衣服的背景是黑色或白色。循环通过ROI的每个像素,您要将衣服的相关值设置为黑色或白色,然后将所捕获图像中的像素替换为服装项目的值。如果您想了解有关访问图像数据的更多信息,请参阅我的文章HERE

有一个" PedestrianDetection"也可以使用Hog描述符,但这需要更多的工作,它可以设计为比Haar级联方法更准确地检测人,但是它的执行时间通常更糟。如果哈尔不满足你的要求,它可能是另一种选择,但我确信它会。

如果您需要更多信息或代码片段告诉我,我希望这可以帮助您,

干杯,

克里斯


代码:

这段代码很快就会被写完,并且没有经过全面测试,所以如果奇怪的错误让我知道并且我会修复它。

好的,我们将从相机捕捉开始这个相当直接,我们根据我们希望使用的设备创建一个新的Capture变量。如果有多个设备,那么我们可以定义最终确定我们的捕获设备的创建,

_capture = new Capture(0);将使用第一个设备
_capture = new Capture(1);将使用第二个设备

在我们的例子中,我们假设我们的相机是默认设备或唯一的相机设备。

参考表格只是一个放在表格上的图片框,很简单。

相机及其捕捉......

private Capture _capture;

public Form1()
{
    InitializeComponent();

    //We will start our capture here we can always do this from another method
    _capture = new Capture();
    Application.Idle += ProcessFrame;
}

Application.Idle + = ProcessFrame;每当我们获取一个帧并且我们的程序没有做任何事情时,就会在方法中添加一个调用,这是使用定时器的首选方法,因为它允许更高的帧速率。

所以在这里我们也在全球范围内声明我们的haarcascade,因为我们经常使用它,所以我们通常不希望每帧产生它。一个重要的注意事项是,我们制作了一个我们获得的框架的副本,这不是必需的,但是如果垃圾收集器在我们执行大型处理操作时释放帧信息,则确保我们不会遇到任何问题。我们还为我们的帧分配内存作为全局变量,因为我们一直在使用它而不想继续创建它。

我已经向您展示了上半身和下半身的检测,以显示如何应用两个级联。 Haarcascades也只处理灰度图像,所以我们创建了一个可以使用的图像。

无论如何这将根据检测到上半身的位置绘制图像。

//Add the cascade file to you project and set to copy always as it needs to 
//be in your output directory
HaarCascade UpperBody = new HaarCascade("haarcascade_mcs_upperbody.xml");
HaarCascade LowerBody = new HaarCascade("haarcascade_lowerbody.xml");

Image<Bgr, Byte> frame = new Image<Bgr, Byte>();
Image<Gray, Byte> Gray_frame = new Image<Gray, Byte>();

private void ProcessFrame(object sender, EventArgs arg)
{
    frame = _capture.QueryFrame().Copy();
    Gray_frame = frame.Convert<Gray, Byte>();

    //Upper Body
    MCvAvgComp[][] UpperBodyDetected = Gray_frame.DetectHaarCascade(
        UpperBody , 
        1.1, 
        10, 
        Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, 
        new Size(20, 20));

    //Lower Body
    MCvAvgComp[][] LowerBodyDetected = Gray_frame.DetectHaarCascade(
        LowerBody , 
        1.1, 
        10, 
        Emgu.CV.CvEnum.HAAR_DETECTION_TYPE.DO_CANNY_PRUNING, 
        new Size(20, 20));

    //draw the results on the image just for effect for now
    // but alternatively here we could display the clothing item according to the ROI
    foreach (MCvAvgComp Upp_Body in UpperBodyDetected[0])
    {
        //draw the upper bodt detected in the with blue
        frame.Draw(Upp_Body.rect, new Bgr(Color.Blue), 2);
    }
    foreach (MCvAvgComp Low_Body in LowerBodyDetected[0])
    {
        //draw the upper bodt detected in the with red
        frame.Draw(Low_Body.rect, new Bgr(Color.Red), 2);
    }
}

好的以便找到身体所需的代码,现在我们必须在我们的图像上绘制对象,这需要更多的调查应用程序,但我会给你一个关于如何绘制图像的快速示例在获得的框架上有白色背景。如果您希望使用新控件绘制图像,那么我担心我没有时间完全测试所需的代码。如果你遇到困难,请问,因为这里有更多知道c#而非图像分析的人。

//our image to draw
Image<Bgr, Byte> Jumper_example = new Image<Bgr, Byte>("filename.jpg");

foreach (MCvAvgComp Upp_Body in UpperBodyDetected[0])
{
    for(int i = 0; i < Jumper_example.Height; i++)
    {
        for(int j = 0; j < Jumper_example.Width; j++)
        {
            //This will only execute if the data isn't white
            if(Jumper_example.Data[i,j,0] != 255 && Jumper_example.Data[i,j,1] != 255 && Jumper_example.Data[i,j,2] != 255)
            {
                //work out our co-ordinates to draw to
                x = Upp_Body.rect.X + j;
                y = Upp_Body.rect.Y + i;

                //.Data is usually backwards if I remember but if it doesn't draw
                //correctley swap x an y this is where I may have messed up if so let me

                //copy data
                frame.Data[y,x,0] = Jumper_example.Data[i,j,0];
                frame.Data[y,x,1] = Jumper_example.Data[i,j,1];
                frame.Data[y,x,2] = Jumper_example.Data[i,j,2];
            }
        }
    }
}

好的,大部分都希望它有所帮助,

干杯,
克里斯