AoiMarkMethod.cs 5.2 KB
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenCvSharp;
using OpenCvSharp.XFeatures2D;

namespace AOI
{
    /// <summary>
    /// 从搜索区域中查找Mark区域,对图片进行校准
    /// </summary>
    public class AoiMarkMethod : AoiMethod
    {
        /// <summary>
        /// 搜索区域路径
        /// </summary>
        public GraphicsPath SearchPath;

        public override ResultBean Check(Image standardImage, Image imageToCheck)
        {
            ResultBean resultBean = new ResultBean();
            resultBean.standardRoiImage = standardImage;
            bool needCut = false;
            //标准图中的Mart区域
            Image markImage = GetRoiImage(standardImage, RoiPath, needCut);
            //搜索区域
            Image searchImage = GetRoiImage(imageToCheck, SearchPath, needCut);
            if (markImage != null && searchImage != null)
            {
                var affine = GetAffineMat(markImage, searchImage);
                if(affine != null)
                {
                    var matToCheck = ImageUtil.ToMat(imageToCheck);
                    var fixedMat =  FixImage(affine, matToCheck);
                    resultBean.result = true;
                    resultBean.currentRoiImage = ImageUtil.ToImage(fixedMat);
                }
            }
            return resultBean;
        }

        /// <summary>
        /// 校准图片
        /// </summary>
        /// <param name="affineMat"></param>
        /// <param name="srcMat"></param>
        /// <returns></returns>
        private Mat FixImage(Mat affineMat, Mat srcMat)
        {
            Mat resultMat = new Mat();
            Cv2.WarpAffine(srcMat, resultMat, affineMat, srcMat.Size());
            return resultMat;
        }
        /// <summary>
        /// 获取映射距阵
        /// </summary>
        /// <param name="markImage"></param>
        /// <param name="srcImage"></param>
        /// <returns></returns>
        private Mat GetAffineMat(Image markImage, Image srcImage)
        {
            Mat markMat = ImageUtil.ToMat(new Bitmap(markImage));
            Mat originalMat = ImageUtil.ToMat(new Bitmap(srcImage));
            Mat srcMat = new Mat();
            //灰度图转换
            Cv2.CvtColor(markMat, markMat, ColorConversionCodes.RGB2GRAY);
            Cv2.CvtColor(originalMat, srcMat, ColorConversionCodes.RGB2GRAY);

            //提取特征点
            SIFT sift = SIFT.Create(200);
            KeyPoint[] markKeyPoints, srcKeyPoints;
            MatOfFloat roiDescriptors = new MatOfFloat();
            MatOfFloat srcDescriptors = new MatOfFloat();
            sift.DetectAndCompute(markMat, null, out markKeyPoints, roiDescriptors);
            sift.DetectAndCompute(srcMat, null, out srcKeyPoints, srcDescriptors);

            var flannMatcher = new FlannBasedMatcher();
            DMatch[] matchePoints = flannMatcher.Match(srcDescriptors, roiDescriptors);
            //提取强特征点
            double minMatch = 1;
            double maxMatch = 0;
            for (int i = 0; i < matchePoints.Length; i++)
            {
                double distance = matchePoints[i].Distance;
                //匹配值最大最小值获取
                if (distance < minMatch)
                {
                    minMatch = distance;
                }
                if (distance > maxMatch)
                {
                    maxMatch = distance;
                }
            }

            List<DMatch> goodMatchePoints = new List<DMatch>();
            for (int i = 0; i < matchePoints.Length; i++)
            {
                if (matchePoints[i].Distance < minMatch + (maxMatch - minMatch) / 4)
                {
                    goodMatchePoints.Add(matchePoints[i]);
                }
            }
            //获取排在前N个的最优匹配特征点
            int num = goodMatchePoints.Count;
            if (num >= 3)
            {
                num = 3;
            }
            else
            {
                //不匹配
                return null;
            }
            List<Point2f> markPoints = new List<Point2f>();
            List<Point2f> srcPoints = new List<Point2f>();
            goodMatchePoints.Sort((left, right) =>
            {
                if (left.Distance > right.Distance)
                    return 1;
                else if (left.Distance == right.Distance)
                    return 0;
                else
                    return -1;
            });

            //Mat matchMat = new Mat();
            //Cv2.DrawMatches(srcMat, srcKeyPoints, markMat, roiKeyPoints, goodMatchePoints.Take(num), matchMat);
            //Cv2.ImShow("Match", matchMat);

            for (int i = 0; i < num; i++)
            {
                srcPoints.Add(srcKeyPoints[goodMatchePoints[i].QueryIdx].Pt);
                markPoints.Add(markKeyPoints[goodMatchePoints[i].TrainIdx].Pt);
            }

            //获取图像1到图像2的投影映射矩阵 尺寸为3*3
            Mat affineMat = Cv2.GetAffineTransform(srcPoints, markPoints);
            return affineMat;
        }
    }
}