public static CalibrationResult Make(CalibrationData[] data) { return new CalibrationResult() { TransformToCamera = BuildTransform(), TransformToProjector = BuildTransform() }; }
public static CalibrationData GetLocalCorners(PointF[] cameraCorners, Projector projector, Camera camera, Size pattern) { if (false) { projector.DrawBackground(Color.Black); var noi = new Image<Bgr, byte>(camera.TakePicture(5)); projector.DrawBackground(Color.FromArgb(0, 255, 0)); var fulli = new Image<Bgr, byte>(camera.TakePicture(5)); projector.DrawPhaseMod(4, 0f, true, Color.FromArgb(0, 255, 0)); var img = new Image<Bgr, byte>(camera.TakePicture(5)); var max = (fulli - noi).Split()[1]; var cur = (img - noi).Split()[1]; var map = new Bitmap(cur.Width, cur.Height); DebugWindow.DrawBitmap(max.Bitmap); DebugWindow.DrawBitmap(cur.Bitmap); using (var fast = new FastBitmap(map)) { for (int y = 0; y < cur.Height; y++) { for (int x = 0; x < cur.Width; x++) { var ii = cur[(int)y, (int)x].Intensity / max[(int)y, (int)x].Intensity; if (ii > 1) ii = 1; var i = (byte)(ii * 255); fast[x, y] = Color.FromArgb(i, i, i); } } } if (DebugWindow != null) DebugWindow.DrawBitmap(map); } //Determine rough checkerboard coordinates in projector space with graycode or binary structured light var rough = DetectRoughCorners(cameraCorners, projector, camera, Color.Green); //Improve accuracy with PhaseModulation //var phine = PhineTune(projector, camera, cameraCorners, rough, 32); //var phine2 = PhineTune(projector, camera, cameraCorners, rough, 64); //var phine3 = PhineTune(projector, camera, cameraCorners, phine2, 128); projector.DrawPoints(rough, 5); //Determine corners in projector space //var projectorCorners = DetectProjectorCorners(nolight, cameraCorners, projOutline, projector, camera); //Save corners in camera and projector space and store along side global coordinates that matches current checkerboard var data = new CalibrationData() { CameraCorners = cameraCorners, ProjectorCorners = rough }; return data; }
public static StereoCalibrationResult Calibrate(CalibrationData[] data, Camera camera, Projector projector, Size pattern, float checkerBoardSize) { var globals = GenerateCheckerBoard(pattern, checkerBoardSize); var datas = data; var globalCorners = datas.Select(row => globals).ToArray(); var cameraCorners = datas.Select(row => Properize(row.CameraCorners, pattern) ) .ToArray(); var projectorCorners = datas.Select(row => Properize(row.ProjectorCorners, pattern) ).ToArray(); //for (var i = 0; i < datas.Length; i++) //{ // var withCorners = camera.TakePicture(0); // QuickDraw.Start(withCorners) // .Color(Color.White) // .DrawPoint(cameraCorners[i].Take(11).ToArray(), 5) // .Finish(); // DebugWindow.DrawBitmap(withCorners); // projector.DrawPoints(projectorCorners[i].Take(11).ToArray(), 4); //} IntrinsicCameraParameters cameraIntrinsics = new IntrinsicCameraParameters(); cameraIntrinsics.IntrinsicMatrix = new Matrix<double>(new double[,] { { 4.884, 0, 0.032 }, { 0, 4.884 * 3.0 / 4.0, -0.037 }, { 0, 0, 1 } }); cameraIntrinsics.DistortionCoeffs = new Matrix<double>(new double[,] { {-0.00575}, {0.000442}, {-0.000107}, {0}, {0}, {0}, {0}, {0}, }); ExtrinsicCameraParameters[] cameraExtrinsicsArray; var cerr = Emgu.CV.CameraCalibration.CalibrateCamera(globalCorners, cameraCorners, camera.Size, cameraIntrinsics, Emgu.CV.CvEnum.CALIB_TYPE.CV_CALIB_USE_INTRINSIC_GUESS, out cameraExtrinsicsArray); IntrinsicCameraParameters projectorIntrinsics = new IntrinsicCameraParameters(); //projectorIntrinsics.IntrinsicMatrix = new Matrix<double>(new double[,] { { 531.15f * 4f / 3f, 0, 1 }, { 0, 531.15f, 1 }, { 0, 0, 1 } }); projectorIntrinsics.IntrinsicMatrix = new Matrix<double>(new double[,] { {2151.0712684548571, 0, projector.Size.Width / 2}, {0, 1974.541465816948, projector.Size.Height / 2}, {0,0,1} }); ExtrinsicCameraParameters[] projectorExtrinsicsArray; var perr = Emgu.CV.CameraCalibration.CalibrateCamera(globalCorners, projectorCorners, projector.Size, projectorIntrinsics, Emgu.CV.CvEnum.CALIB_TYPE.CV_CALIB_RATIONAL_MODEL, out projectorExtrinsicsArray); //Matrix<double> foundamental, essential; //ExtrinsicCameraParameters camera2projectorExtrinsics; //Emgu.CV.CameraCalibration.StereoCalibrate(globalCorners, // cameraCorners, // projectorCorners, // cameraIntrinsics, // projectorIntrinsics, // camera.Size, // Emgu.CV.CvEnum.CALIB_TYPE.DEFAULT, // new MCvTermCriteria(16, 0.01), // out camera2projectorExtrinsics, // out foundamental, // out essential); return new StereoCalibrationResult() { cameraIntrinsic = cameraIntrinsics, cameraExtrinsic = cameraExtrinsicsArray.First(), projectorIntrinsic = projectorIntrinsics, projectorExtrinsic = projectorExtrinsicsArray.First(), cameraToProjectorExtrinsic = null }; }
public static CalibrationResult Calibrate(Projector projector, Camera camera, Emgu.CV.Structure.MCvPoint3D32f[] globalCorners, int iterations = 10, int iterationTimeout = 500) { //if (PhaseModulation.DetermineAlgorithmIntegrity(8, 10000, 0.01) > 0.15) // throw new Exception("Phase modulation integrity is failing"); //projector.SetBounds(new RectangleF(0.25f, 0.25f, 0.5f, 0.5f)); //projector.DrawBinary(3, true, Color.White); //Red and blue checkerboard //For each orientation of checkerboard: //float w = projector.bitmap.Width; //float h = projector.bitmap.Height; //var ps = new PointF[] { // new PointF(440f, h - 324f), new PointF(640f, h - 168f) // }; ////projector.SetBounds(DetermineBounds(ps, projector.bitmap.Width, projector.bitmap.Height)); //projector.SetBounds(DetermineBounds(ps, w, h)); //projector.DrawBackground(Color.White); var datas = new CalibrationData[iterations]; for (int i = 0; i < iterations; i++) { //Take pic of checkerboard with no proj light projector.DrawBackground(Color.Black); //Detect corners in camera space PointF[] cameraCorners; Bitmap withCorners; do { var nolight = camera.TakePicture(5); withCorners = camera.TakePicture(); cameraCorners = DetectCornersRB(nolight, new Size(7, 4)); } while (cameraCorners == null); //cameraCorners = cameraCorners.Take(1).Union(cameraCorners.Skip(cameraCorners.Length - 1)).ToArray(); if (DebugWindow != null) { QuickDraw.Start(withCorners) .Color(Color.White) .DrawPoint(cameraCorners, 5) .Finish(); DebugWindow.DrawBitmap(withCorners); } //Determine rough checkerboard coordinates in projector space with graycode or binary structured light //var smooth = PhaseCalib(projector, camera, cameraCorners); //projector.DrawPoints(smooth, 5); Func<PointF[]> Pass = () => { var rough = DetectRoughCorners(cameraCorners, projector, camera, Color.Green); //var phine = PhineTune(projector, camera, cameraCorners, rough, 32); var phine2 = PhineTune(projector, camera, cameraCorners, rough, 64); var phine3 = PhineTune(projector, camera, cameraCorners, phine2, 128); return phine3; }; var ids = Range.OfInts(cameraCorners.Length); var passes = Range.OfInts(10).ToArray(); var data = passes.Select(p => Pass()).ToArray(); var result = ids.Select(row => passes.Select(p => data[p][row])).ToArray(); var avg = ids.Select(id => new PointF(result[id].Select(r => r.X).Average(), result[id].Select(r => r.Y).Average())).ToArray(); projector.DrawPoints(avg, 5); var avg2 = ids.Select(id => new PointF( result[id].Select(r => new { val= r.X, dist = Math.Abs(avg[id].X - r.X) }) .OrderByDescending(row => row.dist).Reverse().Take(5).Select(row => row.val).Average(), result[id].Select(r => new { val = r.Y, dist = Math.Abs(avg[id].Y - r.Y) }) .OrderByDescending(row => row.dist).Reverse().Take(5).Select(row => row.val).Average())).ToArray(); projector.DrawPoints(avg2, 5); //var outline = DetermineBounds(rough, projector.bitmap.Width, projector.bitmap.Height); //projector.SetBounds(outline); /* double[] xs, ys; { projector.DrawBackground(Color.Black); var nolight = camera.TakePicture(5); projector.DrawBackground(Color.Green); var fulllight = camera.TakePicture(5); projector.DrawBackground(Color.Black); camera.TakePicture(5).Dispose(); projector.Draw(PhaseModulation.DrawPhaseModulation(1, -2 * Math.PI / 3, true, Color.Green)); var light1 = camera.TakePicture(2); projector.DrawBackground(Color.Black); camera.TakePicture(5).Dispose(); projector.Draw(PhaseModulation.DrawPhaseModulation(1, 0, true, Color.Green)); var light2 = camera.TakePicture(2); projector.DrawBackground(Color.Black); camera.TakePicture(5).Dispose(); projector.Draw(PhaseModulation.DrawPhaseModulation(1, 2 * Math.PI / 3, true, Color.Green)); var light3 = camera.TakePicture(2); var pc = PhaseClassifier(nolight, fulllight, projector.bitmap.Width, projector.bitmap.Height); var pc1 = pc(light1); var pc2 = pc(light2); var pc3 = pc(light3); xs = cameraCorners.Select(row => PhaseModulation.IntensityToPhase(pc1((int)row.X, (int)row.Y), pc2((int)row.X, (int)row.Y), pc3((int)row.X, (int)row.Y))).ToArray(); } { projector.DrawBackground(Color.Black); var nolight = camera.TakePicture(5); projector.DrawBackground(Color.Green); var fulllight = camera.TakePicture(5); projector.DrawBackground(Color.Black); camera.TakePicture(5).Dispose(); projector.DrawPhaseMod(1, (float)(-2 * Math.PI / 3), false, Color.FromArgb(0, 255, 0)); var light1 = camera.TakePicture(2); projector.DrawBackground(Color.Black); camera.TakePicture(5).Dispose(); projector.DrawPhaseMod(1, (float)(0), false, Color.FromArgb(0, 255, 0)); var light2 = camera.TakePicture(2); projector.DrawBackground(Color.Black); camera.TakePicture(5).Dispose(); projector.DrawPhaseMod(1, (float)(2 * Math.PI / 3), false, Color.FromArgb(0, 255, 0)); var light3 = camera.TakePicture(2); var pc = PhaseClassifier(nolight, fulllight, projector.bitmap.Width, projector.bitmap.Height); var pc1 = pc(light1); var pc2 = pc(light2); var pc3 = pc(light3); ys = cameraCorners.Select(row => PhaseModulation.IntensityToPhase(pc1((int)row.X, (int)row.Y), pc2((int)row.X, (int)row.Y), pc3((int)row.X, (int)row.Y))).ToArray(); } var resx = xs.Select(row => PhaseModulation.AbsolutePhase(new double[] { row }, new int[] { 1 })).Select(row => row * projector.bitmap.Width).ToArray(); var resy = ys.Select(row => PhaseModulation.AbsolutePhase(new double[] { row }, new int[] { 1 })).Select(row => row * projector.bitmap.Height).ToArray(); var res = resx.Zip(resy, (x, y) => new PointF((float)Math.Round(x, 0), (float)Math.Round(y, 0))).ToArray(); projector.SetBounds(new RectangleF(0, 0, 1, 1)); projector.DrawPoints(res, 5f); */ //Determine corners in projector space //var projectorCorners = DetectProjectorCorners(nolight, cameraCorners, projOutline, projector, camera); //Save corners in camera and projector space and store along side global coordinates that matches current checkerboard //var data = new CalibrationData() { CameraCorners = cameraCorners, ProjectorCorners = projectorCorners, GlobalCorners = globalCorners }; datas[i] = default(CalibrationData); Thread.Sleep(iterationTimeout); } return CalibrationResult.Make(datas); }