c# - 当我将图像提供给经过训练的模型时,它为未在模型中训练的对象提供了 80% 以上的准确度

标签 c# python opencv tensorflow keras

我正在开发识别手势的 Unity-Android 应用程序。我用来训练模型的图像是50x50 黑白图像,手部通过HSV 值 进行分割。现在,在测试模型时也在做同样的事情,但问题是: 当相机中没有手时,它仍然会检测到某些东西(任何东西 - 通过移动相机),因为 HSV 不准确,并且当将带有(没有手)的图像输入模型时,它仍然会给出80% 以上的准确率并为其确定一个随机类别。

用于训练模型的图像和代码已链接。

I am using TensorflowSharp to load my model. For openCV I am using OpenCV for Unity I have 4 gestures (4 classes), where each class has 4-4.5k images total of 17k images. Sample images

1 级

Class 1

第 2 类

Class 2

第 3 类

Class 3

第 4 类

Class 4

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

  • 我尝试过手部检测模型,因此它可以检测到什么时候没有手,但它们并不准确。
  • 我已尝试通过用户的输入来触摸他的手所在的位置,它工作正常,但当手被移开时,由于 HSV,它再次开始随机检测。
  • 我尝试通过 SIFT 等进行特征匹配,但它们的成本非常高。
  • 我尝试了模板匹配,从我的角度来看应该可行,但给出了一些奇怪的结果。

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]}";
    }
}


# EDITED MODEL, MODEL 1

model = models.Sequential()
model.add(layers.ZeroPadding2D((2, 2), batch_input_shape=(None, 50, 50, 1), name="zeropadding1_1"))   

#54x54 fed in due to zero padding
model.add(layers.Conv2D(8, (5, 5), activation='relu', name='conv1_1'))
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding1_2"))
model.add(layers.Conv2D(8, (5, 5), activation='relu', name='conv1_2'))

model.add(layers.MaxPooling2D((2, 2), strides=(2, 2), name="maxpool_1")) #convert 50x50 to 25x25

#25x25 fed in
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding2_1"))
model.add(layers.Conv2D(16, (5, 5), activation='relu', name='conv2_1'))
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding2_2"))
model.add(layers.Conv2D(16, (5, 5), activation='relu', name='conv2_2'))

model.add(layers.MaxPooling2D((5, 5), strides=(5, 5), name="maxpool_2")) #convert 25x25 to 5x5

#5x5 fed in
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding3_1"))
model.add(layers.Conv2D(40, (5, 5), activation='relu', name='conv3_1'))
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding3_2"))
model.add(layers.Conv2D(32, (5, 5), activation='relu', name='conv3_2'))

model.add(layers.Dropout(0.2))
model.add(layers.Flatten())

model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dropout(0.15))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dropout(0.1))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(512, activation='relu'))

model.add(layers.Dense(4, activation='softmax', name="outputlayer"))

# MODEL 2, used a few more that I haven't mentioned

model = models.Sequential()
model.add(layers.ZeroPadding2D((2, 2), batch_input_shape=(None, 50, 50, 1), name="zeropadding1_1"))   

#54x54 fed in due to zero padding
model.add(layers.Conv2D(8, (5, 5), activation='relu', name='conv1_1'))
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding1_2"))
model.add(layers.Conv2D(8, (5, 5), activation='relu', name='conv1_2'))

model.add(layers.MaxPooling2D((2, 2), strides=(2, 2), name="maxpool_1")) #convert 50x50 to 25x25

#25x25 fed in
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding2_1"))
model.add(layers.Conv2D(16, (5, 5), activation='relu', name='conv2_1'))
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding2_2"))
model.add(layers.Conv2D(16, (5, 5), activation='relu', name='conv2_2'))

model.add(layers.MaxPooling2D((5, 5), strides=(5, 5), name="maxpool_2")) #convert 25x25 to 5x5

#5x5 fed in
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding3_1"))
model.add(layers.Conv2D(40, (5, 5), activation='relu', name='conv3_1'))
model.add(layers.ZeroPadding2D((2, 2), name="zeropadding3_2"))
model.add(layers.Conv2D(32, (5, 5), activation='relu', name='conv3_2'))

model.add(layers.Dropout(0.2))
model.add(layers.Flatten())

model.add(layers.Dense(512, activation='tanh'))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(512, activation='tanh'))
model.add(layers.Dropout(0.15))
model.add(layers.Dense(512, activation='tanh'))
model.add(layers.Dropout(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 个类以及输入给它的其余图像的准确度更高。

最佳答案

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

  1. 首先,我们需要检测手是否存在。您可以尝试使用 Siamese 网络 来完成这些任务。我已经成功地使用它们来检测皮肤异常。你可以引用这个-> Harshall Lamba 的“使用 Keras 的 Siamese 网络一次性学习” https://link.medium.com/xrCQOD8ntVHarshvardhan Gupta 的“与 PyTorch 中的连体网络的面部相似性” https://link.medium.com/htBzNmUCyV

  2. 网络会给出二进制输出。如果手存在,则将看到更接近 1 的值。否则,将看到接近零的值。

其他,像 YOLO 这样的 ML 模型用于对象定位,但是 Siamese 网络简单而清醒。

Siamese networks actually use the same CNN and hence they are siamese or conjoined. They measure the absolute error between the image embeddings and try to approximate a similarity function between the images.

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

关于c# - 当我将图像提供给经过训练的模型时,它为未在模型中训练的对象提供了 80% 以上的准确度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55468817/

相关文章:

python - 如何在Python中获得不同的组合?

ubuntu - 删除所有已安装的 OpenCV 库

c++ - 通过串口发送字符串

c# - 具有偏移量的 GroupBy DateTime 列 C# Linq

c# - 为什么 SqlQuery 比在 View 上使用 LINQ 表达式快很多?

c# - Visual Studio 不显示设计数据

c# - SqlException 在 C# 中未处理 - 数据库表中的信息

python - Numpy uint8_t 数组到 vtkImageData

python - 在 python 中创建和使用首选项文件

c++ - 无法在代码块中使用 OpenCV 2.4.9 C++ API