Newer
Older
CaptureEye / AssessEye / Assess.cs
yxw on 14 Aug 2020 17 KB first commt
using OpenCvSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using CaptureEye;
using Point = OpenCvSharp.Point;
using System.Windows.Forms;

namespace AssessEye
{
    public class AssessEye
    {
        // 虹膜清晰度权重
        double sharpnessWeight = 0.5;
        // 虹膜半径权重
        double radiusWeight = 0.1;
        // 虹膜有效区域权重
        double areaWeight = 0.2;
        // 虹膜对比度权重
        double constrastWeight = 0.2;

        //////////////////////////
        ///*** 程序主入口点 ***///
        //////////////////////////
        public double M_AssessEye(Bitmap bitmap, EyeParams eyeParams)
        {
            Mat FaceImage = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap);

            // 有效虹膜区域
            double usable_iris_area = eyeParams.Hm_Effect_Area;

            if (usable_iris_area == 0)
            {
                MessageBox.Show("虹膜质量打分:" + 0 + "\r\n有效区域不满足要求", "提示");
                return 0;
            }

            //清晰度
            double sharpness = SharpnessArea(FaceImage, eyeParams);

            // 虹膜-巩膜对比度
            double iris_sclera_constrast = Iris_Sclera_Constrast(FaceImage, eyeParams);

            // 虹膜-瞳孔对比度
            double iris_pupil_constrast = Iris_Pupil_Constrast(FaceImage, eyeParams);

            // 虹膜半径
            int hm_radius = eyeParams.Hm_radius;

            // 质量评分
            double assess_score = Assess_Score(sharpness, hm_radius, usable_iris_area, iris_sclera_constrast, iris_pupil_constrast);


            MessageBox.Show("虹膜质量打分:" + assess_score + "\r\n清晰度:" +
                sharpness + "\r\n半径:" + hm_radius + "\r\n有效区域:" + usable_iris_area +
                "\r\n虹膜巩膜对比度:" + iris_sclera_constrast + "\r\n虹膜瞳孔对比度:" + iris_pupil_constrast, "提示");

            // 返回质量评分结果
            return assess_score;
            //return 0.0;
        }

        //////////////////////////////
        ///*** 虹膜-巩膜对比度 ***////
        //////////////////////////////
        unsafe double Iris_Sclera_Constrast(Mat FaceImage, EyeParams eyeParams)
        {

            ArrayList irisList = new ArrayList(); // 虹膜像素
            ArrayList scleraList = new ArrayList(); // 巩膜像素
            ArrayList pupilList = new ArrayList(); // 瞳孔像素
            int cols = FaceImage.Cols;
            int rows = FaceImage.Rows;
            int minRow = eyeParams.Tk_row - eyeParams.Tk_radius;
            int maxRow = eyeParams.Tk_row + eyeParams.Tk_radius;

            // 巩膜像素范围(环形)
            // 以虹膜-巩膜边界的半径为1,选中圆形(内半径1.1,外半径1.2)中所有未被遮挡的像素
            Mat scleraTemp = new Mat(rows, cols, MatType.CV_8UC1, new Scalar(0, 0, 0)); // 复制一张黑色图片
            Cv2.Circle(scleraTemp, eyeParams.Hm_col, eyeParams.Hm_row, (int)(eyeParams.Hm_radius * 1.2), new Scalar(255, 255, 255), -1); // 画白色一个实心圆
            Cv2.Circle(scleraTemp, eyeParams.Hm_col, eyeParams.Hm_row, (int)(eyeParams.Hm_radius * 1.1), new Scalar(0, 0, 0), -1); // 画一个黑色实心圆

            int circle_row;
            int circle_col;
            int circle_raduis;
            iris_pupil_circle(eyeParams, out circle_row, out circle_col, out circle_raduis);

            // 虹膜像素范围(环形)
            // 圆形外半径为0.9,内半径延伸至两个边界未被遮挡部分的中点
            Mat irisTemp = new Mat(rows, cols, MatType.CV_8UC1, new Scalar(0, 0, 0)); // 复制一张黑色图片
            Cv2.Circle(irisTemp, eyeParams.Hm_col, eyeParams.Hm_row, (int)(eyeParams.Hm_radius * 0.9), new Scalar(255, 255, 255), -1); // 画白色一个实心圆
            Cv2.Circle(irisTemp, circle_col, circle_row, circle_raduis, new Scalar(0, 0, 0), -1); // 画一个黑色实心圆


            // 瞳孔像素范围(圆形)
            // 以虹膜-瞳孔边界半径为1,选中半径为0.8的圆形中所有未被遮挡的像素
            Mat pupilTemp = new Mat(rows, cols, MatType.CV_8UC1, new Scalar(0, 0, 0)); // 复制一张黑色图片
            Cv2.Circle(pupilTemp, eyeParams.Tk_col, eyeParams.Tk_row, (int)(eyeParams.Tk_radius * 0.8), new Scalar(255, 255, 255), -1); // 画白色一个实心圆

            // 获取各个范围中的像素值(只取瞳孔边界以下的区域)
            for (int i = minRow; i <= maxRow; i++)//行循环
            {
                byte* facedata = (byte*)FaceImage.Ptr(i).ToPointer(); //获取第i行的首地址
                byte* scleradata = (byte*)scleraTemp.Ptr(i).ToPointer();
                byte* irisdata = (byte*)irisTemp.Ptr(i).ToPointer();
                byte* pupildata = (byte*)pupilTemp.Ptr(i).ToPointer();
                for (int j = 0; j < cols; j++)//列循环
                {
                    if (255 == scleradata[j])
                    {
                        scleradata[j] = 150;
                        scleraList.Add(facedata[j]);
                    }
                    if (255 == irisdata[j])
                    {
                        irisdata[j] = 150;
                        irisList.Add(facedata[j]);
                    }
                    if (255 == pupildata[j])
                    {
                        pupildata[j] = 150;
                        pupilList.Add(facedata[j]);
                    }

                }
            }

            // 排序,取像素中值
            scleraList.Sort();
            irisList.Sort();
            pupilList.Sort();
            byte sclear_value = (byte)scleraList[scleraList.Count / 2];
            byte iris_value = (byte)irisList[irisList.Count / 2];
            byte pupil_value = (byte)pupilList[pupilList.Count / 2];
            // 取平均值

            double constrast = 0.0;
            if (iris_value >= pupil_value)
            {
                constrast = System.Math.Abs(sclear_value - iris_value) * 100 / (sclear_value + iris_value - 2 * pupil_value);
            }
            //Console.WriteLine("iris_sclera_constrast: " + constrast + ", sclear_value:" + sclear_value + ", iris_value:" + iris_value + ", pupil_value:" + pupil_value);
            return constrast;
        }

        //////////////////////////////
        ///*** 虹膜-瞳孔对比度 ***////
        //////////////////////////////
        unsafe double Iris_Pupil_Constrast(Mat FaceImage, EyeParams eyeParams)
        {

            ArrayList irisList = new ArrayList(); // 虹膜像素
            ArrayList pupilList = new ArrayList(); // 瞳孔像素
            int rows = FaceImage.Rows;
            int cols = FaceImage.Cols;
            int minRow = eyeParams.Tk_row - eyeParams.Tk_radius;
            int maxRow = eyeParams.Tk_row + eyeParams.Tk_radius;

            // 瞳孔像素范围(圆形)
            // 以虹膜-瞳孔边界半径为1,选中半径为0.8的圆形中所有未被遮挡的像素
            Mat pupilTemp = new Mat(rows, cols, MatType.CV_8UC1, new Scalar(0, 0, 0)); // 复制一张黑色图片
            Cv2.Circle(pupilTemp, eyeParams.Tk_col, eyeParams.Tk_row, (int)(eyeParams.Tk_radius * 0.8), new Scalar(255, 255, 255), -1); // 画白色一个实心圆

            int circle_row;
            int circle_col;
            int circle_raduis;
            iris_pupil_circle(eyeParams, out circle_row, out circle_col, out circle_raduis);

            // 虹膜像素范围(环形)
            // 圆形内半径为1.1,外半径延伸至两个边界未被遮挡部分的中点
            Mat irisTemp = new Mat(rows, cols, MatType.CV_8UC1, new Scalar(0, 0, 0)); // 复制一张黑色图片
            Cv2.Circle(irisTemp, circle_col, circle_row, circle_raduis, new Scalar(255, 255, 255), -1); // 画白色一个实心圆
            Cv2.Circle(irisTemp, eyeParams.Tk_col, eyeParams.Tk_row, (int)(eyeParams.Tk_radius * 1.1), new Scalar(0, 0, 0), -1); // 画黑色一个实心圆

            // 获取各个范围中的像素值(只取瞳孔边界以下的区域)
            for (int i = minRow; i <= maxRow; i++)//行循环
            {
                byte* facedata = (byte*)FaceImage.Ptr(i).ToPointer(); //获取第i行的首地址
                byte* irisdata = (byte*)irisTemp.Ptr(i).ToPointer();
                byte* pupildata = (byte*)pupilTemp.Ptr(i).ToPointer();
                for (int j = 0; j < cols; j++)//列循环
                {
                    if (255 == irisdata[j])
                    {
                        irisdata[j] = 150;
                        irisList.Add(facedata[j]);
                    }
                    if (255 == pupildata[j])
                    {
                        pupildata[j] = 150;
                        pupilList.Add(facedata[j]);
                    }

                }
            }

            // 排序,取像素中值
            irisList.Sort();
            pupilList.Sort();
            byte iris_value = (byte)irisList[irisList.Count / 2];
            byte pupil_value = (byte)pupilList[pupilList.Count / 2];
            // 取平均值

            double weber_ratio = (double)System.Math.Abs(iris_value - pupil_value) / (20 + pupil_value);
            double constrast = weber_ratio * 100 / (0.75 + weber_ratio);
            //Console.WriteLine("iris_sclera_constrast: " + constrast + ", iris_value:" + iris_value + ", pupil_value:" + pupil_value);

            return constrast;
            // return 0.0;
        }

        // 计算两点之间距离
        public double Distance(int x1, int y1, int x2, int y2)
        {
            return System.Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
        }

        // 以虹膜-巩膜,虹膜-瞳孔之间间距的中点,绘制圆,计算圆的圆心和半径
        public void iris_pupil_circle(EyeParams eyeParams, out int circle_row, out int circle_col, out int circle_raduis)
        {
            double distance = Distance(eyeParams.Hm_row, eyeParams.Hm_col, eyeParams.Tk_row, eyeParams.Tk_col);
            if (distance == 0)
            {
                circle_row = eyeParams.Hm_row;
                circle_col = eyeParams.Hm_col;
                circle_raduis = (int)((eyeParams.Hm_radius + eyeParams.Tk_radius) * 0.5);
            }
            else
            {
                int middle1_row;
                int middle1_col;
                int middle2_row;
                int middle2_col;
                if (eyeParams.Hm_row == eyeParams.Tk_row)
                {
                    middle1_row = eyeParams.Tk_row;
                    middle2_row = eyeParams.Tk_row;

                    middle1_col = ((eyeParams.Hm_col + eyeParams.Hm_radius) + (eyeParams.Tk_col + eyeParams.Tk_radius)) / 2;
                    middle2_col = ((eyeParams.Hm_col - eyeParams.Hm_radius) + (eyeParams.Tk_col - eyeParams.Tk_radius)) / 2;

                }
                else if (eyeParams.Hm_col == eyeParams.Tk_col)
                {
                    middle1_col = eyeParams.Tk_col;
                    middle2_col = eyeParams.Tk_col;
                    middle1_row = ((eyeParams.Hm_row + eyeParams.Hm_radius) + (eyeParams.Tk_row + eyeParams.Tk_radius)) / 2;
                    middle2_row = ((eyeParams.Hm_row - eyeParams.Hm_radius) + (eyeParams.Tk_row - eyeParams.Tk_radius)) / 2;

                }
                else
                {
                    middle1_row = (int)(eyeParams.Hm_row + (eyeParams.Hm_radius + eyeParams.Tk_radius + distance) * (eyeParams.Tk_row - eyeParams.Hm_row) / (2 * distance));
                    middle1_col = (int)(eyeParams.Hm_col + (eyeParams.Hm_radius + eyeParams.Tk_radius + distance) * (eyeParams.Tk_col - eyeParams.Hm_col) / (2 * distance));

                    middle2_row = (int)(eyeParams.Hm_row - (eyeParams.Hm_radius - eyeParams.Tk_radius + distance) * (eyeParams.Tk_row - eyeParams.Hm_row) / (2 * distance));
                    middle2_col = (int)(eyeParams.Hm_col - (eyeParams.Hm_radius - eyeParams.Tk_radius + distance) * (eyeParams.Tk_col - eyeParams.Hm_col) / (2 * distance));

                }

                circle_row = (middle1_row + middle2_row) / 2;
                circle_col = (middle1_col + middle2_col) / 2;
                circle_raduis = (int)Distance(circle_row, circle_col, middle1_row, middle1_col);
            }
        }

        public int average(ArrayList list)
        {
            if (list.Count == 0)
            {
                return 0;
            }
            int sum = 0;
            foreach (byte item in list)
            {
                sum += item;
            }
            return sum / list.Count;
        }

        ////////////////////////////////////
        ///*** 图像清晰度(拉普拉斯) ***///
        ////////////////////////////////////
        public double Sharpness(Mat img)
        {
            Mat imageSobel = new Mat();
            Cv2.Laplacian(img, imageSobel, MatType.CV_8UC1);
            double meanValue = Cv2.Mean(imageSobel)[0];
            //Console.WriteLine("Laplacian mean" + meanValue);
            return meanValue;
        }

        public double SharpnessArea(Mat img, EyeParams eyeParams)
        {
            int x = eyeParams.Hm_col - eyeParams.Hm_radius;
            int y = eyeParams.Hm_row - eyeParams.Hm_radius;
            if (x < 0) x = 0;
            if (y < 0) y = 0;

            Mat imgArea = img.Clone(new Rect(x, y, eyeParams.Hm_radius * 2, eyeParams.Hm_radius * 2));

            Mat imageSobel = new Mat();
            Cv2.Laplacian(imgArea, imageSobel, MatType.CV_8UC1);

            Mat meanValueImage = new Mat();
            Mat meanStdValueImage = new Mat();
            Cv2.MeanStdDev(imageSobel, meanValueImage, meanStdValueImage);
            double meanValue = meanStdValueImage.At<double>(0, 0);
            //Console.WriteLine("Std mean" + meanValue);
            return meanValue;
        }

        /////////////////////////////
        ///*** 虹膜质量评分 ***//////
        /////////////////////////////
        public double Assess_Score(double sharpness, int Hm_raduis, double usable_iris_area, double iris_sclera_constrast, double iris_pupil_constrast)
        {
            int high = 10;
            int sharpness_score = 0;
            if (sharpness < 7)
            {
                sharpness_score = 0;
            }
            else if (sharpness >= 7 && sharpness <= high)
            {
                sharpness_score = (int)(sharpness * 100 / (high - 7) - 700 / (high - 7));
            }
            else
            {
                sharpness_score = 100;
            }
            Console.WriteLine("sharpness: " + sharpness + ", score: " + sharpness_score);


            // 虹膜半径不小于 100像素(100像素:60分,往上每一像素增加一分,大于140像素100分)
            int Hm_raduis_socre = 0;
            if (Hm_raduis < 100)
            {
                Hm_raduis_socre = 0;
            }
            else if (Hm_raduis <= 140)
            {
                Hm_raduis_socre = Hm_raduis - 100 + 60;
            }
            else
            {
                Hm_raduis_socre = 100;
            }
            Console.WriteLine("raduis: " + Hm_raduis + ", score: " + Hm_raduis_socre);

            // 虹膜有效区域占比大于 60%(按比例取分数)
            double usable_iris_area_score = 0;
            if (usable_iris_area < 0.6)
            {
                usable_iris_area_score = 0;
            }
            else
            {
                usable_iris_area_score = usable_iris_area * 100;
            }
            Console.WriteLine("area: " + usable_iris_area + ", score: " + usable_iris_area_score);

            // 虹膜与巩膜对比度不小于 10(>30满分,10-30内按比例取分,满分50分)
            double iris_sclera_constrast_score = 0;
            if (iris_sclera_constrast < 10)
            {
                iris_sclera_constrast_score = 0;

            }
            else if (iris_sclera_constrast >= 10 && iris_sclera_constrast <= 30)
            {
                iris_sclera_constrast_score = (iris_sclera_constrast - 10) * 2.5;
            }
            else
            {
                iris_sclera_constrast_score = 50;
            }
            Console.WriteLine("iris_sclera_constrast: " + iris_sclera_constrast + ", score: " + iris_sclera_constrast_score);

            // 虹膜与瞳孔对比度不小于 30(>50满分,30-50内按比例取分,满分50分)
            double iris_pupil_constrast_score = 0;
            if (iris_pupil_constrast < 30)
            {
                iris_pupil_constrast_score = 0;
            }
            else if (iris_pupil_constrast >= 30 && iris_pupil_constrast <= 80)
            {
                iris_pupil_constrast_score = (iris_pupil_constrast - 30) * 1;
            }
            else
            {
                iris_pupil_constrast_score = 50;
            }
            Console.WriteLine("iris_pupil_constrast: " + iris_pupil_constrast + ", score: " + iris_pupil_constrast_score);

            if (iris_pupil_constrast_score == 0 || iris_sclera_constrast_score == 0)
                return 0;

            double assess_score = sharpness_score * sharpnessWeight
                + Hm_raduis_socre * radiusWeight
                + usable_iris_area_score * areaWeight
                + (iris_pupil_constrast_score + iris_sclera_constrast_score) * constrastWeight;

            Console.WriteLine("assecc_score: " + assess_score);
            Console.WriteLine("========================================");
            return assess_score;
        }


    }
}