欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

基于EmguCv的圓形答題卡識別-創(chuàng)新互聯

參考:https://blog.csdn.net/qiao_lili/article/details/83176480

成都創(chuàng)新互聯公司是一家專業(yè)提供臨滄企業(yè)網站建設,專注與做網站、網站設計成都h5網站建設、小程序制作等業(yè)務。10年已為臨滄眾多企業(yè)、政府機構等服務。創(chuàng)新互聯專業(yè)網站制作公司優(yōu)惠進行中。

網上關于C#結合EmguCv開發(fā)答題卡識別的資料很少,因為有做答題卡識別方面的需求,個人也只熟悉C#語言,找了半天也只找到一些通過C++、Python或matlab結合OpenCV來實現識別的例子,只好對著別人的例子嘗試著翻譯成EmguCv,還算成功。自己又針對答題卡識別封裝了幾個函數,記錄在這留給需要的人。(得吐槽下,EmguCv在錯誤管理上還欠缺很多,經常出現莫名其妙的錯誤)

1.設置兩個圖片顯示容器
ib_original.SizeMode = PictureBoxSizeMode.Zoom;
            ib_original.FunctionalMode = Emgu.CV.UI.ImageBox.FunctionalModeOption.Minimum;

            ib_result.SizeMode = PictureBoxSizeMode.Zoom;
            ib_result.FunctionalMode = Emgu.CV.UI.ImageBox.FunctionalModeOption.Minimum;
2.載入要處理的圖片
OpenFileDialog op = new OpenFileDialog();

            if (op.ShowDialog() == DialogResult.OK)
            {
                Mat src = new Mat(op.FileName, Emgu.CV.CvEnum.LoadImageType.AnyColor);
                ib_original.Image = src;
            }

實例圖片

3.獲取當前圖像的大矩形邊界
//獲取當前圖像的大矩形邊界
                VectorOfVectorOfPoint result_contour = GetBoundaryOfPic(src);

public VectorOfVectorOfPoint GetBoundaryOfPic(Mat src)
        {
            Mat dst = new Mat();
            Mat src_gray = new Mat();
            CvInvoke.CvtColor(src, src_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);

            //邊緣檢測
            CvInvoke.Canny(src_gray, dst, 120, 180);

            //尋找答題卡矩形邊界(大的矩形)
            VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();//創(chuàng)建VectorOfVectorOfPoint數據類型用于存儲輪廓

            CvInvoke.FindContours(dst, contours, null, Emgu.CV.CvEnum.RetrType.External,
                Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);//提取輪廓

            VectorOfVectorOfPoint result_contour = new VectorOfVectorOfPoint();//用于存儲篩選過后的輪廓

            int ksize = contours.Size; //獲取連通區(qū)域個數
            if (ksize == 1)
            {
                result_contour = contours;
            }
            else
            {
                double maxLength = -1;//用于保存輪廓周長的大值
                int index = -1;//輪廓周長的大值的序號
                for (int i = 0; i< ksize; i++)
                {
                    VectorOfPoint contour = contours[i];//獲取獨立的連通輪廓
                    double length = CvInvoke.ArcLength(contour, true);//計算連通輪廓的周長

                    if (length >maxLength)
                    {
                        maxLength = length;
                        index = i;
                    }
                }
                result_contour.Push(contours[index]);//篩選后的連通輪廓
            }
            return result_contour;
        }
4.對圖像進行矯正
//對圖像進行矯正
                Mat mat_Perspective = MyWarpPerspective(src, result_contour);

public Mat MyWarpPerspective(Mat src, VectorOfVectorOfPoint result_contour)
        {
            //擬合答題卡的幾何輪廓,保存點集pts并順時針排序
            VectorOfPoint pts = new VectorOfPoint();//用于存放逼近的結果
            VectorOfPoint tempContour = result_contour[0];//臨時用
            double result_length = CvInvoke.ArcLength(tempContour, true);
            CvInvoke.ApproxPolyDP(tempContour, pts, result_length * 0.02, true); //幾何逼近,獲取矩形4個頂點坐標

            //Point[]轉換為PointF[]類型
            PointF[] pts_src = Array.ConvertAll(pts.ToArray(), new Converter(PointToPointF));
            
            //確定透視變換的寬度、高度
            Size sizeOfRect = CalSizeOfRect(pts_src);
            int width= sizeOfRect.Width;
            int height=sizeOfRect.Height;

            //計算透視變換矩陣
            PointF[] pts_target = new PointF[] { new PointF(0, 0), new PointF(width - 1, 0) ,
                        new PointF(width - 1, height - 1) ,new PointF(0, height - 1)};

            //計算透視矩陣
            Mat data = CvInvoke.GetPerspectiveTransform(pts_src, pts_target);
            //進行透視操作
            Mat mat_Perspective = new Mat();
            Mat src_gray = new Mat();
            CvInvoke.CvtColor(src, src_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);
            CvInvoke.WarpPerspective(src_gray, mat_Perspective, data, new Size(width, height));

            return mat_Perspective;
        }

////// 計算給定四個坐標點四邊形的寬、高
        /////////public Size CalSizeOfRect(PointF[] pts_src)
        {
            if (pts_src.Length != 4) return new Size(0,0);//確保為四邊形

            if (pts_src[1].X< pts_src[3].X)
            {
                //說明當前為逆時針存儲,改為順時針存儲(交換第2、4點)
                PointF p = new PointF();
                p = pts_src[1];
                pts_src[1] = pts_src[3];
                pts_src[3] = p;
            }

            //確定透視變換的寬度、高度
            int width;
            int height;

            double width1 = Math.Pow(pts_src[0].X - pts_src[1].X, 2) + Math.Pow(pts_src[0].Y - pts_src[1].Y, 2);
            double width2 = Math.Pow(pts_src[2].X - pts_src[3].X, 2) + Math.Pow(pts_src[2].Y - pts_src[3].Y, 2);

            width = width1 >width2 ? (int)Math.Sqrt(width1) : (int)Math.Sqrt(width2);//根號下a方+b方,且取寬度大的

            double height1 = Math.Pow(pts_src[0].X - pts_src[3].X, 2) + Math.Pow(pts_src[0].Y - pts_src[3].Y, 2);
            double height2 = Math.Pow(pts_src[1].X - pts_src[2].X, 2) + Math.Pow(pts_src[1].Y - pts_src[2].Y, 2);

            height = height1 >height2 ? (int)Math.Sqrt(height1) : (int)Math.Sqrt(height2);

            return new Size(width, height);
        }

////// Point轉換為PointF類型
        /////////public static PointF PointToPointF(Point p)
        {
            return new PointF(p.X, p.Y);
        }
5.閾值分割
//閾值分割
                Mat mat_threshold = new Mat();
                CvInvoke.Threshold(mat_Perspective, mat_threshold, 160, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv);
6.獲取符合標準的圓形輪廓
//獲取符合標準的圓形輪廓
VectorOfVectorOfPoint selected_contours =GetContoursAboveGivenSize(mat_threshold, 20, 20);

////// 提取圖中大于給定寬、高的輪廓
        //////要提取輪廓的圖片///輪廓外接矩形的寬///輪廓外接矩形的高public VectorOfVectorOfPoint GetContoursAboveGivenSize(Mat mat_threshold, int width, int height)
        {
            //輪廓篩選
            //1.膨脹,改善輪廓
            Mat struct_element = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Cross,
                new Size(3, 3), new Point(-1, -1));//結構元素
            Mat mat_dilate = new Mat();
            CvInvoke.MorphologyEx(mat_threshold, mat_dilate, Emgu.CV.CvEnum.MorphOp.Dilate, struct_element, new Point(-1, -1), 1,
                Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0, 0, 0));//形態(tài)學膨脹

            //2.篩選輪廓。篩選條件:寬度和高度同時大于20
            VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();//所有的輪廓
            VectorOfVectorOfPoint selected_contours = new VectorOfVectorOfPoint();//用于存儲篩選過后的圓形輪廓
            Mat mat_dilate_clone = mat_dilate.Clone();//克隆
            CvInvoke.FindContours(mat_dilate_clone, contours, null, Emgu.CV.CvEnum.RetrType.External,
                Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);//提取輪廓,操作過程中會對輸入圖像進行修改

            //選取外接矩形寬、高要同時大于給定標準的輪廓
            for (int i = 0; i< contours.Size; i++)
            {
                Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);//外接矩形
                if (rect.Width >width && rect.Height >height)
                {
                    selected_contours.Push(contours[i]);
                }
            }

            return selected_contours;
        }
7.對輪廓進行分類排序,獲取分類排序后的二維數組
//對輪廓進行分類排序,獲取分類排序后的二維數組
VectorOfVectorOfPoint[,] classed_contours = ClassedOfContours(selected_contours, 5, 5);

////// 對給定的一些輪廓進行分類排序,返回分類排序后的二維數組
        //////要進行排序的輪廓///一行中輪廓的個數///一列中輪廓的個數///public VectorOfVectorOfPoint[,] ClassedOfContours(VectorOfVectorOfPoint selected_contours, int countOfRow, int countOfColumn)
        {
            //依據圓心的位置來確認答題卡輪廓的位置
            //1.計算所有外接圓基本數據
            float[] radius = new float[selected_contours.Size];
            PointF[] center = new PointF[selected_contours.Size];
            for (int i = 0; i< selected_contours.Size; i++)
            {
                CircleF circleF = CvInvoke.MinEnclosingCircle(selected_contours[i]);//最小外接圓
                center[i] = circleF.Center;
                radius[i] = circleF.Radius;
            }
            //2.計算x軸、y軸分割間隔
            float x_min = 999, y_min = 999;
            float x_max = -1, y_max = -1;
            float x_interval = 0, y_interval = 0;//相鄰圓心的間距
            foreach (PointF pf in center)
            {
                //獲取所有圓心中的坐標最值
                if (pf.X< x_min) x_min = pf.X;
                if (pf.X >x_max) x_max = pf.X;

                if (pf.Y< y_min) y_min = pf.Y;
                if (pf.Y >y_max) y_max = pf.Y;
            }
            x_interval = (x_max - x_min) / (countOfRow - 1);//答題卡每行5個圓,即4個間隔
            y_interval = (y_max - y_min) / (countOfColumn - 1);//答題卡每列5個圓,即4個間隔
            //4.分類
            VectorOfVectorOfPoint[,] classed_contours = new VectorOfVectorOfPoint[countOfRow, countOfColumn];
            //初始化VectorOfVectorOfPoint二維數組
            for (int i = 0; i< 5; i++)
            {
                for (int j = 0; j< 5; j++)
                {
                    classed_contours[i, j] = new VectorOfVectorOfPoint();
                }
            }

            for (int i = 0; i< selected_contours.Size; i++)
            {
                PointF pf = center[i];
                int index_x = (int)Math.Round((pf.X - x_min) / x_interval);
                int index_y = (int)Math.Round((pf.Y - y_min) / y_interval);
                VectorOfPoint temp = selected_contours[i];
                classed_contours[index_x, index_y].Push(temp);
            }

            return classed_contours;
        }
8.檢測答題者的選項
//檢測答題者的選項
int[,] result_count = GetResultArray(mat_threshold, classed_contours, 5, 5);

////// 檢測答題者的選項,獲取涂選的結果數組
        //////經閾值處理后的圖像///經排序分類后的輪廓數組///一行中輪廓的個數///一列中輪廓的個數///public int[,] GetResultArray(Mat mat_threshold,VectorOfVectorOfPoint[,] classed_contours, int countOfRow, int countOfColumn)
        {
            int[,] result_count = new int[countOfRow, countOfColumn];//結果數組
            //統(tǒng)計所有答題圓圈外接矩形內非零像素個數
            Rectangle[,] re_rect = new Rectangle[countOfRow, countOfColumn];//外接矩形數組
            int[,] count_roi = new int[countOfRow, countOfColumn];//外接矩形內非零像素個數
            int min_count = 999;//非零像素個數大值,作為已涂選的參照
            int max_count = -1;//非零像素個數最小值,作為未涂選的參照
            for (int i = 0; i< countOfRow; i++)
            {
                for (int j = 0; j< countOfColumn; j++)
                {
                    VectorOfPoint countour = classed_contours[i, j][0];
                    re_rect[i, j] = CvInvoke.BoundingRectangle(countour);
                    Mat temp = new Mat(mat_threshold, re_rect[i, j]);//提取ROI矩形區(qū)域
                    int count = CvInvoke.CountNonZero(temp);//計算圖像內非零像素個數
                    count_roi[i, j] = count;

                    if (count >max_count)max_count = count;
                    if (count< min_count)min_count = count;
                }
            }

            //比對涂選的答案,以涂滿圓圈一半以上為標準
            for (int i = 0; i< countOfRow; i++)
            {
                for (int j = 0; j< countOfColumn; j++)
                {
                    if (count_roi[i, j] >max_count / 2)
                    {
                        result_count[i, j]=1;
                    }
                }
            }

            return result_count;
        }
9.?標示出答題者的選項
//標示出答題者的選項
                Mat temp_mat = new Mat();
                CvInvoke.CvtColor(mat_Perspective, temp_mat, Emgu.CV.CvEnum.ColorConversion.Gray2Bgr);

                for (int i = 0; i< 5; i++)
                {
                    for (int j = 0; j< 5; j++)
                    {
                        if (result_count[i,j]==1)
                        {
                            CvInvoke.DrawContours(temp_mat, classed_contours[i,j], -1, new MCvScalar(255, 0, 0), 2);
                        }
                    }
                }

                ib_result.Image = temp_mat;

結果圖如下:?

你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧

網頁標題:基于EmguCv的圓形答題卡識別-創(chuàng)新互聯
網站地址:http://aaarwkj.com/article16/ccghgg.html

成都網站建設公司_創(chuàng)新互聯,為您提供商城網站、網站設計自適應網站、響應式網站定制開發(fā)、營銷型網站建設

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

成都做網站
国产欧美高清在线观看视频| av在线免费播放观看| 亚洲七七久久精品中文国产| 亚洲精品天堂av免费看| 天天操夜夜骑日日干| 日本欧美国产污黄在线观看| 欧美午夜一级特黄大片| 本色啪啪人妻夜嗨嗨av| 亚洲一区二区婷婷久久| 国产亚洲理论片在线观看| 国产男女在线视频观看| 日本五十路亲子在线一区| 日韩有码中文字幕av | 中文字幕乱码亚洲美女精品 | 国产色视频一区在线观看| 精品人妻少妇免费久久蜜臀av| 中文字幕日韩一区二区| 国产午夜福利一区在线| av天堂黄色在线观看| 一本色道久久88综合日韩| 午夜精品四季av日日骚| 日本一区二区精美视频| 日韩不卡区免费在线观看| 国产三级三级三级免费看| 濑亚美莉在线观看一区二区三区| 欧美日韩中文字幕精品视频| 丰满人妻熟妇乱精品视频| 欧美激情韩国三级日本| 日韩成人在线视频中文字幕| 亚洲精品一区二区三区pp| 亚洲黄色一区大陆av剧情| 国产精品夫妇在线激情啪| 91久久国产免费网站| 91制片国产在线观看| 中文一级伦理一区二区| 日韩亚洲一区二区免费| 国产精品毛片av在线| 欧美大片免费高清观看| 黄色18禁网站在线看| 日韩欧美亚洲视频另类| 国产aaa级日本一区二区三区|