/// <summary> /// detect bulb flicker /// </summary> /// <param name="cam">camera object, derive from openCamera()</param> /// <param name="h**o">derive from getAlignment()</param> /// <param name="detectionDurationMs">detection duration in msec</param> /// <param name="leastFlikerCount">least filker times</param> /// <param name="threshold">bulb threshold, smaller value are more sensitive to noise. 0-255</param> /// <param name="erodeTimes">erode filter</param> /// <param name="debug">if true, will show intermediate debug image</param> /// <returns>Points array contains bulb cordinate</returns> public static MarkerManager.BulbPoint[] detectFilcker(VideoCapture cam, MarkerManager.HomoTrans h**o, int detectionDurationMs, int leastFlikerCount, int threshold = 80, int erodeTimes = 2, bool debug = false) { return(MarkerManager.findFlicker(cam, h**o, detectionDurationMs, leastFlikerCount, threshold, erodeTimes, debug)); }
/// <summary> /// align an image and save the aligned image to file /// </summary> /// <param name="originImagePath">input image</param> /// <param name="alignedImageSavePath">output image path</param> /// <param name="h**o">homography, using getHomo() to obtain one</param> /// <param name="debug">if true, will show intermediate debug image</param> public static void getAlignedImage(string originImagePath, string alignedImageSavePath, MarkerManager.HomoTrans h**o, bool debug = false) { Image <Bgr, byte> img = new Image <Bgr, byte>(originImagePath); Image <Bgr, byte> alignedImg = MarkerManager.getAlignedImage(img, h**o); alignedImg.Save(alignedImageSavePath); if (debug) { CvInvoke.Imshow("aligned img", alignedImg); } }
/// <summary> /// detect bulb from a new image and aligned image get from getAlignment(). /// </summary> /// <param name="alignedImgPath">derive from getAlignment()</param> /// <param name="h**o">derive from getAlignment()</param> /// <param name="compareImgPath">new image to compare with</param> /// <param name="threshold">bulb threshold, smaller value are more sensitive to noise. 0-255</param> /// <param name="erodeTimes">erode filter</param> /// <param name="debug">if true, will show intermediate debug image</param> /// <returns> /// MarkerManager.BulbPoint[][] { (BulbPoint[])litBulbs, (BulbPoint[])litoffBulbs } /// </returns> public static MarkerManager.BulbPoint[][] detectBulb( string alignedImgPath, MarkerManager.HomoTrans h**o, string compareImgPath, int threshold = 80, int erodeTimes = 2, bool debug = false) { Image <Bgr, byte> alignedImg = new Image <Bgr, byte>(alignedImgPath); Image <Bgr, byte> compareImg = new Image <Bgr, byte>(compareImgPath); compareImg = MarkerManager.getAlignedImage(compareImg, h**o); MarkerManager.BulbPoint[] lit = MarkerManager.findBulb( compareImg.Sub(alignedImg), threshold, erodeTimes, debug); MarkerManager.BulbPoint[] litoff = MarkerManager.findBulb( alignedImg.Sub(compareImg), threshold, erodeTimes, debug); return(new MarkerManager.BulbPoint[][] { lit, litoff }); }
/// <summary> /// calculate homography transformation struct /// </summary> /// <param name="originImagePath">input image</param> /// <param name="markerLowRange">marker detection low hue range</param> /// <param name="markerHighRange">marker detection high hue range</param> /// <param name="resolution"> /// expected resolution of the markered rectangle, /// while using Size.Empty, adaptive size will applied (not precise in lenght-width ratio)</param> /// <param name="zoomX"> /// homography zoom ratio, smaller value means draw closer to the plane. /// 1.0 is default. Must greater than 0.</param> /// <param name="offsetX">homography offset X in pixel</param> /// <param name="offsetY">homography offset Y in pixel</param> /// <param name="markerErodeTimes">marker erode filter times</param> /// <param name="debug">if true, will show intermediate debug image</param> /// <returns> /// if four and only four markers are found, a HomoTrans struct will be returned. /// Otherwise, an empty homotrans struct will be returned. /// Set debug=true to adjust input parameters. /// </returns> public static MarkerManager.HomoTrans getHomo(string originImagePath, Hsv markerLowRange, Hsv markerHighRange, Size resolution, float zoomX = 1.0f, float zoomY = 1.0f, int offsetX = 0, int offsetY = 0, int markerErodeTimes = 2, bool debug = false) { Image <Bgr, byte> img = new Image <Bgr, byte>(originImagePath); MarkerManager mm = new MarkerManager(); Point[] pts = MarkerManager.findMarkers(img, markerLowRange, markerHighRange, markerErodeTimes, debug); MarkerManager.HomoTrans h**o = MarkerManager.getHomography( img, pts, resolution, zoomX, zoomY, offsetX, offsetY); return(h**o); }
public static BulbPoint[] findFlicker(VideoCapture vc, HomoTrans h**o, int durationMs, int leastFliker = 2, int threshold = 80, int erodeTimes = 2, bool debug = false) { Mat ele = CvInvoke.GetStructuringElement(Emgu.CV.CvEnum.ElementShape.Ellipse, new Size(3, 3), new Point(-1, -1)); int startTime = System.Environment.TickCount; Mat pic1 = new Mat(); Mat pic2 = new Mat(); vc.Read(pic1); vc.Read(pic2); Mat diffPicAcc = new Mat(); do { Image <Bgr, byte> diffImg = MarkerManager.getAlignedImage(pic1.ToImage <Bgr, byte>(), h**o).AbsDiff( MarkerManager.getAlignedImage(pic2.ToImage <Bgr, byte>(), h**o)); CvInvoke.CvtColor(diffImg, diffImg, Emgu.CV.CvEnum.ColorConversion.Bgr2Hsv); Image <Gray, byte> diffImgValue = diffImg[2].Clone(); for (int y = 0; y < diffImg.Height; y++) { for (int x = 0; x < diffImg.Width; x++) { if (diffImgValue.Data[y, x, 0] < threshold) { diffImgValue.Data[y, x, 0] = 0; } else { diffImgValue.Data[y, x, 0] = 1; } } } if (diffPicAcc.IsEmpty) { diffPicAcc.Create(diffImgValue.Rows, diffImgValue.Cols, Emgu.CV.CvEnum.DepthType.Cv8U, 1); diffPicAcc.SetTo(new MCvScalar(0)); } CvInvoke.Add(diffImgValue, diffPicAcc, diffPicAcc); Mat t = pic1; pic1 = pic2; pic2 = t; vc.Read(pic2); } while (System.Environment.TickCount - startTime < durationMs); Image <Gray, byte> diffPicAccI = diffPicAcc.ToImage <Gray, byte>(); Image <Gray, byte> diffPicAccDebug = null; if (debug) { diffPicAccDebug = diffPicAcc.ToImage <Gray, byte>(); } for (int y = 0; y < diffPicAccI.Height; y++) { for (int x = 0; x < diffPicAccI.Width; x++) { if (diffPicAccI.Data[y, x, 0] < leastFliker) { diffPicAccI.Data[y, x, 0] = 0; } else if (debug) { diffPicAccDebug.Data[y, x, 0] = 255; } } } if (debug) { CvInvoke.Imshow("diffImgAcc", diffPicAccDebug); } CvInvoke.MorphologyEx(diffPicAccI, diffPicAccI, Emgu.CV.CvEnum.MorphOp.Erode, ele, new Point(-1, -1), erodeTimes, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0)); CvInvoke.MorphologyEx(diffPicAccI, diffPicAccI, Emgu.CV.CvEnum.MorphOp.Dilate, ele, new Point(-1, -1), erodeTimes + ERODE_ADDTIONAL_RETRIEVE_COUNT, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar(0)); List <BulbPoint> result = new List <BulbPoint>(); for (int y = 0; y < diffPicAccI.Height; y++) { for (int x = 0; x < diffPicAccI.Width; x++) { if (diffPicAccI.Data[y, x, 0] != 0) { Mat ptsSet = new Mat(); double totalIntensity = hfsMarker(diffPicAccI, x, y, ptsSet, 0, 0); int px = (int)(CvInvoke.Mean(ptsSet.Col(0)).V0); int py = (int)(CvInvoke.Mean(ptsSet.Col(1)).V0); int fTimes = (int)Math.Round(totalIntensity / ptsSet.Rows); result.Add(new BulbPoint(new Point(px, py), h**o.resolution, 0, fTimes)); } } } return(result.ToArray()); }