using OpenCvSharp; using OpenCvSharp.Extensions; using OTSCommon.DBOperate.Model; using OTSIncAReportApp._1_UI.Control_Graph.Controls; using OTSIncAReportApp.OTSRstMgrFunction; using OTSIncAReportGraph; using OTSIncAReportGraph.Class; using OTSIncAReportGraph.Controls; using OTSMeasureApp.ServiceCenter; using OTSModelSharp.ServiceCenter; using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace OTSIncAReportApp._3_ServiceCenter { class ImageExporter { public OTSIncAReportApp.frmReportApp m_ReportApp; //包含particle的field的列表对象 public List m_list_allDfield = null; public ResultFile resultFile = null; public SaveFileDialog sfd = null; public DataTable ParticleData = new DataTable(); public DataTable ParticleClassData = new DataTable(); /// /// 国标一框框 /// public DataTable GBDatatableOne { get; set; } /// ///国标格子大小(像素) /// public int GridLength { get; set; } public int type = 0; //像素大小 public double pixelSize = 0; private double picGBYmin = 0; private double OverlapParamPX = 0; public void opencv_outpic() { ImageSplicer imageSplicer = new ImageSplicer(); Dictionary sampleMembers = ((Dictionary)((Dictionary)resultFile.ResultInfo["Sample"])["Members"]); Dictionary imageProcessParam = (Dictionary)((Dictionary)((Dictionary)sampleMembers["MsrParams"])["Members"])["ImageProcessParam"]; object strOverlapParam = ""; imageProcessParam.TryGetValue("OverlapParam", out strOverlapParam); if (strOverlapParam == null) { strOverlapParam = "0"; //NLog.LogManager.GetCurrentClassLogger().Info("There are no overlapping dimensions"); //return; } //获取图像重叠参数(微米需要转换成像素) int OverlapParam = int.Parse(strOverlapParam.ToString()); if (OverlapParam==0) { OverlapParamPX = 0; }else { OverlapParamPX = OverlapParam / pixelSize; } List list_dt_picdata = new List(); OpenCvSharp.Mat[] list_mats; //导出拼接图片外加颗粒渲染 if (type ==(int)Outpic_enum.ColoredParticles) { list_dt_picdata = imageSplicer.ImageStitchingParticleRendering(resultFile, m_list_allDfield); list_mats = new OpenCvSharp.Mat[list_dt_picdata.Count]; } //导出国标外加颗粒渲染 else if (type == (int)Outpic_enum.GBOne) { list_dt_picdata = imageSplicer.ImageStitchingParticleRendering(resultFile, m_list_allDfield); list_mats = new OpenCvSharp.Mat[list_dt_picdata.Count]; } //导出拼接图片 else { list_dt_picdata = imageSplicer.Mosaics(resultFile, m_list_allDfield); list_mats = new OpenCvSharp.Mat[list_dt_picdata.Count]; } NLog.LogManager.GetCurrentClassLogger().Info("Organize and splice all pictures......"); List list_pano = new List(); List list_panos = new List(); //循环保存每行拼接的图片 for (int i = list_dt_picdata.Count-1; i >= 0; i--) { // 计算新Bitmap的总宽度和高度 int totalWidth = 0; int maxHeight = 0; for ( int c=0;c< list_dt_picdata[i].Rows.Count;c++) { Bitmap bitmap = (Bitmap)list_dt_picdata[i].Rows[c]["mat"]; totalWidth += bitmap.Width; // 减去重叠部分将在绘制时处理 maxHeight = Math.Max(maxHeight, bitmap.Height); } // 因为有n张图片,它们之间会有n-1个重叠区域,所以需要从总宽度中减去这些重叠的像素 // 注意:如果图片数量小于2,则不需要减去任何重叠部分 if (list_dt_picdata[i].Rows.Count > 1) { totalWidth -= (list_dt_picdata[i].Rows.Count - 1) * (int)OverlapParamPX; } // 创建一个新的Bitmap对象来存储拼接后的图像 Bitmap combinedImage = new Bitmap(totalWidth, maxHeight); // 使用Graphics对象来绘制拼接后的图像 using (Graphics g = Graphics.FromImage(combinedImage)) { int currentX = 0; for (int b=0;b< list_dt_picdata[i].Rows.Count; b++) { Bitmap bitmap = (Bitmap)list_dt_picdata[i].Rows[b]["mat"]; // 绘制当前图片,注意调整X坐标以实现重叠 g.DrawImage(bitmap, new Rectangle(currentX, 0, bitmap.Width, bitmap.Height)); // 更新当前X坐标,为下一张图片留出空间(包括重叠部分) currentX += bitmap.Width - (list_dt_picdata[i].Rows.Count > 1 ? (int)OverlapParamPX : 0); // 如果不是最后一张图片,则减去重叠的20像素 } } Mat mat = BitmapConverter.ToMat(combinedImage); list_pano.Add(mat); list_panos.Add(combinedImage); } //导出原图(渲染图)在下方增加每种颜色的标注和面积占比 if (type == (int)Outpic_enum.ColoredParticles || type == (int)Outpic_enum.GBOne) { DataTable particleData = ParticleDataIntegration(ParticleData, ParticleClassData); int NumberOfRows = getPICstringLong(particleData, list_pano); Bitmap bitmap = new Bitmap(list_pano[0].Width, NumberOfRows*140); Graphics g = Graphics.FromImage(bitmap); g.Clear(Color.White); int rowData = 10; //矩形格子宽500 SolidBrush mysbrush1 = new SolidBrush(ColorTranslator.FromHtml("#000000")); Pen mypen = new Pen(mysbrush1, 2); Font myFont = new Font("宋体", 13, FontStyle.Bold); SolidBrush sbrush = new SolidBrush(Color.Black); int Color_Y = 10; int TypeName_Y = 40; int Prozentsatz_Y = 100;int Area_Y = 70; int Gitter_X = 10; picKopfzeile(mypen, myFont, sbrush, g, 10, rowData); Gitter_X = Gitter_X + 350; for (int i = 0; i < particleData.Rows.Count; i++) { if (Gitter_X+350> list_pano[0].Width) { rowData = rowData + 130; picKopfzeile(mypen, myFont, sbrush, g, 10, rowData); Color_Y = Color_Y + 130; TypeName_Y = TypeName_Y + 130; Prozentsatz_Y = Prozentsatz_Y + 130; Area_Y = Area_Y + 130; Gitter_X = 360; } g.DrawRectangle(mypen, Gitter_X, Color_Y, 350, 30); g.DrawRectangle(mypen, Gitter_X, TypeName_Y, 350, 30); g.DrawRectangle(mypen, Gitter_X, Area_Y, 350, 30); g.DrawRectangle(mypen, Gitter_X, Prozentsatz_Y, 350, 30); SolidBrush mysbrush = new SolidBrush(ColorTranslator.FromHtml(particleData.Rows[i]["Color"].ToString())); g.FillRectangle(mysbrush, Gitter_X + 1, Color_Y + 1, 348, 28); g.DrawString(particleData.Rows[i]["TypeName"].ToString(), myFont, sbrush, Gitter_X + 1, TypeName_Y + 2); g.DrawString(particleData.Rows[i]["Area"].ToString(), myFont, sbrush, Gitter_X + 1, Area_Y + 2); g.DrawString(particleData.Rows[i]["Percentage"].ToString()+"%", myFont, sbrush, Gitter_X + 1, Prozentsatz_Y + 2); Gitter_X = Gitter_X + 350; } list_panos.Add(bitmap); g.Dispose(); } Bitmap combined = MergeImagesVertically(list_panos, (int)OverlapParamPX); NLog.LogManager.GetCurrentClassLogger().Info("Picture splicing completed."); NLog.LogManager.GetCurrentClassLogger().Info("Save to disk......"); OpenCvSharp.Mat save_pano = BitmapConverter.ToMat(combined); if (type == (int)Outpic_enum.GBOne) { imageSplicer.DrawingOfNationalStandardBoxes(GBDatatableOne, GridLength, save_pano); } OpenCvSharp.Cv2.ImWrite(sfd.FileName, save_pano); NLog.LogManager.GetCurrentClassLogger().Info("Save complete."); Control_DrawDistrbutionImageAndBSE v = m_ReportApp.im_Control_DrawDistrbutionImageAndBSE; MyEvent += new MyEntrust(v.msgInform); v.Invoke(MyEvent); } private Bitmap MergeImagesVertically(List images, int overlap) { if (images == null || images.Count == 0) { throw new ArgumentException("输入的图片数组不能为空或没有元素"); } // 计算新Bitmap的宽度和高度 int totalWidth = 0; int totalHeight = 0; // 找到最宽的宽度 foreach (var img in images) { if (img.Width > totalWidth) { totalWidth = img.Width; } //totalHeight += img.Height - (img != images[images.Count - 1] ? overlap : 0); // 最后一张图片不减去重叠 } int imgHeight = (int)OverlapParamPX * (images.Count - 1); totalHeight = images[0].Height * (images.Count-1) - imgHeight; // 为最后一张图片添加完整的高度 if (images.Count > 1) { totalHeight += images[images.Count - 1].Height; } else { // 如果只有一张图片,则不需要调整高度 totalHeight = images[0].Height; } Bitmap result = new Bitmap(totalWidth, totalHeight); using (Graphics g = Graphics.FromImage(result)) { g.Clear(Color.Transparent); // 或者设置为其他背景色 int offsetY = 0; foreach (var img in images) { // 绘制图片,考虑重叠部分 g.DrawImage(img, new Rectangle(0, offsetY, img.Width, img.Height)); // 更新偏移量 offsetY += img.Height - (img != images[images.Count - 1] ? overlap : 0); } } return result; } private int getPICstringLong(DataTable particleData, List list_pano) { int Long = 1; int Gitter_X = 10; for (int i = 0; i < particleData.Rows.Count; i++) { if (Gitter_X + 350 > list_pano[0].Width) { Long = Long + 1; Gitter_X = 10; } Gitter_X = Gitter_X + 350; } return Long; } private void picKopfzeile(Pen mypen, Font myFont, SolidBrush sbrush, Graphics g ,int X,int Y) { int Color_Y = Y; int TypeName_Y = Y+30; int Prozentsatz_Y = Y + 90; int Area_Y = Y+ 60; int Gitter_X = X; g.DrawRectangle(mypen, Gitter_X, Color_Y, 350, 30); g.DrawRectangle(mypen, Gitter_X, TypeName_Y, 350, 30); g.DrawRectangle(mypen, Gitter_X, Area_Y, 350, 30); g.DrawRectangle(mypen, Gitter_X, Prozentsatz_Y, 350, 30); g.DrawString("Color", myFont, sbrush, Gitter_X + 1, Color_Y + 2); g.DrawString("TypeName", myFont, sbrush, Gitter_X + 1, TypeName_Y + 2); g.DrawString("Area", myFont, sbrush, Gitter_X + 1, Area_Y + 2); g.DrawString("Prozentsatz", myFont, sbrush, Gitter_X + 1, Prozentsatz_Y + 2); } private DataTable ParticleDataIntegration(DataTable ParticleAll,DataTable ParticleClass) { DataTable dt = ParticleClass.Copy(); dt.Columns.Add("Area", typeof(float)); dt.Columns.Add("Percentage"); dt.Columns.Add("Color"); double ParticleAreaTotal = 0; for (int i=0;i< ParticleAll.Rows.Count;i++) { ParticleAreaTotal = ParticleAreaTotal + Convert.ToDouble(ParticleAll.Rows[i]["Area"]); } for (int i=0;i< dt.Rows.Count;i++) { double ParticleArea = 0; string ParticleColer = ""; for (int a=0;a< ParticleAll.Rows.Count;a++) { if (dt.Rows[i]["TypeName"].ToString()== ParticleAll.Rows[a]["TypeName"].ToString()) { ParticleArea = ParticleArea + Convert.ToDouble(ParticleAll.Rows[a]["Area"]); ParticleColer = ParticleAll.Rows[a]["TypeColor"].ToString(); } } dt.Rows[i]["Area"] = ParticleArea; dt.Rows[i]["Percentage"] = ParameterNormalization(ParticleAreaTotal, ParticleArea); dt.Rows[i]["Color"] = ParticleColer; } return dt; } /// /// 参数归一化 /// /// 总数 /// 传参 /// private string ParameterNormalization(double a_mi, double m) { double ColVal = Convert.ToDouble(m / a_mi * 100); if (ColVal == 0) { return ""; } else { return Math.Round(ColVal, 2).ToString(); } } #region 合并天宇颗粒融合新增函数 public void opencv_outpic2(/*int type*/) { List list_dt_picdata = new List(); if (type == (int)Outpic_enum.pic || type == (int)Outpic_enum.Combin) { list_dt_picdata = opencv_piclist2(); } else if (type == (int)Outpic_enum.Render_pic || type == (int)Outpic_enum.Render_Combin) { list_dt_picdata = opencv_piclist_Render2(); } OpenCvSharp.Mat save_pano = new OpenCvSharp.Mat(); OpenCvSharp.Mat[] list_mats = new OpenCvSharp.Mat[list_dt_picdata.Count]; if (type == (int)Outpic_enum.Combin || type == (int)Outpic_enum.Render_Combin) { ImageStitchUsingOpenCvSharp cImageHandler = new ImageStitchUsingOpenCvSharp(); Dictionary sampleMembers = ((Dictionary)((Dictionary)resultFile.ResultInfo["Sample"])["Members"]); Dictionary imageProcessParam = (Dictionary)((Dictionary)((Dictionary)sampleMembers["MsrParams"])["Members"])["ImageProcessParam"]; object strOverlapParam = ""; imageProcessParam.TryGetValue("OverlapParam", out strOverlapParam); if (strOverlapParam == null) { NLog.LogManager.GetCurrentClassLogger().Info("There are no overlapping dimensions"); return; } int OverlapParam = int.Parse(strOverlapParam.ToString()); List maxXList = new List(); for (int i = 0; i < list_dt_picdata.Count; i++) { OpenCvSharp.Mat[] mats = new OpenCvSharp.Mat[list_dt_picdata[i].Rows.Count]; for (int a = 0; a < list_dt_picdata[i].Rows.Count; a++) { mats[a] = OpenCvSharp.Extensions.BitmapConverter.ToMat((Bitmap)list_dt_picdata[i].Rows[a]["mat"]); } //横向拼接 maxXList.Add(cImageHandler.CombinImageX(mats, OverlapParam, type)); } save_pano = cImageHandler.CombinImageY(maxXList.ToArray(), OverlapParam, type); OpenCvSharp.Cv2.ImWrite(sfd.FileName, save_pano); NLog.LogManager.GetCurrentClassLogger().Info("Save complete."); } else { NLog.LogManager.GetCurrentClassLogger().Info("Organize and splice all pictures......"); for (int i = 0; i < list_dt_picdata.Count; i++) { OpenCvSharp.Mat[] mats = new OpenCvSharp.Mat[list_dt_picdata[i].Rows.Count]; for (int a = 0; a < list_dt_picdata[i].Rows.Count; a++) { mats[a] = OpenCvSharp.Extensions.BitmapConverter.ToMat((Bitmap)list_dt_picdata[i].Rows[a]["mat"]); } OpenCvSharp.Mat pano = new OpenCvSharp.Mat(); OpenCvSharp.Cv2.HConcat(mats, pano); list_mats[i] = pano; } NLog.LogManager.GetCurrentClassLogger().Info("Picture splicing completed."); NLog.LogManager.GetCurrentClassLogger().Info("Save to disk......"); OpenCvSharp.Cv2.VConcat(list_mats, save_pano); OpenCvSharp.Cv2.ImWrite(sfd.FileName, save_pano); NLog.LogManager.GetCurrentClassLogger().Info("Save complete."); } } private List opencv_piclist_Render2() { List list_dt_picdata = new List(); DataTable picDatat = new DataTable(); List fieldlist = resultFile.List_OTSField; picDatat.Columns.Add("X", typeof(double)); picDatat.Columns.Add("Y", typeof(double)); foreach (var f in m_list_allDfield) { DataRow dr = picDatat.NewRow(); dr["X"] = f.GetShowRect().X; dr["Y"] = f.GetShowRect().Y; picDatat.Rows.Add(dr); } int y_max = Convert.ToInt32(picDatat.Compute("Max(Y)", "true")); int y_min = Convert.ToInt32(picDatat.Compute("Min(Y)", "true")); DataTable total_dt_X = picDatat.Copy(); DataView dv_x = total_dt_X.DefaultView; DataView dv_x_2 = dv_x.ToTable(true, "X").DefaultView; dv_x_2.Sort = "X ASC"; total_dt_X = dv_x_2.ToTable(); DataTable total_dt_Y = picDatat.Copy(); DataView dv_Y = total_dt_Y.DefaultView; DataView dv_Y_2 = dv_Y.ToTable(true, "Y").DefaultView; dv_Y_2.Sort = "Y ASC"; total_dt_Y = dv_Y_2.ToTable(); for (int i = 0; i < total_dt_Y.Rows.Count; i++) { NLog.LogManager.GetCurrentClassLogger().Info("Splice line" + i + 1.ToString() + "of" + total_dt_Y.Rows.Count.ToString() + "....."); DataTable data = new DataTable(); data.Columns.Add("mat", typeof(Bitmap)); data.Columns.Add("X", typeof(double)); for (int a = 0; a < total_dt_X.Rows.Count; a++) { DataRow dr2 = data.NewRow(); Bitmap bitmap = new Bitmap((int)m_list_allDfield[0].GetShowRect().Width, (int)m_list_allDfield[0].GetShowRect().Height); Graphics g = Graphics.FromImage(bitmap); g.Clear(Color.White); g.Dispose(); dr2["mat"] = bitmap; dr2["X"] = total_dt_X.Rows[a]["X"]; data.Rows.Add(dr2); } foreach (var f in m_list_allDfield) { if (total_dt_Y.Rows[i]["Y"].ToString() == f.GetShowRect().Y.ToString()) { for (int c = 0; c < data.Rows.Count; c++) { if (data.Rows[c]["X"].ToString() == f.GetShowRect().X.ToString()) { Bitmap image = new Bitmap(f.OriginalImage.Width, f.OriginalImage.Height); Graphics g2 = Graphics.FromImage(image); g2.DrawImage(f.OriginalImage, 0, 0, f.OriginalImage.Width, f.OriginalImage.Height); Graphics graph_2 = Graphics.FromImage(image); for (int a = 0; a < fieldlist.Count; a++) { if (fieldlist[a].FieldID.ToString() == f.FieldID.ToString()) { //先获取该Field中的所有Particle List list_particle; list_particle = fieldlist[a].ParticleList; //再循环计算所有的Particle对象 foreach (Particle particle in list_particle) { //创建DParticle颗粒 DisplayParticle dp = new DisplayParticle(particle); List list_seg; list_seg = particle.SegmentList; //创建颗粒分布图对应的类对象 List list_dsegment = new List(); //再循环取出里面所有的segment foreach (Segment seg in list_seg) { #region 创建DSegment对象,并将STD分析出的化合物颜色保存到DSegment对象中 System.Drawing.Point on_p = new System.Drawing.Point() { X = seg.Start, Y = seg.Height }; System.Drawing.Point off_p = new System.Drawing.Point() { X = seg.Start + seg.Length, Y = seg.Height }; Pen npen = new Pen(dp.Color); graph_2.DrawLine(npen, on_p, off_p); #endregion } } } } data.Rows[c]["mat"] = image; data.Rows[c]["X"] = f.GetShowRect().X; } } } } DataView dataView1 = data.DefaultView; dataView1.Sort = "X ASC"; data = dataView1.ToTable(); list_dt_picdata.Add(data); } return list_dt_picdata; } /// /// 获取每行图片的位置配合opencv方法使用 /// /// private List opencv_piclist2() { List list_dt_picdata = new List(); DataTable picDatat = new DataTable(); picDatat.Columns.Add("X", typeof(double)); picDatat.Columns.Add("Y", typeof(double)); foreach (var f in m_list_allDfield) { DataRow dr = picDatat.NewRow(); dr["X"] = f.GetShowRect().X; dr["Y"] = f.GetShowRect().Y; picDatat.Rows.Add(dr); } int y_max = Convert.ToInt32(picDatat.Compute("Max(Y)", "true")); int y_min = Convert.ToInt32(picDatat.Compute("Min(Y)", "true")); DataTable total_dt_X = picDatat.Copy(); DataView dv_x = total_dt_X.DefaultView; DataView dv_x_2 = dv_x.ToTable(true, "X").DefaultView; dv_x_2.Sort = "X ASC"; total_dt_X = dv_x_2.ToTable(); DataTable total_dt_Y = picDatat.Copy(); DataView dv_Y = total_dt_Y.DefaultView; DataView dv_Y_2 = dv_Y.ToTable(true, "Y").DefaultView; dv_Y_2.Sort = "Y ASC"; total_dt_Y = dv_Y_2.ToTable(); for (int i = 0; i < total_dt_Y.Rows.Count; i++) { NLog.LogManager.GetCurrentClassLogger().Info("Splice line" + i + 1.ToString() + "of" + total_dt_Y.Rows.Count.ToString() + "....."); DataTable data = new DataTable(); data.Columns.Add("mat", typeof(Bitmap)); data.Columns.Add("X", typeof(double)); for (int a = 0; a < total_dt_X.Rows.Count; a++) { DataRow dr2 = data.NewRow(); Bitmap bitmap = new Bitmap((int)m_list_allDfield[0].GetShowRect().Width, (int)m_list_allDfield[0].GetShowRect().Height); Graphics g = Graphics.FromImage(bitmap); g.Clear(Color.White); g.Dispose(); dr2["mat"] = bitmap; dr2["X"] = total_dt_X.Rows[a]["X"]; data.Rows.Add(dr2); } foreach (var f in m_list_allDfield) { if (total_dt_Y.Rows[i]["Y"].ToString() == f.GetShowRect().Y.ToString()) { for (int c = 0; c < data.Rows.Count; c++) { if (data.Rows[c]["X"].ToString() == f.GetShowRect().X.ToString()) { data.Rows[c]["mat"] = f.OriginalImage; data.Rows[c]["X"] = f.GetShowRect().X; } } } } DataView dataView1 = data.DefaultView; dataView1.Sort = "X ASC"; data = dataView1.ToTable(); list_dt_picdata.Add(data); } return list_dt_picdata; } #endregion public delegate void MyEntrust(); public event MyEntrust MyEvent; } }