C# 当我将一个图像输入到我训练过的模型中时,它会给出80%+;对未在模型中训练的对象的精度

C# 当我将一个图像输入到我训练过的模型中时,它会给出80%+;对未在模型中训练的对象的精度,c#,python,opencv,tensorflow,keras,C#,Python,Opencv,Tensorflow,Keras,我正在开发一款能识别手势的Unity Android应用程序。我用来训练模型的图像是50x50黑白图像,通过HSV值进行手动分割。现在,在测试模型时也进行了同样的操作,但问题是: 当相机中没有手时,它仍然会检测到一些东西(任何东西-通过移动相机),因为HSV不准确,当带有(无手)的图像馈送到模型时,它仍然会提供80%以上的准确度,并为其确定一个随机类别。 通过图像和代码对模型进行训练,并将其向下链接 我正在使用TensorflowSharp加载我的模型。 对于openCV,我使用的是统一版的op

我正在开发一款能识别手势的Unity Android应用程序。我用来训练模型的图像是50x50黑白图像,通过HSV值进行手动分割。现在,在测试模型时也进行了同样的操作,但问题是: 当相机中没有手时,它仍然会检测到一些东西(任何东西-通过移动相机),因为HSV不准确,当带有(无手)的图像馈送到模型时,它仍然会提供80%以上的准确度,并为其确定一个随机类别。

通过图像和代码对模型进行训练,并将其向下链接

我正在使用TensorflowSharp加载我的模型。 对于openCV,我使用的是统一版的openCV 我有4个手势(4个班),每个班有4-4.5k图像,总共17k图像。样本图像

第一类

第二类

第三类

第四类

如果您需要任何其他信息,请告诉我,任何帮助都将不胜感激

  • 我尝试过手部检测模型,这样它可以检测到没有手的时候,但它们并不准确
  • 我尝试了用户的输入来触摸他的手所在的位置,效果很好,但当手被移开时,由于HSV,它再次开始随机检测
  • 我尝试过通过SIFT等进行特征匹配,但代价非常昂贵
  • 我尝试了模板匹配,从我的角度来看,这应该是可行的,但却产生了一些奇怪的结果

#型号2,使用了一些我没有提到的其他型号
model=models.Sequential()
model.add(layers.ZeroPadding2D((2,2),批处理输入形状=(无,50,50,1),name=“zeropadding1”)
#由于零填充,54x54馈入
添加(layers.Conv2D(8,(5,5),activation='relu',name='conv1_1'))
model.add(layers.ZeroPadding2D((2,2),name=“zeropadding1_2”))
添加(layers.Conv2D(8,(5,5),activation='relu',name='conv1_2'))
model.add(layers.MaxPooling2D((2,2),strips=(2,2),name=“maxpool_1”)#将50x50转换为25x25
#25x25输入
model.add(layers.ZeroPadding2D((2,2),name=“zeropadding2_1”))
添加(layers.Conv2D(16,(5,5),activation='relu',name='conv2_1'))
model.add(layers.ZeroPadding2D((2,2),name=“zeropadding2_2”))
添加(layers.Conv2D(16,(5,5),activation='relu',name='conv2_'))
model.add(layers.MaxPooling2D((5,5),strips=(5,5),name=“maxpool_2”)#将25x25转换为5x5
#5x5输入
model.add(layers.ZeroPadding2D((2,2),name=“zeropadding3_1”))
添加(layers.Conv2D(40,(5,5),activation='relu',name='conv3_1'))
model.add(layers.ZeroPadding2D((2,2),name=“zeropadding3_2”))
添加(layers.Conv2D(32,(5,5),activation='relu',name='conv3_2'))
模型.添加(层.退出(0.2))
model.add(layers.flatte())
model.add(layers.Dense(512,activation='tanh'))
模型.添加(层.退出(0.2))
model.add(layers.Dense(512,activation='tanh'))
模型.添加(层.退出(0.15))
model.add(layers.Dense(512,activation='tanh'))
模型.添加(层.退出(0.1))
model.add(layers.Dense(512,activation='tanh'))
model.add(layers.Dense(512,activation='tanh'))
model.add(layers.Dense(512,activation='tanh'))
model.add(layers.Dense(512,activation='tanh'))
model.add(layers.Dense(512,activation='tanh'))
model.add(layers.Dense(4,activation='sigmoid',name=“outputlayer”))
预期结果:训练模型的实际4个类别的准确度较高,其余类别的准确度较低


实际结果:对实际的4个类以及输入到它的其余图像具有更高的准确性。

根据我的说法,基本问题是您无法检测图像中是否有手。你需要确定手的位置

  • 首先,我们需要检测手是否存在。您可以尝试暹罗网络来完成这些任务。我成功地用它们来检测皮肤异常。您可以参考此-> “使用Keras的暹罗网络一次性学习”由Harshall Lamba撰写由Harshvardhan Gupta撰写的《PyTorch中暹罗网络的面部相似性》

  • 网络将提供二进制输出。如果有手,则会看到更接近1的值。否则,将看到接近零的值

  • 另外,像YOLO这样的ML模型用于对象定位,但暹罗网络简单而冷静

    暹罗网络实际上使用相同的CNN,因此它们是暹罗网络或连体网络。他们测量图像嵌入之间的绝对误差,并尝试近似图像之间的相似性函数


    经过适当的检测,就可以进行分类了。

    我猜这意味着“80%以上的准确率”,比如信心评分?因为80%以上的准确率似乎不算太差。所以,你有一些图像,网络应该预测“没有手势”,但它预测一些随机类。为什么不为“无手势”类添加输出?您可能也可以使用预先训练好的模型,只需替换最后一层。@Eypros:假设“80%+”是模型1的输出,softmax层确实可以解释为一种概率,因为它将输出缩放为总和为1。对于模型2,这是不可能的,因为sigmoid激活。@Gregor精度通常是指将预测值与基本事实进行比较的度量,而不是以一种奇特的方式来命名预测值分数。这可能是一个糟糕的问题,但是:您的培训数据是否包含大量负面示例,即没有参与的示例?它对它们进行了很好的分类吗?意思:我们能合理地期望它对你的底片进行分类吗?是的,你说得对,整个问题是手部检测。如果通过某种算法,我能“有效地”检测到一只手,那么整个问题就会得到解决。好的,让我来
    
    using (var graph = new TFGraph())
    {
    graph.Import(buffer);
    using (var session = new TFSession(graph))
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();
        var runner = session.GetRunner();
        Mat gray = new Mat();
        Mat HSVMat = new Mat();
        Imgproc.resize(touchedRegionRgba, gray, new
        OpenCVForUnity.Size(50, 50));
        Imgproc.cvtColor(gray, HSVMat, Imgproc.COLOR_RGB2HSV_FULL);
        Imgproc.cvtColor(gray, gray, Imgproc.COLOR_RGBA2GRAY);
        for (int i = 0; i < gray.rows(); i++)
        {
            int count = 0;
            for (int j = 200; count<gray.cols(); j++)
            {
                double[] Hvalue = HSVMat.get(i, count);
                if (!((detector.mLowerBound.val[0] <= Hvalue[0] && Hvalue[0] <= detector.mUpperBound.val[0]) &&
                    (detector.mLowerBound.val[1] <= Hvalue[1] && Hvalue[1] <= detector.mUpperBound.val[1]) &&
                    (detector.mLowerBound.val[2] <= Hvalue[2] && Hvalue[2] <= detector.mUpperBound.val[2])))
                {
                    gray.put(i, count, new byte[] { 0 });
                }
            }
        }
        var tensor = Util.ImageToTensorGrayScale(gray);
        //runner.AddInput(graph["conv1_input"][0], tensor);
        runner.AddInput(graph["zeropadding1_1_input"][0], tensor);
        //runner.Fetch(graph["outputlayer/Softmax"][0]);
        //runner.Fetch(graph["outputlayer/Sigmoid"][0]);
        runner.Fetch(graph["outputlayer/Softmax"][0]);
        var output = runner.Run();
        var vecResults = output[0].GetValue();
        float[,] results = (float[,])vecResults;
        sw.Stop();
        int result = Util.Quantized(results);
        //numberOfFingersText.text += $"Length={results.Length} Elapsed= {sw.ElapsedMilliseconds} ms, Result={result}, Acc={results[0, result]}";
        }
    }