using OTSDataType; using OTSModelSharp.ImageProcess; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using static OTSDataType.otsdataconst; namespace OTSModelSharp.ServiceInterface { using OpenCvSharp; using OTSCLRINTERFACE; using OTSIMGPROC; using OTSModelSharp.DTLBase; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Windows; public class CImageHandler:IImageProcess { #region 通过byte数组生成BMP图像文件 /// /// 将一个byte的数组转换为8bit灰度位图 /// /// 数组 /// 图像宽度 /// 图像高度 /// 位图 public static Bitmap ToGrayBitmap(byte[] data, int width, int height) { if (width == 0 || height == 0) return null; //// 申请目标位图的变量,并将其内存区域锁定 Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed); //// BitmapData这部分内容 需要 using System.Drawing.Imaging; BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); //// 获取图像参数 // 扫描线的宽度 int stride = bmpData.Stride; // 显示宽度与扫描线宽度的间隙 int offset = stride - width; // 获取bmpData的内存起始位置 IntPtr iptr = bmpData.Scan0; // 用stride宽度,表示这是内存区域的大小 int scanBytes = stride * height; //// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组 int posScan = 0; int posReal = 0;// 分别设置两个位置指针,指向源数组和目标数组 byte[] pixelValues = new byte[scanBytes]; //为目标数组分配内存 //for (int x = height-1;x>=0 ; x--) data[startIndex+ y];// for (int x = 0; x < height; x++) { int startIndex = x * width; //// 下面的循环节是模拟行扫描 for (int y = 0; y < width; y++) { pixelValues[posScan++] = data[posReal++]; } posScan += offset; //行扫描结束,要将目标位置指针移过那段“间隙” } //// 用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中 System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes); bmp.UnlockBits(bmpData); // 解锁内存区域 //// 下面的代码是为了修改生成位图的索引表,从伪彩修改为灰度 ColorPalette tempPalette; using (Bitmap tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)) { tempPalette = tempBmp.Palette; } for (int i = 0; i < 256; i++) { tempPalette.Entries[i] = Color.FromArgb(i, i, i); } bmp.Palette = tempPalette; return bmp; } #endregion public static byte[] BitmapToGrayByte(Bitmap bitmap) { // 申请目标位图的变量,并将其内存区域锁定 BitmapData bitmapDat = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); // 获取bmpData的内存起始位置 IntPtr intPtr = bitmapDat.Scan0; byte[] image = new byte[bitmap.Width * bitmap.Height];//原始数据 Marshal.Copy(intPtr, image, 0, bitmap.Width * bitmap.Height); // 将数据复制到byte数组中, //解锁内存区域 bitmap.UnlockBits(bitmapDat); return image; } //获取测量的BSE图 //COTSSample WSample: 工作样品测量 //Byte[] BSEImage: 带背景图数据 //int iHeight: 图像高度 //int iWidth: 图像宽度 //Byte[]BSEImageNoBG : 去背景图数据 public bool GetBSEImage(COTSImageProcParam ImgProcPrm, double pixelSize, byte[] BSEImage, int iHeight, int iWidth, ref byte[] BSEImageNoBG) { Rectangle rect = new Rectangle(); rect.Height = iHeight; rect.Width = iWidth; CBSEImgClr pBSEImageIn = new CBSEImgClr(rect); CBSEImgClr pBSEImageOut = new CBSEImgClr(rect); //pBSEImageIn.SetImageRect(rect); pBSEImageIn.SetImageData(BSEImage,iWidth, iHeight ); //pBSEImageOut.SetImageRect(rect); if (null == ImgProcPrm) { return false; } RemoveBackGround(pBSEImageIn, ImgProcPrm, pixelSize ,ref pBSEImageOut); BSEImageNoBG = pBSEImageOut.GetImageDataPtr(); return true; } /// /// 获取测量的BSE图 /// /// BSE原数据 /// 图像高度 /// 图像宽度 /// /// /// 去背景图数据 /// public bool GetBSEImage(byte[] BSEImage, int iHeight, int iWidth, int grayStart, int grayEnd, ref byte[] BSEImageNoBG) { Rectangle rect = new Rectangle(); rect.Height = iHeight; rect.Width = iWidth; CBSEImgClr pBSEImageIn = new CBSEImgClr(rect); CBSEImgClr pBSEImageOut = new CBSEImgClr(rect); //pBSEImageIn.SetImageRect(rect); pBSEImageIn.SetImageData(BSEImage, iWidth, iHeight ); CIntRangeClr cIntRangeClr = new CIntRangeClr(); cIntRangeClr.SetStart(grayStart); cIntRangeClr.SetEnd(grayEnd); OTSCLRINTERFACE.ImageProForClr imgpro = new OTSCLRINTERFACE.ImageProForClr(); int num=0; imgpro.GetSpecialGrayRangeImage(pBSEImageIn, cIntRangeClr, pBSEImageOut,ref num); for (int i = 0; i < iWidth; i++) { for (int j = 0; j < iHeight; j++) { var bse = pBSEImageOut.GetBSEValue(i, j); if (bse == 255) { var originalBse = pBSEImageIn.GetBSEValue(i, j); pBSEImageOut.SetBSEValue(i, j, originalBse); } else { pBSEImageOut.SetBSEValue(i, j, 255); } } } BSEImageNoBG = pBSEImageOut.GetImageDataPtr(); return true; } // remove background public void RemoveBackGround(CBSEImgClr a_pImgIn, COTSImageProcParam a_pImgProcessParam, double a_pixelSize, ref CBSEImgClr a_pImgOut) { List parts = new List(); List specialGreyparts = new List(); if (!RemoveBGAndGetParts(a_pImgIn, a_pImgProcessParam, a_pixelSize, ref parts)) { return; } if (a_pImgProcessParam.GetSpecialGreyRangeParam().GetIsToRun()) { var param = a_pImgProcessParam.GetSpecialGreyRangeParam(); var ranges = param.GetSpecialGreyRanges(); foreach (var r in ranges) { CIntRangeClr r1 = new CIntRangeClr(); r1.SetStart(r.range.GetStart()); r1.SetEnd(r.range.GetEnd()); CDoubleRangeClr r2 = new CDoubleRangeClr(); r2.SetStart(r.diameterRange.GetStart()); r2.SetEnd(r.diameterRange.GetEnd()); GetParticlesBySpecialGray(a_pImgIn, r1, r2, a_pixelSize, ref specialGreyparts); } } for (int i = 0; i < a_pImgOut.GetWidth(); i++) { for (int j = 0; j < a_pImgOut.GetHeight(); j++) { a_pImgOut.SetBSEValue(i, j, 255); } } if (specialGreyparts.Count > 0) { foreach (var p in specialGreyparts) { foreach (var s in p.GetFeature().GetSegmentsList()) { for (int i = s.GetStart(); i < s.GetStart() + s.GetLength(); i++) { var bseValue = a_pImgIn.GetBSEValue(i, s.GetHeight()); a_pImgOut.SetBSEValue(i, s.GetHeight(), bseValue); } } } } foreach (var p in parts) { foreach (var s in p.GetFeature().GetSegmentsList()) { for (int i = s.GetStart(); i < s.GetStart() + s.GetLength(); i++) { var bseValue = a_pImgIn.GetBSEValue(i, s.GetHeight()); a_pImgOut.SetBSEValue(i, s.GetHeight(), bseValue); } } } return; } public void BDilate3(string source, string target, int wDegree, int rows, int columns) { throw new NotImplementedException(); } public void BErode3(string source, string target, int wDegree, int rows, int columns) { throw new NotImplementedException(); } public bool CalParticleImageProp( COTSParticleClr part, double a_pixelSize) { OTSCLRINTERFACE.ImageProForClr imgpro = new OTSCLRINTERFACE.ImageProForClr(); imgpro.CalcuParticleImagePropertes(part,a_pixelSize); return true; } public bool RemoveBGAndGetParts(CBSEImgClr img, COTSImageProcParam a_pImgProcessParam,double a_pixelSize,ref List parts) { OTSCLRINTERFACE.ImageProForClr imgpro = new OTSCLRINTERFACE.ImageProForClr(); OTSCLRINTERFACE.COTSImgProcPrmClr prm = GetImageProcPrmClr(a_pImgProcessParam); OTSCLRINTERFACE.COTSFieldDataClr flddataclr = new OTSCLRINTERFACE.COTSFieldDataClr(); if (!imgpro.GetFieldDataFromImage(img, prm, a_pixelSize, flddataclr)) { return false; } parts = flddataclr.GetParticleList(); return true; } public bool GetParticlesBySpecialGray(CBSEImgClr img, CIntRangeClr grayrange, CDoubleRangeClr diameterRange,double a_pixelSize, ref List parts) { OTSCLRINTERFACE.ImageProForClr imgpro = new OTSCLRINTERFACE.ImageProForClr(); //OTSCLRINTERFACE.COTSImgProcPrmClr prm = GetImageProcPrmClr(a_pImgProcessParam); OTSCLRINTERFACE.COTSFieldDataClr flddataclr = new OTSCLRINTERFACE.COTSFieldDataClr(); imgpro.GetParticlesBySpecialPartGrayRange(img, grayrange,diameterRange,a_pixelSize, flddataclr); parts = flddataclr.GetParticleList(); return true; } private COTSImgProcPrmClr GetImageProcPrmClr(COTSImageProcParam a_oSource) { COTSImgProcPrmClr prmclr = new COTSImgProcPrmClr(); OTSCLRINTERFACE.CDoubleRangeClr r1 = new OTSCLRINTERFACE.CDoubleRangeClr(a_oSource.GetIncAreaRange().GetStart(), a_oSource.GetIncAreaRange().GetEnd()); prmclr.SetIncArea(r1); OTSCLRINTERFACE.CIntRangeClr r2= new OTSCLRINTERFACE.CIntRangeClr(a_oSource.GetBGGray().GetStart(), a_oSource.GetBGGray().GetEnd()); prmclr.SetBGGray(r2); OTSCLRINTERFACE.CIntRangeClr r3= new OTSCLRINTERFACE.CIntRangeClr(a_oSource.GetParticleGray().GetStart(), a_oSource.GetParticleGray().GetEnd()); prmclr.SetParticleGray(r3); prmclr.SetBGRemoveType((int)a_oSource.GetBGRemoveType()); prmclr.SetAutoBGRemoveType((int)a_oSource.GetAutoBGRemoveType()); prmclr.SetErrodDilateParam(a_oSource.GetErrodDilateParam()); prmclr.SetOverlapParam(a_oSource.GetOverlapParam()); return prmclr; } public bool MergeBigBoundaryParticles(List allFields, int overlap, double pixelSize, int scanFieldSize, System.Drawing.Size ResolutionSize, ref List mergedParts) { List fldclrs = new List(); foreach (var f in allFields) { COTSFieldDataClr fldclr = new COTSFieldDataClr(); PointF p1 = f.GetOTSPosition(); System.Drawing.Point p2 = new System.Drawing.Point((int)p1.X, (int)p1.Y); fldclr.SetPosition(p2); fldclr.SetImageWidth(f.Width); fldclr.SetImageHeight(f.Height); var parts = f.GetListAnalysisParticles(); foreach (var p in parts) { fldclr.AddParticle(p); } fldclrs.Add(fldclr); } OTSCLRINTERFACE.ImageProForClr imgpro = new OTSCLRINTERFACE.ImageProForClr(); imgpro.MergeBigBoundaryParticles(fldclrs, overlap, pixelSize, scanFieldSize, ResolutionSize, mergedParts); return true; } /// /// 根据Segment寻找边缘坐标点 /// /// /// /// /// public static List FindContoursBySegment(int width, int height, List segmentClrs) { List points = new List(); using (Mat mat = new Mat(height, width, MatType.CV_8UC1, new Scalar(0))) { for (int i = 0; i < segmentClrs.Count; i++) { Cv2.Line(mat, new OpenCvSharp.Point(segmentClrs[i].GetStart(), segmentClrs[i].GetHeight()), new OpenCvSharp.Point(segmentClrs[i].GetStart() + segmentClrs[i].GetLength(), segmentClrs[i].GetHeight()), Scalar.White, 1, LineTypes.AntiAlias); } Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(mat, out contours, out hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple, null); for (int i = 0; i < contours.ToList().Count(); i++) { for (int j = 0; j < contours[i].Count(); j++) { System.Drawing.Point point = new System.Drawing.Point(contours[i][j].X, contours[i][j].Y); if (!points.Contains(point)) { points.Add(point); } } } } return points; } public bool RepeatedParticleTreatment(List allFields, COTSSample theSample, string stdPath) { int maxPartCount = theSample.GetMsrParams().GetXRayParam().GetXrayLimit(); int overlap = theSample.GetMsrParams().GetImageProcessParam().GetOverlapParam(); double pixelSize = theSample.CalculatePixelSize(); System.Drawing.Size resolutionSize = theSample.GetResolutionSize(); int scanFieldSizeX = theSample.GetSEMDataMsr().GetScanFieldSize(); int scanFieldSizeY = scanFieldSizeX * resolutionSize.Height / resolutionSize.Width; int offsetX = scanFieldSizeX - (int)(overlap * pixelSize); int offsetY = scanFieldSizeY - (int)(overlap * pixelSize); List deletePartList = new List(); List updatePartList= new List(); Dictionary combinBorderParts = new Dictionary(); List combinBorderParts_style = new List(); foreach (var item in allFields) { if (!item.GetIsMeasureComplete()) { break; } //找到上下左右四帧图 List leftField = allFields.Where(a => a.OTSPos == new System.Drawing.PointF(item.OTSPos.X - offsetX, item.OTSPos.Y)).ToList(); List rightField = allFields.Where(a => a.OTSPos == new System.Drawing.PointF(item.OTSPos.X + offsetX, item.OTSPos.Y)).ToList(); List upField = allFields.Where(a => a.OTSPos == new System.Drawing.PointF(item.OTSPos.X, item.OTSPos.Y + offsetY)).ToList(); List downField = allFields.Where(a => a.OTSPos == new System.Drawing.PointF(item.OTSPos.X, item.OTSPos.Y - offsetY)).ToList(); //判断是否有效 if (leftField.Count() == 1)//包含左帧图 { if (leftField[0].GetIsMeasureComplete() == true)//存在测量帧图 { //寻找重叠颗粒 deletePartList.AddRange(FieldFun(leftField[0], item, "left_right", resolutionSize, overlap, ref combinBorderParts, ref combinBorderParts_style)); } } if (rightField.Count() == 1)//包含右帧图 { if (rightField[0].GetIsMeasureComplete() == true)//存在测量帧图 { //寻找重叠颗粒 deletePartList.AddRange(FieldFun(item, rightField[0], "left_right", resolutionSize, overlap, ref combinBorderParts, ref combinBorderParts_style)); } } if (upField.Count() == 1)//包含上帧图 { if (upField[0].GetIsMeasureComplete() == true)//存在测量帧图 { //寻找重叠颗粒 deletePartList.AddRange(FieldFun(upField[0], item, "up_down", resolutionSize, overlap, ref combinBorderParts, ref combinBorderParts_style)); } } if (downField.Count() == 1)//包含下帧图 { if (downField[0].GetIsMeasureComplete() == true)//存在测量帧图 { //寻找重叠颗粒 deletePartList.AddRange(FieldFun(item, downField[0], "up_down", resolutionSize, overlap, ref combinBorderParts, ref combinBorderParts_style)); } } } //数据库操作 SQLiteHelper sQLiteHelper = new SQLiteHelper(stdPath); sQLiteHelper.GetDBConnection(); sQLiteHelper.BeginTransaction(); deletePartList = deletePartList.Distinct().ToList();//去重 if (!sQLiteHelper.DeletePartForTransaction(deletePartList))//删除重复颗粒 { return false; } if (!sQLiteHelper.CombinPartForTransaction(allFields, combinBorderParts, updatePartList, combinBorderParts_style, resolutionSize))//合并大颗粒 { return false; } if (!sQLiteHelper.UpdatePartForTransaction(updatePartList))//修改Segment { return false; } sQLiteHelper.CommitTransaction(); return true; } private List FieldFun(COTSFieldData left_upField, COTSFieldData right_downField, string style, System.Drawing.Size resolutionSize, int overlap, ref Dictionary combinBorderParts, ref List combinBorderParts_style) { List particleClrs = new List(); combinBorderParts = new Dictionary(); if (style == "left_right") { //寻找左帧图的右侧区域颗粒 double left_upField_sum = 0; double right_downField_sum = 0; List leftBorderParts = new List(); List rightBorderParts = new List(); foreach (var leftParticles in left_upField.GetListAnalysisParticles()) { Rectangle leftRectangle = (Rectangle)leftParticles.GetParticleRect(); if (leftRectangle.Right > resolutionSize.Width - overlap / 2)//未跨界 { left_upField_sum += leftParticles.GetActualArea(); } if (leftRectangle.Right == resolutionSize.Width || leftRectangle.Right == resolutionSize.Width - 1)//边界 { leftBorderParts.Add(leftParticles); } } foreach (var rightParticles in right_downField.GetListAnalysisParticles()) { Rectangle rightRectangle = (Rectangle)rightParticles.GetParticleRect(); if (rightRectangle.Left > overlap / 2)//未跨界 { right_downField_sum += rightParticles.GetActualArea(); } if (rightRectangle.Left == 0)//边界 { rightBorderParts.Add(rightParticles); } } foreach (var leftBorder in leftBorderParts) { Rectangle leftRectangle = (Rectangle)leftBorder.GetParticleRect(); foreach (var rightBorder in rightBorderParts) { Rectangle rightRectangle = (Rectangle)rightBorder.GetParticleRect(); bool isTrue = false; for (int i = leftRectangle.Y; i < leftRectangle.Y + leftRectangle.Height; i++) { if (i > rightRectangle.Y && i < rightRectangle.Y + rightRectangle.Height) { combinBorderParts.Add(leftBorder, rightBorder); combinBorderParts_style.Add("left"); isTrue = true; break; } } if (isTrue) { break; } } } if (left_upField_sum < right_downField_sum) { foreach (var leftParticles in left_upField.GetListAnalysisParticles()) { Rectangle leftRectangle = (Rectangle)leftParticles.GetParticleRect(); if (leftRectangle.Left > resolutionSize.Width - overlap)//未跨界 { if (!combinBorderParts.ContainsKey(leftParticles)) { particleClrs.Add(leftParticles); } } } } else { foreach (var downParticles in right_downField.GetListAnalysisParticles()) { Rectangle downRectangle = (Rectangle)downParticles.GetParticleRect(); if (downRectangle.Right < overlap / 2)//未跨界 { if (!combinBorderParts.ContainsValue(downParticles)) { particleClrs.Add(downParticles); } } } } } else { //寻找上帧图的下侧区域颗粒 double left_upField_sum = 0; double right_downField_sum = 0; List upBorderParts = new List(); List downBorderParts = new List(); foreach (var upParticles in left_upField.GetListAnalysisParticles()) { Rectangle upRectangle = (Rectangle)upParticles.GetParticleRect(); if (upRectangle.Top > resolutionSize.Height - overlap / 2)//未跨界 { left_upField_sum += upParticles.GetActualArea(); } if (upRectangle.Bottom == resolutionSize.Height || upRectangle.Bottom == resolutionSize.Height - 1)//边界 { upBorderParts.Add(upParticles); } } foreach (var downParticles in right_downField.GetListAnalysisParticles()) { Rectangle downRectangle = (Rectangle)downParticles.GetParticleRect(); if (downRectangle.Top > resolutionSize.Height - overlap / 2)//未跨界 { right_downField_sum += downParticles.GetActualArea(); } if (downRectangle.Top == 0)//边界 { downBorderParts.Add(downParticles); } else if (downRectangle.Top == 1)//边界 { downBorderParts.Add(downParticles); } } foreach (var upBorder in upBorderParts) { Rectangle upRectangle = (Rectangle)upBorder.GetParticleRect(); foreach (var downBorder in downBorderParts) { Rectangle downRectangle = (Rectangle)downBorder.GetParticleRect(); bool isTrue = false; for (int i = upRectangle.X; i < upRectangle.X + upRectangle.Width; i++) { if (i > downRectangle.X && i < downRectangle.X + downRectangle.Width) { combinBorderParts.Add(upBorder, downBorder); combinBorderParts_style.Add("up"); isTrue = true; break; } } if (isTrue) { break; } } } if (left_upField_sum < right_downField_sum) { foreach (var upParticles in left_upField.GetListAnalysisParticles()) { Rectangle upRectangle = (Rectangle)upParticles.GetParticleRect(); if (upRectangle.Top > resolutionSize.Height - overlap / 2)//未跨界 { if (!combinBorderParts.ContainsKey(upParticles)) { particleClrs.Add(upParticles); } } } } else { foreach (var downParticles in right_downField.GetListAnalysisParticles()) { Rectangle downRectangle = (Rectangle)downParticles.GetParticleRect(); if (downRectangle.Bottom < overlap / 2)//未跨界 { if (!combinBorderParts.ContainsValue(downParticles)) { particleClrs.Add(downParticles); } } } } } return particleClrs; } public Mat CombinImageX(Mat[] list_mats, int OverlapParam, int type) { List matStitch = new List();//拼接 List matCombin = new List();//合并 for (int i = 0; i < list_mats.Count(); i++) { if (i == 0)//首张 { matCombin.Add(new Mat(list_mats[i], new Rect(0, 0, list_mats[i].Width - OverlapParam - 100, list_mats[i].Height))); matStitch.Add(new Mat(list_mats[i], new Rect(list_mats[i].Width - OverlapParam - 100, 0, OverlapParam + 100, list_mats[i].Height))); } else if(i == list_mats.Count() - 1)//末张 { matStitch.Add(new Mat(list_mats[i], new Rect(0, 0, OverlapParam + 100, list_mats[i].Height))); matCombin.Add(new Mat(list_mats[i], new Rect(OverlapParam + 100, 0, list_mats[i].Width - OverlapParam - 100, list_mats[i].Height))); } else { matStitch.Add(new Mat(list_mats[i], new Rect(0, 0, OverlapParam + 100, list_mats[i].Height))); matCombin.Add(new Mat(list_mats[i], new Rect(OverlapParam + 100, 0, list_mats[i].Width - (OverlapParam + 100) * 2, list_mats[i].Height))); matStitch.Add(new Mat(list_mats[i], new Rect(list_mats[i].Width - OverlapParam - 100, 0, OverlapParam + 100, list_mats[i].Height))); } } for (int i = 0; i < matStitch.Count; i += 2) { if (matStitch.Count == 1) { matCombin.Insert(i + 1, matStitch[i]); } else { matCombin.Insert(i + 1, StitchImageX((int)(OverlapParam / 2 * 1.2), type, matStitch[i], matStitch[i + 1])); } } Mat pano = new OpenCvSharp.Mat(); Cv2.HConcat(matCombin.ToArray(), pano); return pano; } public Mat CombinImageY(Mat[] list_mats, int OverlapParam, int type) { List matStitch = new List();//拼接 List matCombin = new List();//合并 for (int i = 0; i < list_mats.Count(); i++) { if (i == 0)//首张 { matCombin.Add(new Mat(list_mats[i], new Rect(0, 0, list_mats[i].Width, list_mats[i].Height - OverlapParam - 100))); matStitch.Add(new Mat(list_mats[i], new Rect(0, list_mats[i].Height - OverlapParam - 100, list_mats[i].Width, OverlapParam + 100))); } else if (i == list_mats.Count() - 1)//末张 { matStitch.Add(new Mat(list_mats[i], new Rect(0, 0, list_mats[i].Width, OverlapParam + 100))); matCombin.Add(new Mat(list_mats[i], new Rect(0, OverlapParam + 100, list_mats[i].Width, list_mats[i].Height - OverlapParam - 100))); } else { matStitch.Add(new Mat(list_mats[i], new Rect(0, 0, list_mats[i].Width, OverlapParam + 100))); matCombin.Add(new Mat(list_mats[i], new Rect(0, OverlapParam + 100, list_mats[i].Width, list_mats[i].Height - (OverlapParam + 100) * 2))); matStitch.Add(new Mat(list_mats[i], new Rect(0, list_mats[i].Height - OverlapParam - 100, list_mats[i].Width, OverlapParam + 100))); } } for (int i = 0; i < matStitch.Count; i += 2) { if (matStitch.Count == 1) { matCombin.Insert(i + 1, matStitch[i]); } else { matCombin.Insert(i + 1, StitchImageY(OverlapParam, type, matStitch[i], matStitch[i + 1])); } } Mat pano = new OpenCvSharp.Mat(); Cv2.VConcat(matCombin.ToArray(), pano); return pano; } public struct MStitch { public int Pwidth;//单幅图像的宽度 public int Pheight;//单幅图像的高度 public int W_min;//最小的重叠区域宽度 public int W_max;//最大的重叠区域宽度 public int H_min;//最小的重叠区域高度 public double minval;//块过滤阈值 public Mat im;//图像信息 } public struct ImageParam { public int W_box;//宽度信息 public int H_box;//高度信息 public int bdown;//上下信息 public MStitch mStitch; //参数结构 public Mat im;//图像信息 } /// /// 横向拼图 /// public Mat StitchImageXGrid(int min_w, int type, Mat newImg1, Mat newImg2) { MStitch mStitch = new MStitch(); mStitch.Pwidth = newImg1.Width; mStitch.Pheight = newImg1.Height; mStitch.W_min = min_w - 50; mStitch.W_max = min_w + 50; mStitch.H_min = newImg1.Height; mStitch.minval = 255; mStitch.im = newImg1; ImageParam imageParam = Fun_Match(newImg2, mStitch); imageParam.im = newImg2; if (type == 2) { return Fun_Stitch(imageParam); } else { return Fun_StitchRGB(imageParam); } } /// /// 纵向拼图 /// public Mat StitchImageYGrid(int min_w, int type, Mat newImg1, Mat newImg2) { Cv2.Transpose(newImg1, newImg1); Cv2.Flip(newImg1, newImg1, FlipMode.X); Cv2.Transpose(newImg2, newImg2); Cv2.Flip(newImg2, newImg2, FlipMode.X); MStitch mStitch = new MStitch(); mStitch.Pwidth = newImg1.Width; mStitch.Pheight = newImg1.Height; mStitch.W_min = min_w - 50; mStitch.W_max = min_w + 50; mStitch.H_min = newImg1.Height; mStitch.minval = 255; mStitch.im = newImg1; ImageParam imageParam = Fun_Match(newImg2, mStitch); imageParam.im = newImg2; Mat result = type == 2 ? Fun_Stitch(imageParam) : Fun_StitchRGB(imageParam); Cv2.Transpose(result, result); Cv2.Flip(result, result, FlipMode.Y); return result; } /// /// 横向拼图 /// public Mat StitchImageX(int min_w, int type, Mat newImg1, Mat newImg2) { MStitch mStitch = new MStitch(); mStitch.Pwidth = newImg1.Width; mStitch.Pheight = newImg1.Height; mStitch.W_min = min_w; mStitch.W_max = min_w; mStitch.H_min = newImg1.Height; mStitch.minval = 255; mStitch.im = newImg1; ImageParam imageParam = Fun_Match(newImg2, mStitch); imageParam.im = newImg2; if (type == 2) { return Fun_Stitch(imageParam); } else { return Fun_StitchRGB(imageParam); } } /// /// 纵向拼图 /// public Mat StitchImageY(int min_w, int type, Mat newImg1, Mat newImg2) { Cv2.Transpose(newImg1, newImg1); Cv2.Flip(newImg1, newImg1, FlipMode.X); Cv2.Transpose(newImg2, newImg2); Cv2.Flip(newImg2, newImg2, FlipMode.X); MStitch mStitch = new MStitch(); mStitch.Pwidth = newImg1.Width; mStitch.Pheight = newImg1.Height; mStitch.W_min = min_w - 50; mStitch.W_max = min_w - 50; mStitch.H_min = newImg1.Height - 20; mStitch.minval = 255; mStitch.im = newImg1; ImageParam imageParam = Fun_Match(newImg2, mStitch); imageParam.im = newImg2; Mat result = type == 2 ? Fun_Stitch(imageParam) : Fun_StitchRGB(imageParam); Cv2.Transpose(result, result); Cv2.Flip(result, result, FlipMode.Y); return result; } public static ImageParam Fun_Match(Mat im2, MStitch mStitch) { ImageParam imageParam = new ImageParam(); double imsum = 0; int x1 = 0; int y1 = 0; int x2 = 0; int y2 = 0; int w_ind = 0; int h_ind = 0; //在上窗口所有匹配块内进行搜索 for (int w = mStitch.W_min; w <= mStitch.W_max; w++) { for (int h = mStitch.H_min; h <= mStitch.Pheight; h++) { imsum = 0;//块差分集初始化 x2 = 1; for (x1 = mStitch.Pwidth - w; x1 <= mStitch.Pwidth; x1 += 5) { y2 = 1; for (y1 = mStitch.Pheight - h + 1; y1 <= mStitch.Pheight; y1 += 5) { //块差分集计算 CheckRC(ref x1, ref y1, mStitch.im); CheckRC(ref x2, ref y2, im2); imsum = imsum + Math.Abs(mStitch.im.At(y1, x1).Item0 - im2.At(y2, x2).Item0); y2 = y2 + 5; } x2 = x2 + 5; } //阈值更新 if (imsum * 5 * 5 <= mStitch.minval * w * h) { mStitch.minval = imsum * 5 * 5 / (w * h); w_ind = w; h_ind = h; } } } imageParam.W_box = w_ind; imageParam.H_box = h_ind; imageParam.bdown = 1; //在下窗口所有匹配块内进行搜索 Parallel.For(mStitch.W_min, mStitch.W_max, w => { Parallel.For(mStitch.H_min, mStitch.Pheight, h => { imsum = 0;//块差分集初始化 x2 = 1; for (x1 = mStitch.Pwidth - w; x1 <= mStitch.Pwidth; x1 += 5) { y1 = 1; for (y2 = mStitch.Pheight - h + 1; y2 <= mStitch.Pheight; y2 += 5) { //块差分集计算 CheckRC(ref x1, ref y1, mStitch.im); CheckRC(ref x2, ref y2, im2); imsum = imsum + Math.Abs(mStitch.im.At(y1, x1).Item0 - im2.At(y2, x2).Item0); y1 = y1 + 5; } x2 = x2 + 5; } //阈值更新 if (imsum * 5 * 5 <= mStitch.minval * w * h) { mStitch.minval = imsum * 5 * 5 / (w * h); w_ind = w; h_ind = h; imageParam.bdown = 0; } }); }); imageParam.mStitch = mStitch; return imageParam; } public static void CheckRC(ref int x, ref int y, Mat im) { //图像矩阵访问有效性检测 // 输入参数: // x——列 // y——行 // im——图像矩阵 // 输出参数: // x——列 // y——行 y = Math.Max(y, 1); y = Math.Min(y, im.Height - 1); x = Math.Max(x, 1); x = Math.Min(x, im.Width - 1); } public Mat Fun_Stitch(ImageParam imageParam) { //图像融合 //输入参数: //im2——待融合图像 //W_box——宽度信息 //H_box——高度信息 //bdown——上下信息 //MStitch——参数结构 //输出参数: //MStitch——参数结构 //im——融合图像 Mat img = imageParam.im; int x1 = 0; int y1 = 0; int x2 = 0; int y2 = 0; double w = 0.5; //融合权值 if (imageParam.bdown == 1) { //下区域重叠 x2 = 1; //融合重叠区域 for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++) { y2 = 1; for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++) { //安全性检测 CheckRC(ref x1, ref y1, imageParam.mStitch.im); CheckRC(ref x2, ref y2, imageParam.im); //融合权值 w = (double)x2 / (double)imageParam.W_box; //加权融合 double ColorRGB = imageParam.mStitch.im.At(y1, x1).Item0 * (1.0 - w) + imageParam.im.At(y2, x2).Item0 * w; imageParam.mStitch.im.Set(y1, x1, new Vec3b((byte)ColorRGB, (byte)ColorRGB, (byte)ColorRGB)); y2 = y2 + 1; } x2 = x2 + 1; } } else { //上区域重叠 x2 = 1; //融合重叠区域 for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++) { y2 = 1; for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++) { //安全性检测 CheckRC(ref x1, ref y1, imageParam.mStitch.im); CheckRC(ref x2, ref y2, imageParam.im); //融合权值 w = (double)x2 / (double)imageParam.W_box; //加权融合 double ColorRGB = imageParam.mStitch.im.At(y1, x1).Item0 * (1.0 - w) + imageParam.im.At(y2, x2).Item0 * w; imageParam.mStitch.im.Set(y1, x1, new Vec3b((byte)ColorRGB, (byte)ColorRGB, (byte)ColorRGB)); y2 = y2 + 1; } x2 = x2 + 1; } } //最终图 img = new Mat(imageParam.mStitch.Pheight, imageParam.mStitch.Pwidth + imageParam.im.Width - x2 + 1, MatType.CV_8UC3); //分离出重叠区域 Rect m_select = new Rect(x2 - 1, 0, imageParam.im.Width - x2 + 1, imageParam.mStitch.Pheight); Mat imgSwitch = new Mat(imageParam.im, m_select); Cv2.HConcat(imageParam.mStitch.im, imgSwitch, img); return img; } public Mat Fun_StitchRGB(ImageParam imageParam) { //图像融合 //输入参数: //im2——待融合图像 //W_box——宽度信息 //H_box——高度信息 //bdown——上下信息 //MStitch——参数结构 //输出参数: //MStitch——参数结构 //im——融合图像 Mat img = imageParam.im; int x1 = 0; int y1 = 0; int x2 = 0; int y2 = 0; double w = 0.5; //融合权值 if (imageParam.bdown == 1) { //下区域重叠 x2 = 1; //融合重叠区域 for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++) { y2 = 1; for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++) { //安全性检测 CheckRC(ref x1, ref y1, imageParam.mStitch.im); CheckRC(ref x2, ref y2, imageParam.im); //融合权值 w = (double)x2 / (double)imageParam.W_box; //加权融合 double ColorR = imageParam.mStitch.im.At(y1, x1).Item0 * (1.0 - w) + imageParam.im.At(y2, x2).Item0 * w; double ColorG = imageParam.mStitch.im.At(y1, x1).Item1 * (1.0 - w) + imageParam.im.At(y2, x2).Item1 * w; double ColorB = imageParam.mStitch.im.At(y1, x1).Item2 * (1.0 - w) + imageParam.im.At(y2, x2).Item2 * w; if (imageParam.mStitch.im.At(y1, x1).Item0 == imageParam.mStitch.im.At(y1, x1).Item1 && imageParam.mStitch.im.At(y1, x1).Item1 == imageParam.mStitch.im.At(y1, x1).Item2 && imageParam.im.At(y2, x2).Item0 == imageParam.im.At(y2, x2).Item1 && imageParam.im.At(y2, x2).Item1 == imageParam.im.At(y2, x2).Item2) { imageParam.mStitch.im.Set(y1, x1, new Vec3b((byte)ColorR, (byte)ColorG, (byte)ColorB)); } else { } y2 = y2 + 1; } x2 = x2 + 1; } } else { //上区域重叠 x2 = 1; //融合重叠区域 for (x1 = imageParam.mStitch.Pwidth - imageParam.W_box; x1 < imageParam.mStitch.Pwidth; x1++) { y2 = 1; for (y1 = imageParam.mStitch.Pheight - imageParam.H_box + 1; y1 < imageParam.mStitch.Pheight; y1++) { //安全性检测 CheckRC(ref x1, ref y1, imageParam.mStitch.im); CheckRC(ref x2, ref y2, imageParam.im); //融合权值 w = (double)x2 / (double)imageParam.W_box; //加权融合 double ColorR = imageParam.mStitch.im.At(y1, x1).Item0 * (1.0 - w) + imageParam.im.At(y2, x2).Item0 * w; double ColorG = imageParam.mStitch.im.At(y1, x1).Item1 * (1.0 - w) + imageParam.im.At(y2, x2).Item1 * w; double ColorB = imageParam.mStitch.im.At(y1, x1).Item2 * (1.0 - w) + imageParam.im.At(y2, x2).Item2 * w; if (imageParam.mStitch.im.At(y1, x1).Item0 == imageParam.mStitch.im.At(y1, x1).Item1 && imageParam.mStitch.im.At(y1, x1).Item1 == imageParam.mStitch.im.At(y1, x1).Item2 && imageParam.im.At(y2, x2).Item0 == imageParam.im.At(y2, x2).Item1 && imageParam.im.At(y2, x2).Item1 == imageParam.im.At(y2, x2).Item2) { imageParam.mStitch.im.Set(y1, x1, new Vec3b((byte)ColorR, (byte)ColorG, (byte)ColorB)); } else { } y2 = y2 + 1; } x2 = x2 + 1; } } //最终图 img = new Mat(imageParam.mStitch.Pheight, imageParam.mStitch.Pwidth + imageParam.im.Width - x2 + 1, MatType.CV_8UC3); //分离出重叠区域 Rect m_select = new Rect(x2 - 1, 0, imageParam.im.Width - x2 + 1, imageParam.mStitch.Pheight); Mat imgSwitch = new Mat(imageParam.im, m_select); Cv2.HConcat(imageParam.mStitch.im, imgSwitch, img); return img; } } }