using OpenCvSharp.Extensions; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace PaintDotNet.Adjust { public class StitchingController { public int MathSelect = 3; /// /// 一次:0/连续:1 /// public int Mode; public int State; /// /// 列数 /// public readonly int RowN; /// /// 列数 /// public readonly int ColumnN; /// /// 拼接率 /// public readonly double StitchRate; Queue _matBuffer = new Queue(); public List _offsetList; int _counterSum; int _counterDone; public Bitmap _img0; public Bitmap _img1; public int ImageWidth; public int ImageHeight; public OpenCvSharp.Mat _matResult; public System.Drawing.Bitmap Result { get { lock (lockobj) { return _matResult == null ? null : BitmapConverter.ToBitmap(_matResult); } } } public OpenCvSharp.Mat ResultMat { get { lock (lockobj) { return _matResult == null ? null : _matResult.Clone(); } } } public bool IsDone { get; private set; } = false; public Task StitchingTask; public StitchingController(int columnN, int rowN, double stitchRate) { ColumnN = columnN; RowN = rowN; StitchRate = stitchRate; Mode = 1; } public StitchingController(int columnN, double stitichRate, Bitmap[] mats) { ColumnN = columnN; RowN = mats.Length / ColumnN; foreach (var mat in mats) Add(mat); Mode = 0; } public void Add(Bitmap mat) { if (_counterDone == 0)//第一张 { _img1 = mat; ImageWidth = mat.Width; ImageHeight = mat.Height; _matResult = BitmapConverter.ToMat(mat); _counterDone++; } else { _matBuffer.Enqueue(mat); } _counterSum++; } public void Start() { StitchingTask = new Task(Runtime); StitchingTask.Start(); } public void Stop() { IsDone = true; } public void Runtime() { while (!IsDone) { if (Mode == 1 && _counterDone == ColumnN * RowN) { Stop(); return; } if (_matBuffer.Count == 0) { if (Mode == 0) { Stop(); return; } Thread.Sleep(50); } else { _img0 = _matBuffer.Dequeue(); Stitch(); _img1 = _img0; _counterDone++; } } } public void SynRun() { if (_matBuffer.Count == 0) { if (Mode == 0) { Stop(); return; } } else { _img0 = _matBuffer.Dequeue(); Stitch(); _img1 = _img0; _counterDone++; } if (_counterDone == ColumnN * RowN) { Stop(); } } public void Stitch() { bool error = true; Point movep = new Point(0, 0); int dir = Dir(); Bitmap img0; Bitmap img1; //切图 { switch (dir) { case 1: LastX += (int)(ImageWidth * (1 - StitchRate)); img0 = AdjustIntent.Cut(_img0, StitchRate, AdjustIntent.Side.Left); img1 = AdjustIntent.Cut(_img1, StitchRate, AdjustIntent.Side.Right); break; case 2: LastY += (int)(ImageHeight * (1 - StitchRate)); img0 = AdjustIntent.Cut(_img0, StitchRate, AdjustIntent.Side.Top); img1 = AdjustIntent.Cut(_img1, StitchRate, AdjustIntent.Side.Buttom); break; case 3: LastX -= (int)(ImageWidth * (1 - StitchRate)); img0 = AdjustIntent.Cut(_img0, StitchRate, AdjustIntent.Side.Right); img1 = AdjustIntent.Cut(_img1, StitchRate, AdjustIntent.Side.Left); break; default: img0 = _img0; img1 = _img1; break; } } //拼接算法 1 if (error && (MathSelect & 1) > 0) { int orbCount = img0.Width * img0.Height / 40000; movep = AdjustIntent.MatchOneBySift( BitmapConverter.ToMat(img0), BitmapConverter.ToMat(img1), out error, orbCount, 0.1, dir); } ////拼接算法 2 if (error && (MathSelect & 2) > 0) { movep = VisualMath.Tools.MatchByAccordDotNet(img0, img1, out error); } //按位置偏移 if (error) { #region 计算偏移 movep = new Point(0, 0); } #endregion #region 拼接图片 lock (lockobj) _matResult = MatMerge(BitmapConverter.ToMat(_img0), _matResult, movep); #endregion } private int LastX; private int LastY; private object lockobj = new object(); /// /// 计算拼接方向 /// /// [1]右;[2]下;[3]左 private int Dir() { var rowIndex = _counterDone / ColumnN; var colIndex = _counterDone % ColumnN; var directionRect = 1; if (colIndex == 0) { directionRect = 2; } else if (rowIndex % 2 == 1) { directionRect = 3; } return directionRect; } private Point DefaultOffset() { int x = (int)(ImageWidth * StitchRate); int y = (int)(ImageHeight * StitchRate); int dir = Dir(); switch (dir) { case 1: return new Point(x, 0); case 2: return new Point(0, y); case 3: return new Point(-x, 0); default: return new Point(0, 0); } } /// /// 等待拼图全部完成 /// public void Wait() { while (!IsDone) { Thread.Sleep(50); } } public void Dispose() { IsDone = true; Wait(); _matResult.Dispose(); GC.Collect(); } /// /// 利用Opencv 将新图贴到大图上 /// /// /// /// /// public OpenCvSharp.Mat MatMerge(OpenCvSharp.Mat matNew, OpenCvSharp.Mat matBig, System.Drawing.Point point) { //LastX -= point.X; //LastY -= point.Y; var result = new OpenCvSharp.Mat(); int srcOriX = 0; int srcOriY = 0; int newOriX = 0; int newOriY = 0; //得到变换矩阵后拼接图像 int viewWidth = matBig.Width;// 2448; int viewHeight = matBig.Height;// 2040; if (LastX <= 0) { viewWidth = (int)(viewWidth - LastX); srcOriX = (int)(-LastX); newOriX = 0; LastX = 0; } else { viewWidth = (int)Math.Max(LastX + matNew.Width, matBig.Width); newOriX = (int)LastX; } if (LastY <= 0) { viewHeight = (int)(viewHeight - LastY); srcOriY = (int)(-LastY); newOriY = 0; LastY = 0; } else { newOriY = (int)LastY; viewHeight = (int)Math.Max(matBig.Height, matNew.Height + LastY); } result = new OpenCvSharp.Mat(new OpenCvSharp.Size(viewWidth, viewHeight), matNew.Type()); OpenCvSharp.Mat tempMatSrc = matNew.Clone(); //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像) OpenCvSharp.Mat mask = tempMatSrc.CvtColor(OpenCvSharp.ColorConversionCodes.RGBA2GRAY); OpenCvSharp.Mat posSrc = new OpenCvSharp.Mat(result, new OpenCvSharp.Rect(newOriX, newOriY, matNew.Width, matNew.Height)); tempMatSrc.CopyTo(posSrc, mask);//原图像复制到新图像 OpenCvSharp.Mat tempMat = matBig.Clone(); //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像) mask = tempMat.CvtColor(OpenCvSharp.ColorConversionCodes.RGBA2GRAY); OpenCvSharp.Mat pos = new OpenCvSharp.Mat(result, new OpenCvSharp.Rect(srcOriX, srcOriY, matBig.Width, matBig.Height)); tempMat.CopyTo(pos, mask);//原图像复制到新图像 return result; } } }