public List <Rectangle> GetAllRects() { var list = new List <Rectangle>(); //定位点 list.Add(this.FixedPoint.LeftTop.Outer); list.Add(this.FixedPoint.LeftTop.Inner); list.Add(this.FixedPoint.RightTop.Outer); list.Add(this.FixedPoint.RightTop.Inner); list.Add(this.FixedPoint.LeftBottom.Outer); list.Add(this.FixedPoint.LeftBottom.Inner); list.Add(this.FixedPoint.RightBottom.Outer); list.Add(this.FixedPoint.RightBottom.Inner); //偏移块 this.OffsetAreas.ForEach(a => { list.Add(a.Area); list.AddRange(CVHelper.MoveRects(a.OffsetList, a.Area.X, a.Area.Y)); }); //选项区域 this.OptionAreaList.ForEach(a => { list.Add(a.Area); foreach (var item in a.Options.Values) { list.AddRange(CVHelper.MoveRects(item, a.Area.X, a.Area.Y)); } }); return(list); }
private void Btn_regMult_Click(object sender, EventArgs e) { CVHelper commonUse = new CVHelper(); foreach (var filePath in this.multSelectPicPathList) { try { var bitmap = new Bitmap(filePath); var rectList = commonUse.GetRectListFromBitmap(bitmap, Convert.ToInt32(this.minNum.Value), Convert.ToInt32(this.maxNum.Value), 0, 0, true, 2); Mat src = new Image <Bgr, byte>(bitmap).Mat; foreach (var item in rectList) { CvInvoke.Rectangle(src, item, new MCvScalar(0, 0, 255)); } commonUse.SaveMat(src, Path.GetFileName(filePath), false); this.successNum++; } catch (Exception) { this.failNum++; } finally { this.lbl_regResul.Text = this.failNum == 0?"":$"失败数量:{this.failNum}"; this.lbl_picNumInfo.Text = $"选择张数:{this.successNum}/{this.multSelectPicPathList?.Length}"; } } }
private void Btn_paintFormRect_Click(object sender, EventArgs e) { //for (int i = 0; i < 6; i++) //{ // Random r = new Random(); // var index= r.Next(0, Form1.OrginalRectList.Count - 1); // Form1.OrginalRectList.RemoveAt(index); //} Console.WriteLine(Form1.OrginalRectList.Count); //Form1.OrginalRectList.RemoveAt(0); //Form1.OrginalRectList.RemoveAt(Form1.OrginalRectList.Count - 1); CVHelper common = new CVHelper(); var tempList = common.FillFull(Form1.OrginalRectList); //var tempList = Form1.OrginalRectList; this.picBox.RegionInfo = new RegionInfo(this.picBox.Image.Width, this.picBox.Image.Height, tempList); Console.WriteLine(tempList.Count); this.picBox.CurrentSelectedRect = this.picBox.RegionInfo; //画出 Mat matOrginal = new Image <Bgr, byte>((Bitmap)this.picBox.Image).Mat; foreach (var item in this.picBox.CurrentSelectedRect.RectList) { CvInvoke.Rectangle(matOrginal, Rectangle.Round(item), new MCvScalar(0, 0, 255)); } CVHelper commonUse = new CVHelper(); commonUse.SaveMat(matOrginal, "获取裁剪图中的所有轮廓边在原始图中ZoomForm"); }
public OffsetArea NewByOffset(int offsetX, int offsetY) { return(new OffsetArea( CVHelper.MoveRect(this.Area, offsetX, offsetY), this.OffsetList, this.OffsetType)); }
private void Btn_regWrap_Click(object sender, EventArgs e) { //思路:重新调整大小(根据四个定位点),获取扫描结果的定位点,获取答案结果 //重新获取扫描结果的定位点 var leftTopArea = this.OriginalPaper.FixedPoint.LeftTop.GetEnlargeOuter(); var cutBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, leftTopArea.X, leftTopArea.Y, leftTopArea.Width, leftTopArea.Height); var leftTopInner = common.GetBigRectFromBitmap(cutBitmap, 2000, 6000, leftTopArea.X, leftTopArea.Y); CalcOffset(this.OriginalPaper.FixedPoint.LeftTop.Inner, leftTopInner, out int offsetX, out int offsetY); var scanPaper = this.OriginalPaper.NewPaperByOffset(offsetX, offsetY); var mat = new Image <Bgr, byte>(this.OriginalBitmap).Mat; //通过透视调整大小 List <PointF> srcPoints = scanPaper.FixedPoint.GetPointsByClockwise(); List <PointF> desPoints = new List <PointF>() { CVHelper.PointToPointF(scanPaper.FixedPoint.LeftTop.Inner.Location) }; //右上 var rightTopArea = scanPaper.FixedPoint.RightTop.Outer; var rightTopBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, rightTopArea); var rightTopInner = common.GetBigRectFromBitmap(rightTopBitmap, 2000, 6000, rightTopArea.X, rightTopArea.Y); desPoints.Add(CVHelper.PointToPointF(rightTopInner.Location)); //右下 var rightBottomArea = scanPaper.FixedPoint.RightBottom.Outer; var rightBottomBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, rightBottomArea); var rightBottomInner = common.GetBigRectFromBitmap(rightBottomBitmap, 2000, 6000, rightBottomArea.X, rightBottomArea.Y); desPoints.Add(CVHelper.PointToPointF(rightBottomInner.Location)); //左下 var leftBottomArea = scanPaper.FixedPoint.LeftBottom.Outer; var leftBottomBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, leftBottomArea); var leftBottomInner = common.GetBigRectFromBitmap(leftBottomBitmap, 2000, 6000, leftBottomArea.X, leftBottomArea.Y); desPoints.Add(CVHelper.PointToPointF(leftBottomInner.Location)); //计算透视矩阵 Mat data = CvInvoke.GetPerspectiveTransform(desPoints.ToArray(), srcPoints.ToArray()); //进行透视操作 //Mat src_gray = new Mat(); Mat mat_Perspective = new Mat(); CvInvoke.WarpPerspective(mat, mat_Perspective, data, this.OriginalBitmap.Size); //根据偏移块进行调整 scanPaper = CalPaperByOffsetS(scanPaper, mat_Perspective.Bitmap); PaperRegResultShowForm.DrawPaperRect(mat_Perspective, scanPaper); this.picSrc.LoadImage(mat_Perspective.Bitmap); //保存 string calOffsetStr = this.IsCalOffset.Checked ? "并模块偏移" : ""; common.SaveMat(mat_Perspective, $"试卷结果校正透视后{calOffsetStr}在扫描模板中显示"); }
private void Btn_validate2_Click(object sender, EventArgs e) { //思路获取偏移量, List <PointF> srcPoints = this.OriginalPaper.FixedPoint.GetPointsByClockwise(); List <PointF> desPoints = new List <PointF>(); //重新获取扫描结果的全部定位点-》重新调整大小(根据四个定位点透视) //左上 var leftTopArea = this.OriginalPaper.FixedPoint.LeftTop.GetEnlargeOuter(); var cutBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, leftTopArea.X, leftTopArea.Y, leftTopArea.Width, leftTopArea.Height); var leftTopInner = common.GetBigRectFromBitmap(cutBitmap, 500, 6000, leftTopArea.X, leftTopArea.Y); desPoints.Add(leftTopInner.Location); //右上 var rightTopArea = this.OriginalPaper.FixedPoint.RightTop.GetEnlargeOuter(); var rightTopBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, rightTopArea); var rightTopInner = common.GetBigRectFromBitmap(rightTopBitmap, 500, 6000, rightTopArea.X, rightTopArea.Y); desPoints.Add(CVHelper.PointToPointF(rightTopInner.Location)); //右下 var rightBottomArea = this.OriginalPaper.FixedPoint.RightBottom.GetEnlargeOuter(); var rightBottomBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, rightBottomArea); var rightBottomInner = common.GetBigRectFromBitmap(rightBottomBitmap, 500, 6000, rightBottomArea.X, rightBottomArea.Y); desPoints.Add(CVHelper.PointToPointF(rightBottomInner.Location)); //左下 var leftBottomArea = this.OriginalPaper.FixedPoint.LeftBottom.GetEnlargeOuter(); var leftBottomBitmap = PictureBoxReadCard.Cut(this.OriginalBitmap, leftBottomArea); var leftBottomInner = common.GetBigRectFromBitmap(leftBottomBitmap, 500, 6000, leftBottomArea.X, leftBottomArea.Y); desPoints.Add(CVHelper.PointToPointF(leftBottomInner.Location)); //计算透视矩阵 Mat data = CvInvoke.GetPerspectiveTransform(desPoints.ToArray(), srcPoints.ToArray()); //进行透视操作 var mat = new Image <Bgr, byte>(this.OriginalBitmap).Mat; Mat mat_Perspective = new Mat(); CvInvoke.WarpPerspective(mat, mat_Perspective, data, this.OriginalBitmap.Size, Inter.Nearest, Warp.Default, BorderType.Constant, new MCvScalar(255, 255, 255)); //根据偏移块进行调整 var paper = CalPaperByOffsetS(this.OriginalPaper, mat_Perspective.Bitmap); PaperRegResultShowForm.DrawPaperRect(mat_Perspective, paper); this.picSrc.LoadImage(mat_Perspective.Bitmap); //保存 string calOffsetStr = this.IsCalOffset.Checked ? "并模块偏移" : ""; common.SaveMat(mat_Perspective, $"试卷结果直接透视后{calOffsetStr}在扫描模板中显示"); }
private void Btn_percentTest_Click(object sender, EventArgs e) { CVHelper common = new CVHelper(); Rectangle r1 = new Rectangle(1, 1, 200, 200); Rectangle r2 = new Rectangle(2, 2, 190, 190); var percent = common.DecideOverlap(r2, r1, out Rectangle maxRect); MessageBox.Show(percent.ToString()); }
private void Btn_regBrokenRect_Click(object sender, EventArgs e) { //FastDetector if (this.ib_middleCut.Image == null) { MessageBox.Show("裁剪图片不能为空"); return; } CVHelper commonUse = new CVHelper(); var rectList = commonUse.GetRectListFromBitmap(this.ib_middleCut.Image.Bitmap, 40, 600, isAutoFillFull: true, optimizeTimes: 2, isBrokenOption: true); //排序 var rectListDic = commonUse.OrderRectList(rectList); Mat src = new Image <Bgr, byte>(ib_middleCut.Image.Bitmap).Mat; foreach (var item in rectList) { CvInvoke.Rectangle(src, item, new MCvScalar(0, 0, 255)); } commonUse.SaveMat(src, "获取裁剪图中的所有轮廓边界提取"); this.ib_middle.Image = src; //在原始图片中画出矩形框 var orginalRectList = new List <Rectangle>(); foreach (var item in rectList) { var tmpRect = new Rectangle(new Point(this.destRect.X + item.X, this.destRect.Y + item.Y), item.Size); orginalRectList.Add(tmpRect); } Mat matOrginal = new Image <Bgr, byte>(this.ib_original.Image.Bitmap).Mat; foreach (var item in orginalRectList) { CvInvoke.Rectangle(matOrginal, Rectangle.Round(item), new MCvScalar(0, 0, 255)); } commonUse.SaveMat(matOrginal, "获取裁剪图中的所有轮廓边在原始图中"); this.ib_result.Image = matOrginal; //在原始的PictureBox中画出框 this.DrawRectInPictureBox(this.ib_original, orginalRectList); // OrginalRectList = orginalRectList; CutedRectList = rectList; }
/// <summary> /// /// </summary> /// <param name="rectList">相对图片0,0</param> /// <param name="area"></param> /// <returns></returns> public static List <Rectangle> GetRectsByAreaAndCol(List <Rectangle> rectList, Rectangle area) { var list = new List <Rectangle>(); rectList.ForEach(r => { if (r.Y > area.Y && r.Y < area.Y + area.Height) { list.Add(CVHelper.MoveRect(r, -area.X, -area.Y)); } }); return(list); }
public static List <Rectangle> GetRectsByAreaAndRow(List <Rectangle> rectList, Rectangle area) { var list = new List <Rectangle>(); rectList.ForEach(r => { if (r.X > area.X && r.X < area.X + area.Width) { list.Add(CVHelper.MoveRect(r, -area.X, -area.Y)); } }); return(list); }
private void Btn_answerReg3_Click(object sender, EventArgs e) { CVHelper commonUse = new CVHelper(); var src = new Image <Gray, byte>(ib_middleCut.Image.Bitmap); var thresholdImage = src.CopyBlank(); int myThreshold = 210; CvInvoke.Threshold(src, thresholdImage, myThreshold, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); commonUse.SaveMat(thresholdImage.Mat, "二值化后"); //思路 close -腐蚀-腐蚀-膨胀 //形态学膨胀 Mat mat_dilate = commonUse.MyDilate(thresholdImage.Mat, Emgu.CV.CvEnum.MorphOp.Close); commonUse.SaveMat(mat_dilate, "形态学膨胀"); //mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Close); //commonUse.SaveMat(mat_dilate, "形态学膨胀1"); mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Erode); commonUse.SaveMat(mat_dilate, "形态学膨胀腐蚀1"); mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Erode); commonUse.SaveMat(mat_dilate, "形态学膨胀腐蚀2"); mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Dilate); commonUse.SaveMat(mat_dilate, "形态学膨胀2"); var image_dilate = mat_dilate.ToImage <Gray, byte>(); List <Rectangle> validRectList = new List <Rectangle>(); CutedRectList.ForEach(rect => { var newRect = new Rectangle(Math.Max(0, rect.X - 8), Math.Max(0, rect.Y - 8), rect.Width, rect.Height); var tmpImage = image_dilate.Copy(newRect); var result = GetWhiteColorPercenter(tmpImage); if (result > 0.2) { validRectList.Add(rect); } commonUse.SaveMat(tmpImage.Mat, "形态学后" + result); }); validRectList.ForEach(r => { CvInvoke.Rectangle(src, r, new MCvScalar(0, 0, 255)); }); new CVHelper().SaveMat(src.Mat, "通过比例计算获取的答案"); this.ib_result.Image = src; }
private void Btn_offset_Click(object sender, EventArgs e) { if (ib_original.Image == null) { MessageBox.Show("请先加载图片"); return; } var cutedBitmap = this.ib_original.GetFirstRegionRect(); if (cutedBitmap == null) { MessageBox.Show("将要识别的图片不能为空"); return; } CVHelper commonUse = new CVHelper(); var rectList = commonUse.GetRectListFromBitmap(cutedBitmap, Convert.ToInt32(this.minNum.Value), Convert.ToInt32(this.maxNum.Value), 0, 0, false, 0); //排序 //var rectListDic = commonUse.OrderRectList(rectList); Mat src = new Image <Bgr, byte>(cutedBitmap).Mat; foreach (var item in rectList) { CvInvoke.Rectangle(src, item, new MCvScalar(0, 0, 255)); } commonUse.SaveMat(src, "偏移量测试定位点"); this.ib_result.Image = src.Bitmap; if (rectList?.Count == 0) { return; } this.Paper.OffsetAreas.Add(new OffsetArea(this.ib_original.RegionInfo.RectList.FirstOrDefault(), rectList, this.ckb_isRow.Checked? OffsetType.Rows: OffsetType.Column)); }
private static bool ValidateColumn(Rectangle area, List <Rectangle> offsetList) { /// 偏移量区域,规范,最高线和最低线距离最近的偏移测量点大于1.5个偏移高度 /// 左右距离需要大于0.6个偏移点宽度 bool isValidate = true; var averageWidth = offsetList.Average(r => r.Width); var averageHeight = offsetList.Average(r => r.Height); var maxRect = CVHelper.GetMaxRect(offsetList); if (averageWidth * 0.6 > maxRect.X || area.Width - averageWidth * 0.6 < maxRect.X + maxRect.Width || averageHeight * 1.5 > maxRect.Y || area.Height < maxRect.Y + maxRect.Height + averageHeight * 1.5) { return(false); } return(isValidate); }
private static bool ValidateRow(Rectangle area, List <Rectangle> offsetList) { //横向的,上下0.4个宽度,左右大于0.8个高度度即可 bool isValidate = true; var averageWidth = offsetList.Average(r => r.Width); var averageHeight = offsetList.Average(r => r.Height); var maxRect = CVHelper.GetMaxRect(offsetList); if (maxRect.X < 0.4 * averageWidth || maxRect.X + maxRect.Width + 0.4 * averageWidth > area.Width || maxRect.Y < 0.8 * averageHeight || maxRect.Y + maxRect.Height + 0.8 * averageHeight > area.Height) { return(false); } return(isValidate); }
private void Btn_reg2All_Click(object sender, EventArgs e) { if (this.ib_original.Image == null) { MessageBox.Show("原始图片不能为空"); return; } CVHelper commonUse = new CVHelper(); var centerList = commonUse.GetCenterPointListFromBitmap(this.ib_original.Image.Bitmap, (int)this.num_threshold.Value);//300分辨率用200,150分辨率用45 Mat tmpMat = new Image <Bgr, byte>(this.ib_original.Image.Bitmap).Mat; centerList.ForEach(p => { CvInvoke.Circle(tmpMat, p, 6, new MCvScalar(0, 0, 255), 2); }); this.ib_result.Image = tmpMat; }
public OptionArea NewByOffsetS(List <OffsetInfo> offsetInfos) { var newOptionArea = new OptionArea() { Options = this.Options, WidthInterval = this.WidthInterval, HeightInterval = this.HeightInterval }; var offsetCol = OffsetInfo.GetNearestByColumn(offsetInfos, this.Area); var offsetRow = OffsetInfo.GetNearestByRow(offsetInfos, this.Area); int xAvgCount = 0, yavgCount = 0; xAvgCount += offsetCol.offsetX == 0 ? 0 : 1; xAvgCount += offsetRow.offsetX == 0 ? 0 : 1; yavgCount += offsetCol.offsetY == 0 ? 0 : 1; yavgCount += offsetRow.offsetY == 0 ? 0 : 1; newOptionArea.Area = CVHelper.MoveRect(this.Area, (offsetCol.offsetX + offsetRow.offsetX), (offsetCol.offsetY + offsetRow.offsetY)); return(newOptionArea); }
/// <summary> /// 计算占用比 /// </summary> /// <param name="image">所在区域的图片</param> public void CalAreaPercent(Image <Gray, byte> image, string saveName = "") { //image.Save("ssss.jpg"); int maxX = image.Width, maxY = image.Height; int width = this.Rectangle.Width, height = this.Rectangle.Height; int xExtensionDis = width / CVArea.extensionWBase, yExtensionDis = height / CVArea.extensionHBase; var extensionRect = new Rectangle(Math.Max(0, this.Rectangle.X - xExtensionDis), Math.Max(0, this.Rectangle.Y - yExtensionDis), this.Rectangle.Width + 2 * xExtensionDis, this.Rectangle.Height + 2 * yExtensionDis); var newRect = new Rectangle(new Point(this.Rectangle.X - extensionRect.X, this.Rectangle.Y - extensionRect.Y), this.Rectangle.Size); if (extensionRect.Right > maxX) { extensionRect.Width -= extensionRect.Right - maxX; } if (extensionRect.Bottom > maxY) { extensionRect.Height -= extensionRect.Bottom - maxY; } using (var extOptionRectImage = image.Copy(extensionRect)) { var thresholdMat = extOptionRectImage.CopyBlank().Mat; //CvInvoke.Threshold(CVHelper.Filter( extOptionRectImage.Mat), thresholdMat, this.Threshold, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); CvInvoke.Threshold(extOptionRectImage, thresholdMat, this.Threshold, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); Mat mat_dilate = CVHelper.MyDilateS(thresholdMat, Emgu.CV.CvEnum.MorphOp.Open); mat_dilate = CVHelper.MyDilateS(mat_dilate, Emgu.CV.CvEnum.MorphOp.Dilate); new CVHelper().SaveMat(extOptionRectImage.Mat, $"原始选项原图行学后-{saveName}"); new CVHelper().SaveMat(mat_dilate, $"异常选项原图行学后-{saveName}"); using (var originalImage = this.Max(mat_dilate.ToImage <Gray, byte>(), newRect)) { this.AreaPercent = CVHelper.GetWhiteColorPercenterS(originalImage); Console.WriteLine($"{this.Threshold}下的白色所占比:{this.AreaPercent}"); } } }
private void Btn_reg_Click(object sender, EventArgs e) { if (this.picSrc.Image == null) { MessageBox.Show("请先加载图片"); return; } CVHelper commonUse = new CVHelper(); List <Rectangle> posRectList = new List <Rectangle>(); for (int i = 0; i < this.picSrc.RegionInfo.RectList.Count; i++) { var tmpRect = this.picSrc.RegionInfo.RectList[i]; var cutedBitmap = PictureBoxReadCard.Cut(this.picSrc.orignalBitmap, tmpRect.X, tmpRect.Y, tmpRect.Width, tmpRect.Height); if (cutedBitmap == null) { MessageBox.Show("将要识别的图片不能为空"); return; } var rectList = commonUse.GetRectListFromBitmap(cutedBitmap, 200, 6000, tmpRect.X, tmpRect.Y, false, 0); posRectList.AddRange(rectList); } //获取定位点信息 var dic = commonUse.OrderRectList(posRectList, true, false); var tempList1 = dic[1].OrderBy(r => r.X).ToList(); var tempList2 = dic[2].OrderBy(r => r.X).ToList(); //四个点 var p1 = tempList1[0]; var p2 = new Point(tempList1[1].X, p1.Y); lbl1.Text = $"左上角:X:{tempList1[0].X},Y:{tempList1[0].Y},Width:{tempList1[0].Width},Height:{tempList1[0].Height}"; lbl2.Text = $"右上角:X:{tempList1[1].X},Y:{tempList1[1].Y},Width:{tempList1[1].Width},Height:{tempList1[1].Height}"; lbl3.Text = $"左下角:X:{tempList2[0].X},Y:{tempList2[0].Y},Width:{tempList2[0].Width},Height:{tempList2[0].Height}"; lbl4.Text = $"右下角:X:{tempList2[1].X},Y:{tempList2[1].Y},Width:{tempList2[1].Width},Height:{tempList2[1].Height}"; var width = tempList1[1].X - tempList1[0].X; var height = tempList2[0].Y - tempList1[0].Y; lbl5.Text = $"W:{width},H:{height}"; Console.WriteLine($"{lbl1.Text};{lbl5.Text}"); //画出所有定位点 //排序 //var rectListDic = commonUse.OrderRectList(rectList); using (Mat src = new Image <Bgr, byte>((Bitmap)this.picSrc.orignalBitmap.Clone()).Mat) { foreach (var item in posRectList) { CvInvoke.Rectangle(src, item, new MCvScalar(0, 0, 255)); } CvInvoke.Line(src, tempList1[0].Location, tempList1[1].Location, new MCvScalar(0, 0, 255), 2); CvInvoke.Line(src, tempList2[0].Location, tempList1[0].Location, new MCvScalar(0, 0, 255), 2); CvInvoke.PutText(src, lbl5.Text, tempList1[0].Location, FontFace.HersheyComplex, 3, new MCvScalar(0, 0, 255), 2); commonUse.SaveMat(src, "定位点画出后"); } }
private void BtStart_Click(object sender, EventArgs e) { //this.Start(); CVHelper commonUse = new CVHelper(); if (this.ib_middleCut.Image != null) { //Mat src1 = new Image<Bgr, byte>(ib_middleCut.Image.Bitmap).Mat; Mat src = new Image <Bgr, byte>(ib_middleCut.Image.Bitmap).Mat;// new Mat(); //CvInvoke.PyrMeanShiftFiltering(src1, src, 25, 10, 1, new MCvTermCriteria(5, 1)); //commonUse.SaveMat(src, "降噪后"); //commonUse.SaveMat(src1, "降噪后原始"); Mat dst = new Mat(); Mat src_gray = new Mat(); CvInvoke.CvtColor(src, src_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray); //存储灰度图片 commonUse.SaveMat(src_gray, "灰度"); #region 二值化 //二值化 Mat mat_threshold = new Mat(); int myThreshold = Convert.ToInt32(num_threshold.Value); CvInvoke.Threshold(src_gray, mat_threshold, myThreshold, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); commonUse.SaveMat(mat_threshold, "二值化"); //形态学膨胀 Mat mat_dilate = commonUse.MyDilate(mat_threshold, Emgu.CV.CvEnum.MorphOp.Close); commonUse.SaveMat(mat_dilate, "形态学膨胀"); mat_dilate = commonUse.MyDilate(mat_threshold, Emgu.CV.CvEnum.MorphOp.Open); commonUse.SaveMat(mat_dilate, "形态学膨胀1"); mat_dilate = commonUse.MyDilate(mat_threshold, Emgu.CV.CvEnum.MorphOp.Erode); commonUse.SaveMat(mat_dilate, "形态学膨胀"); #endregion //边缘检测 CvInvoke.Canny(mat_dilate, dst, Convert.ToInt32(this.num_Min.Value), Convert.ToInt32(this.num_Max.Value), Convert.ToInt32(this.num_apertureSize.Value)); commonUse.SaveMat(dst, "边缘检测"); //寻找答题卡矩形边界(所有的矩形) VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); //创建VectorOfVectorOfPoint数据类型用于存储轮廓 VectorOfVectorOfPoint validContours = new VectorOfVectorOfPoint(); //有效的,所有的选项的 CvInvoke.FindContours(dst, contours, null, Emgu.CV.CvEnum.RetrType.Ccomp, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple);//提取轮廓 //CvInvoke.ApproxPolyDP //画出所有矩形 Mat middleMat = new Image <Bgr, byte>(this.ib_middleCut.Image.Bitmap).Mat; CvInvoke.DrawContours(middleMat, contours, -1, new MCvScalar(0, 0, 255), 1); this.ib_result.Image = middleMat; commonUse.SaveMat(middleMat, "画出所有轮廓的"); //获取矩形边界另一种方法 //var tempRect=CvInvoke.BoundingRectangle(contours); //CvInvoke.Rectangle(src, tempRect, new MCvScalar(0, 0, 255)); //this.ib_middle.Image = src; //return; //打印所以后矩形面积和周长 int size = contours.Size; //for (int i = 0; i < size; i++) //{ // var item = contours[i]; // var tempArea = CvInvoke.ContourArea(item); // var tempArc = CvInvoke.ArcLength(item, true); // Console.WriteLine($"面积:{tempArea};周长:{tempArc}"); ; // if (tempArea > 200 && tempArea<1000) // { // validContours.Push(item); // } //} //画出符合要求的所有矩形 //CvInvoke.DrawContours(src, validContours, -1, new MCvScalar(0, 0, 255), 1); //var rectList = commonUse.GetRectList(validContours); //foreach (var item in rectList) //{ // //宽高比例不能>4或者0.24 // if (item.Width * 1.0 / item.Height > 4 || item.Width * 1.0 / item.Height < 0.25) // { // continue; // } // CvInvoke.Rectangle(src, item, new MCvScalar(0, 0, 255)); //} //commonUse.SaveMat(src, "带有所有轮廓边界的"); //this.ib_middle.Image = src; } else { MessageBox.Show("请先加载图片"); } }
private void Btn_reg_Click(object sender, EventArgs e) { if (ib_original.Image == null) { MessageBox.Show("请先加载图片"); return; } var cutedBitmap = this.ib_original.GetFirstRegionRect(); if (cutedBitmap == null) { MessageBox.Show("将要识别的图片不能为空"); return; } CVHelper commonUse = new CVHelper(); var rectList = commonUse.GetRectListFromBitmap(cutedBitmap, Convert.ToInt32(this.minNum.Value), Convert.ToInt32(this.maxNum.Value), 0, 0, true, 2); //排序 //var rectListDic = commonUse.OrderRectList(rectList); Mat src = new Image <Bgr, byte>(cutedBitmap).Mat; foreach (var item in rectList) { CvInvoke.Rectangle(src, item, new MCvScalar(0, 0, 255)); } commonUse.SaveMat(src, "获取裁剪图中的所有轮廓边界提取"); this.ib_result.Image = src.Bitmap; //填充试卷内容 if (rectList?.Count == 0) { return; } //填充试卷内容 var firstRect = this.ib_original.RegionInfo.RectList.FirstOrDefault(); if (!isFixedPointReg) { commonUse.CaculateRectInfo(rectList, out double averageWidth, out double averageHeight, out double intervalWidth, out double intervalHeight); this.Paper.OptionAreaList.Add(new OptionArea() { Area = firstRect, Options = commonUse.OrderRectList(rectList, true, false), WidthInterval = (int)intervalWidth, HeightInterval = (int)intervalHeight }); } else { var fixedPointDetail = rectList.FirstOrDefault(); fixedPointDetail.X += firstRect.X; fixedPointDetail.Y += firstRect.Y; var fixedType = this.GetFixedType(this.ib_original.orignalBitmap.Width, this.ib_original.orignalBitmap.Height, fixedPointDetail); switch (fixedType) { case FixedType.LeftTop: this.Paper.FixedPoint.LeftTop = new FixedPointDetail() { Outer = firstRect, Inner = fixedPointDetail }; break; case FixedType.RightTop: this.Paper.FixedPoint.RightTop = new FixedPointDetail() { Outer = firstRect, Inner = fixedPointDetail }; break; case FixedType.LeftBottom: this.Paper.FixedPoint.LeftBottom = new FixedPointDetail() { Outer = firstRect, Inner = fixedPointDetail }; break; case FixedType.RightBottom: this.Paper.FixedPoint.RightBottom = new FixedPointDetail() { Outer = firstRect, Inner = fixedPointDetail }; break; default: break; } } }
public Paper NewPaperByOffsetS(List <OffsetArea> newOffsetAreaList) { var paper = new Paper(); //列偏移模块 var newColOffsetList = new List <Rectangle>(); //相对0,0 var originalColOffsetList = new List <Rectangle>(); //相对0,0 //行偏移模块 var newRowOffsetList = new List <Rectangle>(); //相对0,0 var originalRowOffsetList = new List <Rectangle>(); //相对0,0 newOffsetAreaList.ForEach(a => { if (a.OffsetType == OffsetType.Column) { newColOffsetList.AddRange(CVHelper.MoveRects(a.OffsetList, a.Area.X, a.Area.Y)); } else { newRowOffsetList.AddRange(CVHelper.MoveRects(a.OffsetList, a.Area.X, a.Area.Y)); } }); //tmpColOffsetList = tmpColOffsetList.OrderBy(r => r.Y).ToList(); this.OffsetAreas.ForEach(a => { if (a.OffsetType == OffsetType.Column) { originalColOffsetList.AddRange(CVHelper.MoveRects(a.OffsetList, a.Area.X, a.Area.Y)); } else { originalRowOffsetList.AddRange(CVHelper.MoveRects(a.OffsetList, a.Area.X, a.Area.Y)); } }); //originalColOffsetList = originalColOffsetList.OrderBy(r => r.Y).ToList(); var offsetInfoList = OffsetInfo.NewListByColumn(originalColOffsetList, newColOffsetList); offsetInfoList.AddRange(OffsetInfo.NewListByRow(originalRowOffsetList, newRowOffsetList)); //定位点 暂不处理 paper.FixedPoint = this.FixedPoint.NewFixedPointByOffset(0, 0); //选项区域 this.OptionAreaList.ForEach(o => { paper.OptionAreaList.Add(o.NewByOffsetS(offsetInfoList)); }); //偏移量 this.OffsetAreas.ForEach(a => { if (a.OffsetType == OffsetType.Column) { var tmpList = OffsetInfo.GetRectsByAreaAndCol(newColOffsetList, a.Area); paper.OffsetAreas.Add(new OffsetArea(a.Area, tmpList, a.OffsetType)); } else { var tmpList = OffsetInfo.GetRectsByAreaAndRow(newRowOffsetList, a.Area); paper.OffsetAreas.Add(new OffsetArea(a.Area, tmpList, a.OffsetType)); } }); return(paper); }
public void Start() { CVHelper commonUse = new CVHelper(); if (ib_original.Image != null) { //Mat src = new Image<Bgr, byte>(ib_original.Image.Bitmap).Mat; Mat src = ib_original.Image.GetInputArray().GetMat(); //1.获取当前图像的最大矩形边界 VectorOfVectorOfPoint max_contour = commonUse.GetBoundaryOfPic(src); //2.对图像进行矫正 Mat mat_Perspective = commonUse.MyWarpPerspective(src, max_contour); //规范图像大小 CvInvoke.Resize(mat_Perspective, mat_Perspective, new Size(590, 384), 0, 0, Emgu.CV.CvEnum.Inter.Cubic); //3.二值化处理(大于阈值取0,小于阈值取255。其中白色为0,黑色为255) Mat mat_threshold = new Mat(); int myThreshold = Convert.ToInt32(num_threshold.Value); CvInvoke.Threshold(mat_Perspective, mat_threshold, myThreshold, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); //ib_middle.Image = mat_threshold; //形态学膨胀 Mat mat_dilate = commonUse.MyDilate(mat_threshold); //ib_middle.Image = mat_dilate; //筛选长宽比大于2的轮廓 VectorOfVectorOfPoint selected_contours = commonUse.GetUsefulContours(mat_dilate, 1); //画出轮廓 Mat color_mat = commonUse.DrawContours(mat_Perspective, selected_contours); ib_middle.Image = color_mat; ib_result.Image = mat_Perspective; //准考证号,x=230+26*5,y=40+17*10 //tb_log.Text = commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 230, 26, 5, 40, 17, 10, "准考证号:"); ////答题区1-5题,x=8+25*5,y=230+16*4 //tb_log.Text += commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 8, 25, 5, 230, 16, 4, "1-5:"); ////答题区6-10题,x=159+25*5,y=230+16*4 //tb_log.Text += commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 159, 25, 5, 230, 16, 4, "6-10:"); ////答题区11-15题,x=310+25*5,y=230+16*4 //tb_log.Text += commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 310, 25, 5, 230, 16, 4, "11-15:"); ////答题区16-20题,x=461+25*5,y=230+16*4 //tb_log.Text += commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 461, 25, 5, 230, 16, 4, "16-20:"); ////答题区21-25题,x=8+25*5,y=312+16*4 //tb_log.Text += commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 8, 25, 5, 312, 16, 4, "21-25:"); ////答题区26-30题,x=159+25*5,y=312+16*4 //tb_log.Text += commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 159, 25, 5, 312, 16, 4, "26-30:"); ////答题区31-35题,x=310+25*5,y=312+16*4 //tb_log.Text += commonUse.GetValueAndDrawGrid(ib_result, selected_contours, 310, 25, 5, 312, 16, 4, "31-35:"); } else { MessageBox.Show("请先加载图片"); } }
/// <summary> /// 该区域的图片 /// </summary> /// <param name="src"></param> /// <param name="myThreshold"></param> public void Recognition(Image <Gray, byte> src, int myThreshold = 180) { ////思路:第一次正常识别--->初步智能筛选---->再次智能筛选---》再次智能(如果未选,继续多次,如果多选) ////var src = new Image<Gray, byte>(bitmap); var thresholdMat = src.CopyBlank().Mat; CvInvoke.Threshold(src, thresholdMat, myThreshold, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); new CVHelper().SaveMat(src.Mat, "原始的"); //思路 open -膨胀 //形态学膨胀 Mat mat_dilate = CVHelper.MyDilateS(thresholdMat, Emgu.CV.CvEnum.MorphOp.Open); new CVHelper().SaveMat(mat_dilate, "Open行学"); mat_dilate = CVHelper.MyDilateS(mat_dilate, Emgu.CV.CvEnum.MorphOp.Dilate); new CVHelper().SaveMat(mat_dilate, "Dilate行学"); //补充偏移置换 //src = Max(src); foreach (var question in this.CVQuestionList) { for (int i = 0; i < question.OptionRectList.Count; i++) { var cvRect = question.OptionRectList[i]; //计算平均灰度值 //var fileName = $"{this.Name}第"; cvRect.CalVagGrayValueAndHist(src); //计算面积比 cvRect.CalAreaPercent(src); if (cvRect.AreaPercent > CVArea.valAreaPercent) { question.Results.Add(i); } } } //打印初步识别的 //new CommonUse().DrawRectCircleAndSave(src.Mat.Clone(), this.GetRectList(), $"{this.Name}-初步识别的", -this.Area.X, -this.Area.Y, points: this.GetResultPointList(false)); this.DrawDetail(src.Clone(), this.Name); //初步筛选 this.Check(); new CVHelper().DrawRectCircleAndSave(src.Mat.Clone(), this.GetRectList(false), $"{this.Name}-初步筛选结果", points: this.GetResultPointList(false)); //再次智能处理异常的 this.CVQuestionList.ForEach(q => { this.IntelligentChose(src, q); int total = 11; for (int i = 2; i <= total; i++) { if (q.ResultStatus == QuestionResultStatus.Right) { break; } else if (q.ResultStatus == QuestionResultStatus.Absence) { q.IntelligentChoseByAbsence(src, i); } } }); //再次通过神经网络识别 //this.RecognitionByML(); for (int i = 0; i < this.CVQuestionList.Count; i++) { var q = this.CVQuestionList[i]; if (q.ResultStatus != QuestionResultStatus.Absence) { continue; } //针对只有一个的选框的不适用人工智能网络) //if (this.GetOptionCount() == 1) //{ // continue; //} for (int j = 0; j < q.OptionRectList.Count; j++) { var rect = q.OptionRectList[j]; if (rect.AreaPercent == 0 && rect.AvgGrayValue == 0) { continue; } //智能识别 var queRect = rect.Rectangle; using (var copy = src.Copy(queRect)) { var isAnswer = MLearner.IsAnswer(copy); if (!q.Results.Contains(j) && isAnswer) { q.Results.Add(j); } new CVHelper().SaveMat(copy.Mat, "需要智能之别的" + isAnswer, dictory: "MLReg\\"); } } } //脱离原rectangle,再次智能筛选 try { DoMLAgain(src); } catch (Exception ex) { Console.WriteLine("再次智能之别是,发生错误"); Console.WriteLine(ex); } }
/// <summary> /// 再次智能识别 /// </summary> /// <param name="src"></param> private void DoMLAgain(Image <Gray, byte> src) { //正对使用了偏移块还不准的区域再次识别 if (!this.IsAbsence()) { return; } var cvHelper = new CVHelper(); var rectList = cvHelper.GetRectListFromBitmap(src.Bitmap, isAutoFillFull: true); if (rectList.Count != this.GetOptionCount())// || rectList.Count==1 针对只有一个的选框的不适用 { return; } var rectListDic = cvHelper.OrderRectList(rectList, this.IsOrderByRow()); var anwserDir = new Dictionary <int, List <int> >(); foreach (var key in rectListDic.Keys) { var queOptions = rectListDic[key]; var tmpResult = new List <int>(); for (int i = 0; i < queOptions.Count; i++) { var queRect = queOptions[i]; using (var copy = src.Copy(queRect)) { var isAnswer = MLearner.IsAnswer(copy); if (isAnswer) { tmpResult.Add(i); } #if DEBUG new CVHelper().SaveMat(copy.Mat, "再次智能之别的" + isAnswer, dictory: "MLReg2\\"); #endif } } anwserDir.Add(key, tmpResult); } //合并答案 foreach (var key in anwserDir.Keys) { var result = anwserDir[key]; if (this.CVQuestionList[key - 1].ResultStatus == QuestionResultStatus.Absence) { this.CVQuestionList[key - 1].Results = result; } } #if DEBUG //画出再次智能出来的框和识别出来的中心点 var tmpRectList = new List <Rectangle>(); var tmpPointList = new List <Point>(); foreach (var key in rectListDic.Keys) { tmpRectList.AddRange(rectListDic[key]); anwserDir[key].ForEach(i => { var rect = rectListDic[key][i]; var point = rect.Location; point.Offset(rect.Width / 2, rect.Height / 2); tmpPointList.Add(point); }); } cvHelper.DrawRectCircleAndSave(src.Mat, tmpRectList, "再次智能后", points: tmpPointList, dictory: "MLReg2\\"); #endif }
private void Btn_anwserReg_Click(object sender, EventArgs e) { if (this.ib_middleCut.Image == null) { MessageBox.Show("裁剪图片不能为空"); return; } CVHelper commonUse = new CVHelper(); Mat src = new Image <Bgr, byte>(ib_middleCut.Image.Bitmap).Mat;// new Mat(); //CvInvoke.PyrMeanShiftFiltering(src1, src, 25, 10, 1, new MCvTermCriteria(5, 1)); //commonUse.SaveMat(src, "降噪后"); //commonUse.SaveMat(src1, "降噪后原始"); Mat dst = new Mat(); Mat src_gray = new Mat(); CvInvoke.CvtColor(src, src_gray, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray); //存储灰度图片 commonUse.SaveMat(src_gray, "灰度"); #region 二值化 //二值化 Mat mat_threshold = new Mat(); int myThreshold = Convert.ToInt32(num_threshold.Value); CvInvoke.Threshold(src_gray, mat_threshold, myThreshold, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv); commonUse.SaveMat(mat_threshold, "二值化"); //思路 close -腐蚀-腐蚀-膨胀 //形态学膨胀 Mat mat_dilate = commonUse.MyDilate(mat_threshold, Emgu.CV.CvEnum.MorphOp.Close); commonUse.SaveMat(mat_dilate, "形态学膨胀"); //mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Close); //commonUse.SaveMat(mat_dilate, "形态学膨胀1"); mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Erode); commonUse.SaveMat(mat_dilate, "形态学膨胀腐蚀1"); mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Erode); commonUse.SaveMat(mat_dilate, "形态学膨胀腐蚀2"); mat_dilate = commonUse.MyDilate(mat_dilate, Emgu.CV.CvEnum.MorphOp.Dilate); commonUse.SaveMat(mat_dilate, "形态学膨胀2"); #endregion //边缘检测 CvInvoke.Canny(mat_dilate, dst, Convert.ToInt32(this.num_Min.Value), Convert.ToInt32(this.num_Max.Value), Convert.ToInt32(this.num_apertureSize.Value)); commonUse.SaveMat(dst, "边缘检测"); //寻找答题卡矩形边界(所有的矩形) VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); //创建VectorOfVectorOfPoint数据类型用于存储轮廓 VectorOfVectorOfPoint validContours = new VectorOfVectorOfPoint(); //有效的,所有的选项的 CvInvoke.FindContours(dst, contours, null, Emgu.CV.CvEnum.RetrType.Ccomp, Emgu.CV.CvEnum.ChainApproxMethod.ChainApproxSimple, new Point(8, 8));//提取轮廓 //打印所以后矩形面积和周长 int size = contours.Size; for (int i = 0; i < size; i++) { var item = contours[i]; var tempArea = CvInvoke.ContourArea(item); var tempArc = CvInvoke.ArcLength(item, true); Console.WriteLine($"面积:{tempArea};周长:{tempArc}");; if (tempArea > 200 && tempArea < 2000) { validContours.Push(item); } } //CvInvoke.ApproxPolyDP //画出所有轮廓 Mat middleMat = new Image <Bgr, byte>(this.ib_middleCut.Image.Bitmap).Mat; CvInvoke.DrawContours(middleMat, validContours, -1, new MCvScalar(0, 0, 255), 1); this.ib_result.Image = middleMat; commonUse.SaveMat(middleMat, "画出所有轮廓的"); //画出所有矩形 Mat tmpMat = new Image <Bgr, byte>(this.ib_middleCut.Image.Bitmap).Mat; List <Rectangle> rectangles = commonUse.GetRectList(validContours, false); rectangles.ForEach(rect => { CvInvoke.Rectangle(tmpMat, rect, new MCvScalar(0, 0, 255)); }); commonUse.SaveMat(tmpMat, "画出所有矩形轮廓的"); this.ib_result.Image = tmpMat; }
private void Btn_answerReg4_Click(object sender, EventArgs e) { if (this.ib_middleCut.Image == null) { MessageBox.Show("裁剪图片不能为空"); return; } CVHelper commonUse = new CVHelper(); var centerList = new List <Point>(); if (!this.ck_IsIntell.Checked && !this.ckb_ANN.Checked) { centerList = commonUse.GetCenterPointListFromBitmapByWhiteArea(this.ib_middleCut.Image.Bitmap, CutedRectList); Mat tmpMat = new Image <Bgr, byte>(this.ib_middleCut.Image.Bitmap).Mat; centerList.ForEach(p => { CvInvoke.Circle(tmpMat, p, 6, new MCvScalar(0, 0, 255), 2); }); this.ib_result.Image = tmpMat; } else { var rectList = new List <Rectangle>(); CutedRectList.ForEach(r => { r.Offset(destRect.Location); //int offsetX = Math.Min(5, r.X), offsetY = Math.Min(5, r.Y); //r.Offset(-offsetX, -offsetY); rectList.Add(r); }); CVArea area = new CVArea(this.destRect, commonUse.OrderRectList(rectList, IsFillFull: false), name: "测试卷"); if (this.ck_IsIntell.Checked) { centerList = commonUse.GetCenterPointListFromBitmapByWhiteArea(this.ib_original.Image.Bitmap, new List <CVArea>() { area }); } else if (this.ckb_ANN.Checked) { centerList = commonUse.GetCenterPointListFromBitmapByWhiteAreaByML(this.ib_original.Image.Bitmap, new List <CVArea>() { area }); } Mat tmpMat = new Image <Bgr, byte>(this.ib_original.Image.Bitmap).Mat; centerList.ForEach(p => { CvInvoke.Circle(tmpMat, p, 6, new MCvScalar(0, 0, 255), 2); }); this.ib_result.Image = tmpMat; this.CurrentArea = area; return; } }