첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
본 블로그는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 블로그 콘텐츠 향상을 위해 쓰여집니다.

728x90
반응형
728x170

[소스 이미지]

 

 

[결과 이미지]

 

TestProject.z01
10.00MB
TestProject.z02
10.00MB
TestProject.z03
10.00MB
TestProject.z04
10.00MB
TestProject.z05
10.00MB
TestProject.z06
10.00MB
TestProject.zip
5.49MB

▶ RectangleExtension.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 사각형 확장
    /// </summary>
    public static class RectangleExtension
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 영역 구하기 - GetArea(rectangle)

        /// <summary>
        /// 영역 구하기
        /// </summary>
        /// <param name="rectangle">사각형</param>
        /// <returns>영역</returns>
        public static float GetArea(this RectangleF rectangle)
        {
            return rectangle.Width * rectangle.Height;
        }

        #endregion
    }
}

 

728x90

 

▶ YOLOModel.cs

using System.Collections.Generic;

namespace TestProject
{
    /// <summary>
    /// YOLO 모델
    /// </summary>
    public abstract class YOLOModel
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 너비 - Width

        /// <summary>
        /// 너비
        /// </summary>
        public abstract int Width { get; set; }

        #endregion
        #region 높이 - Height

        /// <summary>
        /// 높이
        /// </summary>
        public abstract int Height { get; set; }

        #endregion
        #region 깊이 - Depth

        /// <summary>
        /// 깊이
        /// </summary>
        public abstract int Depth { get; set; }

        #endregion
        #region 차원 - Dimension

        /// <summary>
        /// 차원
        /// </summary>
        public abstract int Dimension { get; set; }

        #endregion
        #region 스트라이드 배열 - StrideArray

        /// <summary>
        /// 스트라이드 배열
        /// </summary>
        public abstract float[] StrideArray { get; set; }

        #endregion
        #region 앵커 배열 - AnchorArray

        /// <summary>
        /// 앵커 배열
        /// </summary>
        public abstract float[][][] AnchorArray { get; set; }

        #endregion
        #region 도형 배열 - ShapeArray

        /// <summary>
        /// 도형 배열
        /// </summary>
        public abstract int[] ShapeArray { get; set; }

        #endregion
        #region 신뢰도 - Confidence

        /// <summary>
        /// 신뢰도
        /// </summary>
        public abstract float Confidence { get; set; }

        #endregion
        #region 다중 신뢰도 - MultipleConfidence

        /// <summary>
        /// 다중 신뢰도
        /// </summary>
        public abstract float MultipleConfidence { get; set; }

        #endregion
        #region 오버랩 - Overlap

        /// <summary>
        /// 오버랩
        /// </summary>
        public abstract float Overlap { get; set; }

        #endregion
        #region 출력 배열 - OutputArray

        /// <summary>
        /// 출력 배열
        /// </summary>
        public abstract string[] OutputArray { get; set; }

        #endregion
        #region 레이블 리스트 - LabelList

        /// <summary>
        /// 레이블 리스트
        /// </summary>
        public abstract List<YOLOLabel> LabelList { get; set; }

        #endregion
        #region 탐지 사용 여부 - UseDetect

        /// <summary>
        /// 탐지 사용 여부
        /// </summary>
        public abstract bool UseDetect { get; set; }

        #endregion
    }
}

 

300x250

 

▶ YOLOCOCOP5Model.cs

using System.Collections.Generic;

namespace TestProject
{
    /// <summary>
    /// YOLO COCO P5 모델
    /// </summary>
    public class YOLOCOCOP5Model : YOLOModel
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 너비 - Width

        /// <summary>
        /// 너비
        /// </summary>
        public override int Width { get; set; } = 640;

        #endregion
        #region 높이 - Height

        /// <summary>
        /// 높이
        /// </summary>
        public override int Height { get; set; } = 640;

        #endregion
        #region 깊이 - Depth

        /// <summary>
        /// 깊이
        /// </summary>
        public override int Depth { get; set; } = 3;

        #endregion
        #region 차원 - Dimension

        /// <summary>
        /// 차원
        /// </summary>
        public override int Dimension { get; set; } = 85;

        #endregion
        #region 스트라이드 배열 - StrideArray

        /// <summary>
        /// 스트라이드 배열
        /// </summary>
        public override float[] StrideArray { get; set; } = new float[] { 8, 16, 32 };

        #endregion
        #region 앵커 배열 - AnchorArray

        /// <summary>
        /// 앵커 배열
        /// </summary>
        public override float[][][] AnchorArray { get; set; } = new float[][][]
        {
            new float[][] { new float[] { 010, 13 }, new float[] { 016, 030 }, new float[] { 033, 023 } },
            new float[][] { new float[] { 030, 61 }, new float[] { 062, 045 }, new float[] { 059, 119 } },
            new float[][] { new float[] { 116, 90 }, new float[] { 156, 198 }, new float[] { 373, 326 } }
        };

        #endregion
        #region 도형 배열 - ShapeArray

        /// <summary>
        /// 도형 배열
        /// </summary>
        public override int[] ShapeArray { get; set; } = new int[] { 80, 40, 20 };

        #endregion
        #region 신뢰도 - Confidence

        /// <summary>
        /// 신뢰도
        /// </summary>
        public override float Confidence { get; set; } = 0.20f;

        #endregion
        #region 다중 신뢰도 - MultipleConfidence

        /// <summary>
        /// 다중 신뢰도
        /// </summary>
        public override float MultipleConfidence { get; set; } = 0.25f;

        #endregion
        #region 오버랩 - Overlap

        /// <summary>
        /// 오버랩
        /// </summary>
        public override float Overlap { get; set; } = 0.45f;

        #endregion
        #region 출력 배열 - OutputArray

        /// <summary>
        /// 출력 배열
        /// </summary>
        public override string[] OutputArray { get; set; } = new[] { "output" };

        #endregion
        #region 레이블 리스트 - LabelList

        /// <summary>
        /// 레이블 리스트
        /// </summary>
        public override List<YOLOLabel> LabelList { get; set; } = new List<YOLOLabel>()
        {
            new YOLOLabel { ID = 1,  Name = "person"         },
            new YOLOLabel { ID = 2,  Name = "bicycle"        },
            new YOLOLabel { ID = 3,  Name = "car"            },
            new YOLOLabel { ID = 4,  Name = "motorcycle"     },
            new YOLOLabel { ID = 5,  Name = "airplane"       },
            new YOLOLabel { ID = 6,  Name = "bus"            },
            new YOLOLabel { ID = 7,  Name = "train"          },
            new YOLOLabel { ID = 8,  Name = "truck"          },
            new YOLOLabel { ID = 9,  Name = "boat"           },
            new YOLOLabel { ID = 10, Name = "traffic light"  },
            new YOLOLabel { ID = 11, Name = "fire hydrant"   },
            new YOLOLabel { ID = 12, Name = "stop sign"      },
            new YOLOLabel { ID = 13, Name = "parking meter"  },
            new YOLOLabel { ID = 14, Name = "bench"          },
            new YOLOLabel { ID = 15, Name = "bird"           },
            new YOLOLabel { ID = 16, Name = "cat"            },
            new YOLOLabel { ID = 17, Name = "dog"            },
            new YOLOLabel { ID = 18, Name = "horse"          },
            new YOLOLabel { ID = 19, Name = "sheep"          },
            new YOLOLabel { ID = 20, Name = "cow"            },
            new YOLOLabel { ID = 21, Name = "elephant"       },
            new YOLOLabel { ID = 22, Name = "bear"           },
            new YOLOLabel { ID = 23, Name = "zebra"          },
            new YOLOLabel { ID = 24, Name = "giraffe"        },
            new YOLOLabel { ID = 25, Name = "backpack"       },
            new YOLOLabel { ID = 26, Name = "umbrella"       },
            new YOLOLabel { ID = 27, Name = "handbag"        },
            new YOLOLabel { ID = 28, Name = "tie"            },
            new YOLOLabel { ID = 29, Name = "suitcase"       },
            new YOLOLabel { ID = 30, Name = "frisbee"        },
            new YOLOLabel { ID = 31, Name = "skis"           },
            new YOLOLabel { ID = 32, Name = "snowboard"      },
            new YOLOLabel { ID = 33, Name = "sports ball"    },
            new YOLOLabel { ID = 34, Name = "kite"           },
            new YOLOLabel { ID = 35, Name = "baseball bat"   },
            new YOLOLabel { ID = 36, Name = "baseball glove" },
            new YOLOLabel { ID = 37, Name = "skateboard"     },
            new YOLOLabel { ID = 38, Name = "surfboard"      },
            new YOLOLabel { ID = 39, Name = "tennis racket"  },
            new YOLOLabel { ID = 40, Name = "bottle"         },
            new YOLOLabel { ID = 41, Name = "wine glass"     },
            new YOLOLabel { ID = 42, Name = "cup"            },
            new YOLOLabel { ID = 43, Name = "fork"           },
            new YOLOLabel { ID = 44, Name = "knife"          },
            new YOLOLabel { ID = 45, Name = "spoon"          },
            new YOLOLabel { ID = 46, Name = "bowl"           },
            new YOLOLabel { ID = 47, Name = "banana"         },
            new YOLOLabel { ID = 48, Name = "apple"          },
            new YOLOLabel { ID = 49, Name = "sandwich"       },
            new YOLOLabel { ID = 50, Name = "orange"         },
            new YOLOLabel { ID = 51, Name = "broccoli"       },
            new YOLOLabel { ID = 52, Name = "carrot"         },
            new YOLOLabel { ID = 53, Name = "hot dog"        },
            new YOLOLabel { ID = 54, Name = "pizza"          },
            new YOLOLabel { ID = 55, Name = "donut"          },
            new YOLOLabel { ID = 56, Name = "cake"           },
            new YOLOLabel { ID = 57, Name = "chair"          },
            new YOLOLabel { ID = 58, Name = "couch"          },
            new YOLOLabel { ID = 59, Name = "potted plant"   },
            new YOLOLabel { ID = 60, Name = "bed"            },
            new YOLOLabel { ID = 61, Name = "dining table"   },
            new YOLOLabel { ID = 62, Name = "toilet"         },
            new YOLOLabel { ID = 63, Name = "tv"             },
            new YOLOLabel { ID = 64, Name = "laptop"         },
            new YOLOLabel { ID = 65, Name = "mouse"          },
            new YOLOLabel { ID = 66, Name = "remote"         },
            new YOLOLabel { ID = 67, Name = "keyboard"       },
            new YOLOLabel { ID = 68, Name = "cell phone"     },
            new YOLOLabel { ID = 69, Name = "microwave"      },
            new YOLOLabel { ID = 70, Name = "oven"           },
            new YOLOLabel { ID = 71, Name = "toaster"        },
            new YOLOLabel { ID = 72, Name = "sink"           },
            new YOLOLabel { ID = 73, Name = "refrigerator"   },
            new YOLOLabel { ID = 74, Name = "book"           },
            new YOLOLabel { ID = 75, Name = "clock"          },
            new YOLOLabel { ID = 76, Name = "vase"           },
            new YOLOLabel { ID = 77, Name = "scissors"       },
            new YOLOLabel { ID = 78, Name = "teddy bear"     },
            new YOLOLabel { ID = 79, Name = "hair drier"     },
            new YOLOLabel { ID = 80, Name = "toothbrush"     }
        };

        #endregion
        #region 탐지 사용 여부 - UseDetect

        /// <summary>
        /// 탐지 사용 여부
        /// </summary>
        public override bool UseDetect { get; set; } = true;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - YOLOCOCOP5Model()

        /// <summary>
        /// 생성자
        /// </summary>
        public YOLOCOCOP5Model()
        {
        }

        #endregion
    }
}

 

▶ YOLOCOCOP6Model.cs

using System.Collections.Generic;

namespace TestProject
{
    /// <summary>
    /// YOLO COCO P6 모델
    /// </summary>
    public class YOLOCOCOP6Model : YOLOModel
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 너비 - Width

        /// <summary>
        /// 너비
        /// </summary>
        public override int Width { get; set; } = 1280;

        #endregion
        #region 높이 - Height

        /// <summary>
        /// 높이
        /// </summary>
        public override int Height { get; set; } = 1280;

        #endregion
        #region 깊이 - Depth

        /// <summary>
        /// 깊이
        /// </summary>
        public override int Depth { get; set; } = 3;

        #endregion
        #region 차원 - Dimension

        /// <summary>
        /// 차원
        /// </summary>
        public override int Dimension { get; set; } = 85;

        #endregion
        #region 스트라이드 배열 - StrideArray

        /// <summary>
        /// 스트라이드 배열
        /// </summary>
        public override float[] StrideArray { get; set; } = new float[] { 8, 16, 32, 64 };

        #endregion
        #region 앵커 배열 - AnchorArray

        /// <summary>
        /// 앵커 배열
        /// </summary>
        public override float[][][] AnchorArray { get; set; } = new float[][][]
        {
            new float[][] { new float[] { 019, 027 }, new float[] { 044, 040 }, new float[] { 038, 094 } },
            new float[][] { new float[] { 096, 068 }, new float[] { 086, 152 }, new float[] { 180, 137 } },
            new float[][] { new float[] { 140, 301 }, new float[] { 303, 264 }, new float[] { 238, 542 } },
            new float[][] { new float[] { 436, 615 }, new float[] { 739, 380 }, new float[] { 925, 792 } }
        };

        #endregion
        #region 도형 배열 - ShapeArray

        /// <summary>
        /// 도형 배열
        /// </summary>
        public override int[] ShapeArray { get; set; } = new int[] { 160, 80, 40, 20 };

        #endregion
        #region 신뢰도 - Confidence

        /// <summary>
        /// 신뢰도
        /// </summary>
        public override float Confidence { get; set; } = 0.20f;

        #endregion
        #region 다중 신뢰도 - MultipleConfidence

        /// <summary>
        /// 다중 신뢰도
        /// </summary>
        public override float MultipleConfidence { get; set; } = 0.25f;

        #endregion
        #region 오버랩 - Overlap

        /// <summary>
        /// 오버랩
        /// </summary>
        public override float Overlap { get; set; } = 0.45f;

        #endregion
        #region 출력 배열 - OutputArray

        /// <summary>
        /// 출력 배열
        /// </summary>
        public override string[] OutputArray { get; set; } = new[] { "output" };

        #endregion
        #region 레이블 리스트 - LabelList

        /// <summary>
        /// 레이블 리스트
        /// </summary>
        public override List<YOLOLabel> LabelList { get; set; } = new List<YOLOLabel>()
        {
            new YOLOLabel { ID = 1, Name = "person"          },
            new YOLOLabel { ID = 2, Name = "bicycle"         },
            new YOLOLabel { ID = 3, Name = "car"             },
            new YOLOLabel { ID = 4, Name = "motorcycle"      },
            new YOLOLabel { ID = 5, Name = "airplane"        },
            new YOLOLabel { ID = 6, Name = "bus"             },
            new YOLOLabel { ID = 7, Name = "train"           },
            new YOLOLabel { ID = 8, Name = "truck"           },
            new YOLOLabel { ID = 9, Name = "boat"            },
            new YOLOLabel { ID = 10, Name = "traffic light"  },
            new YOLOLabel { ID = 11, Name = "fire hydrant"   },
            new YOLOLabel { ID = 12, Name = "stop sign"      },
            new YOLOLabel { ID = 13, Name = "parking meter"  },
            new YOLOLabel { ID = 14, Name = "bench"          },
            new YOLOLabel { ID = 15, Name = "bird"           },
            new YOLOLabel { ID = 16, Name = "cat"            },
            new YOLOLabel { ID = 17, Name = "dog"            },
            new YOLOLabel { ID = 18, Name = "horse"          },
            new YOLOLabel { ID = 19, Name = "sheep"          },
            new YOLOLabel { ID = 20, Name = "cow"            },
            new YOLOLabel { ID = 21, Name = "elephant"       },
            new YOLOLabel { ID = 22, Name = "bear"           },
            new YOLOLabel { ID = 23, Name = "zebra"          },
            new YOLOLabel { ID = 24, Name = "giraffe"        },
            new YOLOLabel { ID = 25, Name = "backpack"       },
            new YOLOLabel { ID = 26, Name = "umbrella"       },
            new YOLOLabel { ID = 27, Name = "handbag"        },
            new YOLOLabel { ID = 28, Name = "tie"            },
            new YOLOLabel { ID = 29, Name = "suitcase"       },
            new YOLOLabel { ID = 30, Name = "frisbee"        },
            new YOLOLabel { ID = 31, Name = "skis"           },
            new YOLOLabel { ID = 32, Name = "snowboard"      },
            new YOLOLabel { ID = 33, Name = "sports ball"    },
            new YOLOLabel { ID = 34, Name = "kite"           },
            new YOLOLabel { ID = 35, Name = "baseball bat"   },
            new YOLOLabel { ID = 36, Name = "baseball glove" },
            new YOLOLabel { ID = 37, Name = "skateboard"     },
            new YOLOLabel { ID = 38, Name = "surfboard"      },
            new YOLOLabel { ID = 39, Name = "tennis racket"  },
            new YOLOLabel { ID = 40, Name = "bottle"         },
            new YOLOLabel { ID = 41, Name = "wine glass"     },
            new YOLOLabel { ID = 42, Name = "cup"            },
            new YOLOLabel { ID = 43, Name = "fork"           },
            new YOLOLabel { ID = 44, Name = "knife"          },
            new YOLOLabel { ID = 45, Name = "spoon"          },
            new YOLOLabel { ID = 46, Name = "bowl"           },
            new YOLOLabel { ID = 47, Name = "banana"         },
            new YOLOLabel { ID = 48, Name = "apple"          },
            new YOLOLabel { ID = 49, Name = "sandwich"       },
            new YOLOLabel { ID = 50, Name = "orange"         },
            new YOLOLabel { ID = 51, Name = "broccoli"       },
            new YOLOLabel { ID = 52, Name = "carrot"         },
            new YOLOLabel { ID = 53, Name = "hot dog"        },
            new YOLOLabel { ID = 54, Name = "pizza"          },
            new YOLOLabel { ID = 55, Name = "donut"          },
            new YOLOLabel { ID = 56, Name = "cake"           },
            new YOLOLabel { ID = 57, Name = "chair"          },
            new YOLOLabel { ID = 58, Name = "couch"          },
            new YOLOLabel { ID = 59, Name = "potted plant"   },
            new YOLOLabel { ID = 60, Name = "bed"            },
            new YOLOLabel { ID = 61, Name = "dining table"   },
            new YOLOLabel { ID = 62, Name = "toilet"         },
            new YOLOLabel { ID = 63, Name = "tv"             },
            new YOLOLabel { ID = 64, Name = "laptop"         },
            new YOLOLabel { ID = 65, Name = "mouse"          },
            new YOLOLabel { ID = 66, Name = "remote"         },
            new YOLOLabel { ID = 67, Name = "keyboard"       },
            new YOLOLabel { ID = 68, Name = "cell phone"     },
            new YOLOLabel { ID = 69, Name = "microwave"      },
            new YOLOLabel { ID = 70, Name = "oven"           },
            new YOLOLabel { ID = 71, Name = "toaster"        },
            new YOLOLabel { ID = 72, Name = "sink"           },
            new YOLOLabel { ID = 73, Name = "refrigerator"   },
            new YOLOLabel { ID = 74, Name = "book"           },
            new YOLOLabel { ID = 75, Name = "clock"          },
            new YOLOLabel { ID = 76, Name = "vase"           },
            new YOLOLabel { ID = 77, Name = "scissors"       },
            new YOLOLabel { ID = 78, Name = "teddy bear"     },
            new YOLOLabel { ID = 79, Name = "hair drier"     },
            new YOLOLabel { ID = 80, Name = "toothbrush"     }
        };

        #endregion
        #region 탐지 사용 여부 - UseDetect

        /// <summary>
        /// 탐지 사용 여부
        /// </summary>
        public override bool UseDetect { get; set; } = true;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - YOLOCOCOP6Model()

        /// <summary>
        /// 생성자
        /// </summary>
        public YOLOCOCOP6Model()
        {
        }

        #endregion
    }
}

 

▶ YOLOLabelKind.cs

namespace TestProject
{
    /// <summary>
    /// YOLO 레이블 종류
    /// </summary>
    public enum YOLOLabelKind
    {
        /// <summary>
        /// 일반
        /// </summary>
        Generic
    }
}

 

▶ YOLOLabel.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// YOLO 레이블
    /// </summary>
    public class YOLOLabel
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region ID - ID

        /// <summary>
        /// ID
        /// </summary>
        public int ID { get; set; }

        #endregion
        #region 명칭 - Name

        /// <summary>
        /// 명칭
        /// </summary>
        public string Name { get; set; }

        #endregion
        #region 종류 - Kind

        /// <summary>
        /// YOLO 레이블 종류
        /// </summary>
        public YOLOLabelKind Kind { get; set; }

        #endregion
        #region 색상 - Color

        /// <summary>
        /// 색상
        /// </summary>
        public Color Color { get; set; }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - YOLOLabel()

        /// <summary>
        /// 생성자
        /// </summary>
        public YOLOLabel()
        {
            Color = Color.Yellow;
        }

        #endregion
    }
}

 

▶ YOLOPrediction.cs

using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// YOLO 예측
    /// </summary>
    public class YOLOPrediction
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 레이블 - Label

        /// <summary>
        /// 레이블
        /// </summary>
        public YOLOLabel Label { get; set; }

        #endregion
        #region 사각형 - Rectangle

        /// <summary>
        /// 사각형
        /// </summary>
        public RectangleF Rectangle { get; set; }

        #endregion
        #region 점수 - Score

        /// <summary>
        /// 점수
        /// </summary>
        public float Score { get; set; }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - YOLOPrediction()

        /// <summary>
        /// 생성자
        /// </summary>
        public YOLOPrediction()
        {
        }

        #endregion
        #region 생성자 - YOLOPrediction(label)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="label">레이블</param>
        public YOLOPrediction(YOLOLabel label)
        {
            Label = label;
        }

        #endregion
        #region 생성자 - YOLOPrediction(label, confidence)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="label">레이블</param>
        /// <param name="confidence">신뢰도</param>
        public YOLOPrediction(YOLOLabel label, float confidence) : this(label)
        {
            Score = confidence;
        }

        #endregion
    }
}

 

▶ YOLOScorer.cs

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;

namespace TestProject
{
    /// <summary>
    /// YOLO 채점기
    /// </summary>
    public class YOLOScorer<T> : IDisposable where T : YOLOModel
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 모델
        /// </summary>
        private readonly T model;

        /// <summary>
        /// 추론 세션
        /// </summary>
        private readonly InferenceSession inferenceSession;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - YOLOScorer()

        /// <summary>
        /// 생성자
        /// </summary>
        public YOLOScorer()
        {
            this.model = Activator.CreateInstance<T>();
        }

        #endregion
        #region 생성자 - YOLOScorer(filePath, options)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="filePath">파일 경로</param>
        /// <param name="options">옵션</param>
        public YOLOScorer(string filePath, SessionOptions options = null) : this()
        {
            this.inferenceSession = new InferenceSession(File.ReadAllBytes(filePath), options ?? new SessionOptions());
        }

        #endregion
        #region 생성자 - YOLOScorer(stream, options)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="stream">스트림</param>
        /// <param name="options">옵션</param>
        public YOLOScorer(Stream stream, SessionOptions options = null) : this()
        {
            using(BinaryReader reader = new BinaryReader(stream))
            {
                this.inferenceSession = new InferenceSession(reader.ReadBytes((int)stream.Length), options ?? new SessionOptions());
            }
        }

        #endregion
        #region 생성자 - YOLOScorer(weightByteArray, options)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="weightByteArray">가중치 바이트 배열</param>
        /// <param name="options">옵션</param>
        public YOLOScorer(byte[] weightByteArray, SessionOptions options = null) : this()
        {
            this.inferenceSession = new InferenceSession(weightByteArray, options ?? new SessionOptions());
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 예측하기 - Predict(image)

        /// <summary>
        /// 예측하기
        /// </summary>
        /// <param name="image">이미지</param>
        /// <returns>예측하기</returns>
        public List<YOLOPrediction> Predict(Image image)
        {
            return Supress(ParseOutput(Inference(image), image));
        }

        #endregion
        #region 리소스 해제하기 - Dispose()

        /// <summary>
        /// 리소스 해제하기
        /// </summary>
        public void Dispose()
        {
            this.inferenceSession.Dispose();
        }

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region 크기 변경 비트맵 구하기 - GetResizeBitmap(image)

        /// <summary>
        /// 크기 변경 비트맵 구하기
        /// </summary>
        /// <param name="image">이미지</param>
        /// <returns>크기 변경 비트맵</returns>
        private Bitmap GetResizeBitmap(Image image)
        {
            PixelFormat pixelFormat = image.PixelFormat;

            Bitmap bitmap = new Bitmap(this.model.Width, this.model.Height, pixelFormat);

            using(Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.Clear(Color.FromArgb(0, 0, 0, 0));

                var (widthRatio, heightRatio) = (this.model.Width / (float)image.Width, this.model.Height / (float)image.Height);

                float ratio = Math.Min(widthRatio, heightRatio);

                var (width, height) = ((int)(image.Width * ratio), (int)(image.Height * ratio));

                var (x, y) = ((this.model.Width / 2) - (width / 2), (this.model.Height / 2) - (height / 2));

                graphics.DrawImage(image, new Rectangle(x, y, width, height));
            }

            return bitmap;
        }

        #endregion
        #region 픽셀 추출하기 - ExtractPixels(image)

        /// <summary>
        /// 픽셀 추출하기
        /// </summary>
        /// <param name="image">이미지</param>
        /// <returns>텐서</returns>
        private Tensor<float> ExtractPixels(Image image)
        {
            Bitmap bitmap = new Bitmap(image);

            Rectangle rectangle = new Rectangle(0, 0, image.Width, image.Height);

            BitmapData bitmapData = bitmap.LockBits(rectangle, ImageLockMode.ReadOnly, image.PixelFormat);

            DenseTensor<float> tensor = new DenseTensor<float>(new[] { 1, 3, image.Height, image.Width });

            unsafe
            {
                for(int y = 0; y < bitmapData.Height; y++)
                {
                    byte* pointer = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride);

                    for(int x = 0; x < bitmapData.Width; x++)
                    {
                        tensor[0, 0, y, x] = pointer[x * 3 + 0] / 255.0f;
                        tensor[0, 1, y, x] = pointer[x * 3 + 1] / 255.0f;
                        tensor[0, 2, y, x] = pointer[x * 3 + 2] / 255.0f;
                    }
                }

                bitmap.UnlockBits(bitmapData);
            }

            return tensor;
        }

        #endregion
        #region 추론하기 - Inference(image)

        /// <summary>
        /// 추론하기
        /// </summary>
        /// <param name="image">이미지</param>
        /// <returns>밀집 텐서 배열</returns>
        private DenseTensor<float>[] Inference(Image image)
        {
            Bitmap resizedBitmap = null;

            if(image.Width != this.model.Width || image.Height != this.model.Height)
            {
                resizedBitmap = GetResizeBitmap(image);
            }

            List<NamedOnnxValue> inputList = new List<NamedOnnxValue>
            {
                NamedOnnxValue.CreateFromTensor("images", ExtractPixels(resizedBitmap ?? image))
            };

            IDisposableReadOnlyCollection<DisposableNamedOnnxValue> resultCollection = this.inferenceSession.Run(inputList);

            List<DenseTensor<float>> outputList = new List<DenseTensor<float>>();

            foreach(string output in this.model.OutputArray)
            {
                outputList.Add(resultCollection.First(x => x.Name == output).Value as DenseTensor<float>);
            };

            return outputList.ToArray();
        }

        #endregion
        #region 탐지 파싱하기 - ParseDetect(outputTensor, image)

        /// <summary>
        /// 탐지 파싱하기
        /// </summary>
        private List<YOLOPrediction> ParseDetect(DenseTensor<float> outputTensor, Image image)
        {
            List<YOLOPrediction> resultList = new List<YOLOPrediction>();

            var (xGain, yGain) = (this.model.Width / (float)image.Width, this.model.Height / (float)image.Height);

            float gain = Math.Min(xGain, yGain);

            var (xPadding, yPadding) = ((this.model.Width - image.Width * gain) / 2, (this.model.Height - image.Height * gain) / 2);

            for(int i = 0; i < outputTensor.Length / this.model.Dimension; i++)
            {
                if(outputTensor[0, i, 4] <= this.model.Confidence)
                {
                    continue;
                }

                for(int j = 5; j < this.model.Dimension; j++)
                {
                    outputTensor[0, i, j] = outputTensor[0, i, j] * outputTensor[0, i, 4];
                }

                for(int k = 5; k < this.model.Dimension; k++)
                {
                    if(outputTensor[0, i, k] <= this.model.MultipleConfidence)
                    {
                        continue;
                    }

                    float xMinimum = ((outputTensor[0, i, 0] - outputTensor[0, i, 2] / 2) - xPadding) / gain;
                    float yMinimum = ((outputTensor[0, i, 1] - outputTensor[0, i, 3] / 2) - yPadding) / gain;
                    float xMaximum = ((outputTensor[0, i, 0] + outputTensor[0, i, 2] / 2) - xPadding) / gain;
                    float yMaximum = ((outputTensor[0, i, 1] + outputTensor[0, i, 3] / 2) - yPadding) / gain;

                    xMinimum = Clamp(xMinimum, 0, image.Width );
                    yMinimum = Clamp(yMinimum, 0, image.Height);
                    xMaximum = Clamp(xMaximum, 0, image.Width );
                    yMaximum = Clamp(yMaximum, 0, image.Height);

                    YOLOLabel label = this.model.LabelList[k - 5];

                    YOLOPrediction prediction = new YOLOPrediction(label, outputTensor[0, i, k])
                    {
                        Rectangle = new RectangleF(xMinimum, yMinimum, xMaximum - xMinimum, yMaximum - yMinimum)
                    };

                    resultList.Add(prediction);
                }
            }

            return resultList;
        }

        #endregion
        #region XYXY 배열 구하기 - GetXYXYArray(sourceArray)

        /// <summary>
        /// XYXY 배열 구하기
        /// </summary>
        /// <param name="sourceArray">소스 배열</param>
        /// <returns>XYXY 배열</returns>
        /// <remarks>xywh bbox 형식을 xyxy로 변환한다.</remarks>
        private float[] GetXYXYArray(float[] sourceArray)
        {
            float[] targetArray = new float[4];

            targetArray[0] = sourceArray[0] - sourceArray[2] / 2f;
            targetArray[1] = sourceArray[1] - sourceArray[3] / 2f;
            targetArray[2] = sourceArray[0] + sourceArray[2] / 2f;
            targetArray[3] = sourceArray[1] + sourceArray[3] / 2f;

            return targetArray;
        }

        #endregion
        #region 범위 내 자르기 - Clamp(value, minimumValue, maximumValue)

        /// <summary>
        /// 범위 내 자르기
        /// </summary>
        /// <param name="value">값</param>
        /// <param name="minimumValue">최소값</param>
        /// <param name="maximumValue">최대값</param>
        /// <returns>값</returns>
        public float Clamp(float value, float minimumValue, float maximumValue)
        {
            return (value < minimumValue) ? minimumValue : (value > maximumValue) ? maximumValue : value;
        }

        #endregion
        #region 시그모이드 구하기 - GetSigmoid(value)

        /// <summary>
        /// 시그모이드 구하기
        /// </summary>
        /// <param name="value">값</param>
        /// <returns>시그모이드</returns>
        private float GetSigmoid(float value)
        {
            return 1 / (1 + (float)Math.Exp(-value));
        }

        #endregion
        #region 시그모이드 파싱하기 - ParseSigmoid(outputTensor, image)

        /// <summary>
        /// 시그모이드 파싱하기
        /// </summary>
        /// <param name="outputTensor">출력 텐서</param>
        /// <param name="image">이미지</param>
        /// <returns>예측 리스트</returns>
        private List<YOLOPrediction> ParseSigmoid(DenseTensor<float>[] outputTensor, Image image)
        {
            List<YOLOPrediction> resultList = new List<YOLOPrediction>();

            var (xGain, yGain) = (this.model.Width / (float)image.Width, this.model.Height / (float)image.Height);

            float gain = Math.Min(xGain, yGain);

            var (xPadding, yPadding) = ((this.model.Width - image.Width * gain) / 2, (this.model.Height - image.Height * gain) / 2);

            for(int i = 0; i < outputTensor.Length; i++)
            {
                int shapeCount = this.model.ShapeArray[i];

                for(int j = 0; j < this.model.AnchorArray.Length; j++)
                {
                    for(int y = 0; y < shapeCount; y++)
                    {
                        for(int x = 0; x < shapeCount; x++)
                        {
                            int offset = (shapeCount * shapeCount * j + shapeCount * y + x) * this.model.Dimension;

                            float[] bufferArray = outputTensor[i].Skip(offset).Take(this.model.Dimension).Select(GetSigmoid).ToArray();

                            float objectConfidence = bufferArray[4];

                            if(objectConfidence < this.model.Confidence)
                            {
                                continue;
                            }

                            List<float> scoreList = bufferArray.Skip(5).Select(b => b * objectConfidence).ToList();

                            float multipleConfidence = scoreList.Max();

                            if(multipleConfidence <= this.model.MultipleConfidence)
                            {
                                continue;
                            }

                            float rawX = (bufferArray[0] * 2 - 0.5f + x) * this.model.StrideArray[i];
                            float rawY = (bufferArray[1] * 2 - 0.5f + y) * this.model.StrideArray[i];

                            float rawWidth  = (float)Math.Pow(bufferArray[2] * 2, 2) * this.model.AnchorArray[i][j][0];
                            float rawHeight = (float)Math.Pow(bufferArray[3] * 2, 2) * this.model.AnchorArray[i][j][1];

                            float[] xyxyArray = GetXYXYArray(new float[] { rawX, rawY, rawWidth, rawHeight });

                            float xMinimum = Clamp((xyxyArray[0] - xPadding) / gain, 0, image.Width );
                            float yMinimum = Clamp((xyxyArray[1] - yPadding) / gain, 0, image.Height);
                            float xMaximum = Clamp((xyxyArray[2] - xPadding) / gain, 0, image.Width );
                            float yMaximum = Clamp((xyxyArray[3] - yPadding) / gain, 0, image.Height);

                            YOLOLabel label = this.model.LabelList[scoreList.IndexOf(multipleConfidence)];

                            YOLOPrediction prediction = new YOLOPrediction(label, multipleConfidence)
                            {
                                Rectangle = new RectangleF(xMinimum, yMinimum, xMaximum - xMinimum, yMaximum - yMinimum)
                            };

                            resultList.Add(prediction);
                        }
                    }
                }
            }

            return resultList;
        }

        #endregion
        #region 출력 파싱하기 - ParseOutput(outputTenserArray, image)

        /// <summary>
        /// 출력 파싱하기
        /// </summary>
        /// <param name="outputTenserArray">출력 텐서 배열</param>
        /// <param name="image">이미지</param>
        /// <returns>예측 리스트</returns>
        private List<YOLOPrediction> ParseOutput(DenseTensor<float>[] outputTenserArray, Image image)
        {
            return this.model.UseDetect ? ParseDetect(outputTenserArray[0], image) : ParseSigmoid(outputTenserArray, image);
        }

        #endregion
        #region 억제하기 - Supress(sourceList)

        /// <summary>
        /// 억제하기
        /// </summary>
        /// <param name="sourceList">소스 리스트</param>
        /// <returns>억제 리스트</returns>
        private List<YOLOPrediction> Supress(List<YOLOPrediction> sourceList)
        {
            List<YOLOPrediction> targetList = new List<YOLOPrediction>(sourceList);

            foreach(YOLOPrediction source in sourceList)
            {
                foreach(YOLOPrediction target in targetList.ToList())
                {
                    if(target == source)
                    {
                        continue;
                    }

                    var (rectangle1, rectangle2) = (source.Rectangle, target.Rectangle);

                    RectangleF intersectionRectangle = RectangleF.Intersect(rectangle1, rectangle2);

                    float intesectionArea = intersectionRectangle.GetArea();
                    float unionArea       = rectangle1.GetArea() + rectangle2.GetArea() - intesectionArea;
                    float overlap         = intesectionArea / unionArea;

                    if(overlap > this.model.Overlap)
                    {
                        if(source.Score > target.Score)
                        {
                            targetList.Remove(target);
                        }
                    }
                }
            }

            return targetList;
        }

        #endregion
    }
}

 

▶ Program.cs

using System;
using System.Collections.Generic;
using System.Drawing;

namespace TestProject
{
    /// <summary>
    /// 프로그램
    /// </summary>
    class Program
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 프로그램 시작하기 - Main()

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        private static void Main()
        {
            using Image image = Image.FromFile("IMAGE//source.jpg");

          //using YOLOScorer<YOLOCOCOP5Model> scorer = new YOLOScorer<YOLOCOCOP5Model>("ASSET/yolov5s.onnx");
            using YOLOScorer<YOLOCOCOP6Model> scorer = new YOLOScorer<YOLOCOCOP6Model>("ASSET/yolov5s6.onnx");

            List<YOLOPrediction> predictionList = scorer.Predict(image);

            using Graphics graphics = Graphics.FromImage(image);

            foreach(YOLOPrediction prediction in predictionList)
            {
                double score = Math.Round(prediction.Score, 2);

                graphics.DrawRectangles(new Pen(prediction.Label.Color, 1), new[] { prediction.Rectangle });

                var (x, y) = (prediction.Rectangle.X - 3, prediction.Rectangle.Y - 23);

                graphics.DrawString
                (
                    $"{prediction.Label.Name} ({score})",
                    new Font("Consolas", 16, GraphicsUnit.Pixel),
                    new SolidBrush(prediction.Label.Color),
                    new PointF(x, y)
                );
            }

            image.Save("d:\\result.jpg");
        }

        #endregion
    }
}
728x90
반응형
그리드형
Posted by 사용자 icodebroker

댓글을 달아 주세요