当前位置:   article > 正文

人工智能---动物识别系统

动物识别系统

人工智能动物识别系统规则库的实现

0 前言

       由于研究生阶段的需要,需要系统学习C#语言,为了将最近学习的东西进行一个总结,偶然间想到了本科写的那个动物识别系统,用C语言写的很简单,只是用了简单的if…else语句,这里也是简单的用C#语言进行了一个复现。原来的C语言版本在这里:动物识别系统C语言版

1 问题重述和技术背景

1.1 问题重述

       有如下规则库,用户来选择这些条件,根据用户输入的条件来判断这是一种什么动物:

编号IF条件推论
R1有毛哺乳动物
R2有奶哺乳动物
R3有羽毛
R4会飞 & 会下蛋
R5吃肉食肉动物
R6有犬齿 & 有爪 & 眼盯前方食肉动物
R7哺乳动物 & 有蹄有蹄类动物
R8哺乳动物 & 反刍动物有蹄类动物
R9哺乳动物 & 食肉动物 & 黄褐色 & 暗斑点金钱豹
R10哺乳动物 & 食肉动物 & 黄褐色 & 黑色条纹
R11有蹄类动物 & 长脖子 & 长腿 & 暗斑点长颈鹿
R12有蹄类动物 & 黑色条纹斑马
R13鸟 & 不会飞 & 长脖子 & 长腿 & 黑白二色鸵鸟
R14鸟 & 不会飞 & 会游泳 & 黑白二色企鹅
R15鸟 & 善飞信天翁

       如果用一个图来表示就是这样的:
动物推理图
图中,食肉动物那一列,需要同时满足时哺乳动物才能继续往下推出时金钱豹或老虎。

1.2技术背景

        我采用的是字典作为知识库和规则库的存储结构,知识库的结构是:

Dictionary<int, string> _knowledgeBase = new Dictionary<int, string>()
{
   {1, "有毛发"},{2, "有奶 "},{3 ,"有羽毛"},{4 ,"会飞 "},
   {5 ,"会下蛋"},{6 ,"眼盯前方"},{7 ,"有蹄 "},{8 ,"反刍动物"},
   {9 ,"吃肉 "},{10 ,"有犬齿"},{11 ,"有爪"},{12 ,"长脖子"},
   {13 ,"长腿"},{14 ,"有暗斑点"},{15 ,"有黑色条纹"},{16 ,"黄褐色"},
   {17 ,"不会飞"},{18 ,"黑白二色"},{19 ,"会游泳"},{20 ,"擅飞"}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这样知识库条件的序号就一一对应上了,也方便输出。

规则库的结构是:

Dictionary<int[], string> _ruleBase = new Dictionary<int[], string>();
  • 1

之所以选择int数组作为其存储结构,在用户输入后,把用户输入的条件序号转换为一个int数组,这样就可以直接看字典中是否有这个键,当然要对这个int数组进行一个约束,因为对于判断数组相同的要求是:1.数组元素个数相同。2.对应位置上的元素相同,我这里采用的方式是对int数组进行一个排序,即使用户不是按照顺序输入的条件,也能进行判断。
        遇到的问题:因为int数组是引用类型,存储的是地址,因次即使Dictionary中存在和用户输入相同的键,也不能进行判断,用户输入的条件数组的地址和Dictionary中键的地址是不一样的,比如:

 Dictionary<int[], string> _rule = new Dictionary<int[], string>();
 _rule.Add(new int[] { 1, 2, 3 }, "鸟");
 int[] rule = { 1, 2, 3 };
 bool result = _rule.ContainsKey(rule); //result的结果为false
  • 1
  • 2
  • 3
  • 4

result的结果居然是false,那就是引用类型的缘故,解决方法:需要重写Equals()方法,以及重写GetHashCode()方法。
参考自文章:C#中,对于Dictionary字典类型,使用引用类型做Key的注意事项

2 完整代码

using System;
using System.Collections.Generic;
using System.Linq;

namespace AnimalSystem
{
    // 使用引用类型作为字典的Key,需要重写Equals方法和GetHashCode()方法
    public class ArrayExtend
    {
        int[] arr;
        string content = "";

        public void Init(int[] a)
        {
            int count = a.Count();
            arr = new int[count];
            for (int i = 0; i < count; i++)
            {
                arr[i] = a[i];
                content += arr[i] + ",";
            }
        }

        public override bool Equals(object obj)
        {
            ArrayExtend temp22 = (ArrayExtend)obj;
            bool flag = true;
            for (int i = 0; i < arr.Count(); i++)
            {
                if (arr[i] != temp22.arr[i])
                    flag = false;
            }
            return flag;
        }

        public override int GetHashCode()
        {
            return content.GetHashCode();
        }
    }
    class Program
    {

        static void Main(string[] args)
        {
            // 准备知识库
            Dictionary<int, string> _knowledgeBase = new Dictionary<int, string>()
            {
                    {1, "有毛发"},{2, "有奶 "},{3 ,"有羽毛"},{4 ,"会飞 "},
                    {5 ,"会下蛋"},{6 ,"眼盯前方"},{7 ,"有蹄 "},{8 ,"反刍动物"},
                    {9 ,"吃肉 "},{10 ,"有犬齿"},{11 ,"有爪"},{12 ,"长脖子"},
                    {13 ,"长腿"},{14 ,"有暗斑点"},{15 ,"有黑色条纹"},{16 ,"黄褐色"},
                    {17 ,"不会飞"},{18 ,"黑白二色"},{19 ,"会游泳"},{20 ,"擅飞"}
            };

            // 这里使用的是int[]数组类型作为字典的Key,其使用方法引用自文章
            // https://www.cnblogs.com/WangSong-Gemini/p/16407833.html
            // 准备规则库(命名规则:第一个数字代表动物编号,第二个数字代表该动物的条件编号)
            Dictionary<ArrayExtend, string> _ruleBase = new Dictionary<ArrayExtend, string>();
            ArrayExtend a11 = new ArrayExtend();
            ArrayExtend a12 = new ArrayExtend();
            ArrayExtend a13 = new ArrayExtend();
            ArrayExtend a14 = new ArrayExtend();
            ArrayExtend a21 = new ArrayExtend();
            ArrayExtend a22 = new ArrayExtend();
            ArrayExtend a23 = new ArrayExtend();
            ArrayExtend a24 = new ArrayExtend();
            ArrayExtend a31 = new ArrayExtend();
            ArrayExtend a32 = new ArrayExtend();
            ArrayExtend a33 = new ArrayExtend();
            ArrayExtend a34 = new ArrayExtend();
            ArrayExtend a41 = new ArrayExtend();
            ArrayExtend a42 = new ArrayExtend();
            ArrayExtend a43 = new ArrayExtend();
            ArrayExtend a44 = new ArrayExtend();
            ArrayExtend a51 = new ArrayExtend();
            ArrayExtend a52 = new ArrayExtend();
            ArrayExtend a61 = new ArrayExtend();
            ArrayExtend a62 = new ArrayExtend();
            ArrayExtend a71 = new ArrayExtend();
            ArrayExtend a72 = new ArrayExtend();
            a11.Init(new int[] { 1, 7, 15 });
            a12.Init(new int[] { 2, 7, 15 });
            a13.Init(new int[] { 1, 8, 15 });
            a14.Init(new int[] { 2, 8, 15 }); // 斑马
            a21.Init(new int[] { 1, 7, 12, 13, 14 });
            a22.Init(new int[] { 2, 7, 12, 13, 14 });
            a23.Init(new int[] { 1, 8, 12, 13, 14 });
            a24.Init(new int[] { 2, 8, 12, 13, 14 }); // 长颈鹿
            a31.Init(new int[] { 1, 9, 14, 16 });
            a32.Init(new int[] { 2, 9, 14, 16 });
            a33.Init(new int[] { 1, 6, 10, 11, 14, 16 });
            a34.Init(new int[] { 2, 6, 10, 11, 14, 16 }); // 金钱豹
            a41.Init(new int[] { 1, 9, 15, 16 });
            a42.Init(new int[] { 2, 9, 15, 16 });
            a43.Init(new int[] { 1, 6, 10, 11, 15, 16 });
            a44.Init(new int[] { 2, 6, 10, 11, 15, 16 }); // 虎
            a51.Init(new int[] { 3, 12, 13, 17, 18 });
            a52.Init(new int[] { 4, 5, 12, 13, 17, 18 }); // 鸵鸟
            a61.Init(new int[] { 3, 20 });
            a62.Init(new int[] { 4, 5, 20 }); // 信天翁
            a71.Init(new int[] { 3, 17, 18, 19 });
            a72.Init(new int[] { 4, 5, 17, 18, 19 }); // 企鹅
            _ruleBase.Add(a11, "斑马");
            _ruleBase.Add(a12, "斑马");
            _ruleBase.Add(a13, "斑马");
            _ruleBase.Add(a14, "斑马");
            _ruleBase.Add(a21, "长颈鹿");
            _ruleBase.Add(a22, "长颈鹿");
            _ruleBase.Add(a23, "长颈鹿");
            _ruleBase.Add(a24, "长颈鹿");
            _ruleBase.Add(a31, "金钱豹");
            _ruleBase.Add(a32, "金钱豹");
            _ruleBase.Add(a33, "金钱豹");
            _ruleBase.Add(a34, "金钱豹");
            _ruleBase.Add(a41, "虎");
            _ruleBase.Add(a42, "虎");
            _ruleBase.Add(a43, "虎");
            _ruleBase.Add(a44, "虎");
            _ruleBase.Add(a51, "鸵鸟");
            _ruleBase.Add(a52, "鸵鸟");
            _ruleBase.Add(a61, "信天翁");
            _ruleBase.Add(a62, "信天翁");
            _ruleBase.Add(a71, "企鹅");
            _ruleBase.Add(a72, "企鹅");


            // 输出知识库
            Console.WriteLine("===============================动物识别系统规则库===============================");
            foreach (var item in _knowledgeBase)
            {
                Console.Write("{0}:{1}\t", item.Key, item.Value);
                if (item.Key % 5 == 0) // 控制换行的逻辑
                {
                    Console.WriteLine();
                }
            }

            // 获取用户输入
            Console.WriteLine("================================================================================");
            Console.WriteLine("请输入已知条件(用空格分开),按回车结束:");
            
            // 获取用户输入
            string userInput = Console.ReadLine();
            // 拆分用户输入
            string[] inputx = userInput.Split(' ');
            // 将用户输入的字符串转换成int数组
            int[] inputy = new int[inputx.Length];
            for (int i = 0; i < inputy.Length; i++)
            {
                inputy[i] = Convert.ToInt32(inputx[i]);
            }
            // 反馈给用户检查
            Console.WriteLine("================================================================================");
            Console.Write("请检查您的输入:");
            foreach(var item in inputy)
            {
                Console.Write(item + " ");
            }
            Console.WriteLine();
            Console.Write("Y/N?: ");
            string inputCheck = Console.ReadLine();
            if(inputCheck.Equals("Y") || inputCheck.Equals("y"))
            {
                Console.WriteLine("OK");
                // 将用户的输入排个序
                SortArray(inputy);
            }
            else if(inputCheck.Equals("N") || inputCheck.Equals("n"))
            {
                // 实现跳转到重新输入的逻辑?(待实现)
                Console.WriteLine("Error");
                
            }
            else
            {
                Console.WriteLine("请重新输入:");
                throw new Exception("输入错误");
                // 跳转到重新输入的逻辑?
            }
            Console.WriteLine("================================================================================");
            // 进行判断的逻辑
            ArrayExtend inputUser = new ArrayExtend();
            inputUser.Init(inputy);
            try
            {
                // 如果当前规则库中没有存在这个规则在这里就会抛出异常
                string result = _ruleBase[inputUser];
                Console.WriteLine("根据您输入的条件,可以推断出这个动物是:" + result);
            }
            catch (Exception)
            {
                Console.WriteLine("根据您的输入条件,无法判断这是一种什么动物。");
            }
            
            Console.ReadLine();
        }

        // 将数组元素从小到大排序(用户的输入可能不是按照从小到大的顺序,根据规则库的存储结构,需要将用户的输入进行从小到大的排序)
        static void SortArray(int[] arr)
        {
            for (int i = 0; i < arr.Length-1; i++)
            {
                for (int j = i + 1; j < arr.Length; j++)
                {
                    if (arr[j] < arr[i])
                    {
                        int temp = arr[j];
                        arr[j] = arr[i];
                        arr[i] = temp;
                    }
                }
            }
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217

3 总结

        代码还有很多不完善的地方,比如说实现反复推理,不是每次运行推理结束后又要点一次运行,又比如说在不小心输入错误了,实现重新输入等等。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/655087
推荐阅读
相关标签
  

闽ICP备14008679号