private Bitmap CreateObjectMask(Bitmap img, /*out IplImage image_mask,*/ out double mask_length, out double mask_area, out double mask_width, out double mask_height, out double mask_pvheight, int num_smooth, int contrast, double canny1, double canny2, out Mat image_mask_spc, out double mask2_area, int filter_size = 3, int brightAreaThreshold = -1, int darkAreaThreshold = -1) { Bitmap dst = null; //IplImage img_mask = Cv.CreateImage(new CvSize(img.Width, img.Height), BitDepth.U8, 1); Mat img_mask = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0); image_mask_spc = null; mask_length = mask_area = mask_width = mask_height = mask_pvheight = mask2_area = 0; Mat img_gray; Mat img_canny; Mat img_mask_copy; int i, x, y, offset; IntPtr ptr; Byte pixel; ////////////////// var distance = new List <double>(); double center_x = 0; double center_y = 0; double center_count = 0; double distance_mean = 0; double distance_stddev = 0; double sum_m = 0; double sum_v = 0; double temp = 0; ////////////////// //////////////////////////////////////////////////////////// ////////////////////////Mask make/////////////////////////// //////////////////////////////////////////////////////////// img_gray = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0); img_canny = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0); img_mask_copy = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0); Mat src = BitmapConverter.ToMat(img); Cv2.CvtColor(src, img_gray, ColorConversionCodes.BGR2GRAY); //Contrast -> Increase the edge contrast for transparent diamond byte[] lut = CalcLut(contrast, 0); //img_gray.LUT(img_gray, lut); Cv2.LUT(img_gray, lut, img_gray); //Median filter -> Eliminate point noise in the image //Elimination of big dusts should be coded here if (num_smooth > 0) { //for (i = 0; i < num_smooth; i++) img_gray.Smooth(img_gray, SmoothType.Median, 3, 3, 0, 0); //for (i = 0; i < num_smooth; i++) img_gray.Smooth(img_gray, SmoothType.Median, filter_size, filter_size, 0, 0); for (i = 0; i < num_smooth; i++) { Cv2.MedianBlur(img_gray, img_gray, filter_size); } img_canny = img_gray.Canny(canny1, canny2); } else { img_canny = img_gray.Canny(canny1, canny2); } ///////////////////////////////////////////////////////////// //ConvexHull ///////////////////////////////////////////////////////////// //OpenCvSharp.CvMemStorage storage = new CvMemStorage(0); //CvSeq points = Cv.CreateSeq(SeqType.EltypePoint, CvSeq.SizeOf, CvPoint.SizeOf, storage); //CvSeq<CvPoint> points = new CvSeq<CvPoint>(SeqType.EltypePoint, CvSeq.SizeOf, storage); //CvPoint pt; List <OpenCvSharp.Point> points = new List <OpenCvSharp.Point>(); OpenCvSharp.Point pt; ptr = img_canny.Data; for (y = 0; y < img_canny.Height; y++) { for (x = 0; x < img_canny.Width; x++) { offset = (img_canny.Width * y) + (x); pixel = Marshal.ReadByte(ptr, offset); if (pixel > 0) { pt.X = x; pt.Y = y; points.Add(pt); ////////////////////// center_x = center_x + x; center_y = center_y + y; center_count++; ////////////////////// } } } center_x = center_x / center_count; center_y = center_y / center_count; //CvPoint[] hull; //CvMemStorage storage1 = new CvMemStorage(0); //CvSeq<CvPoint> contours; //List<Mat> hull = new List<Mat>(); MatOfPoint hull = new MatOfPoint(); int x_min = 3000, x_max = 0, y_min = 3000, y_max = 0; int y_x_min = 3000, y_x_max = 3000; if (points.Count > 0) { //Calcurate Ave and Std of distance from each edge points to the weighed center for (i = 0; i < points.Count; i++) { pt = points[i]; temp = Math.Sqrt((pt.X - center_x) * (pt.X - center_x) + (pt.Y - center_y) * (pt.Y - center_y)); distance.Add(temp); sum_m += temp; sum_v += temp * temp; } distance_mean = sum_m / points.Count; temp = (sum_v / points.Count) - distance_mean * distance_mean; distance_stddev = Math.Sqrt(temp); // Outlier elimination for (i = points.Count - 1; i >= 0; i--) { if (distance[i] > (distance_mean + 3.0 * distance_stddev)) { points.RemoveAt(i); } } Cv2.ConvexHull(MatOfPoint.FromArray(points), hull, true); //2014/4/14 Add calc mask_width, mask_height and mask_pvheight foreach (OpenCvSharp.Point item in hull) { if (x_min > item.X) { x_min = item.X; y_x_min = item.Y; } else if (x_min == item.X && y_x_min > item.Y) { y_x_min = item.Y; } if (x_max < item.X) { x_max = item.X; y_x_max = item.Y; } else if (x_max == item.X && y_x_max > item.Y) { y_x_max = item.Y; } if (y_min > item.Y) { y_min = item.Y; } if (y_max < item.Y) { y_max = item.Y; } } mask_width = x_max - x_min; mask_height = y_max - y_min; mask_pvheight = ((double)y_x_max + (double)y_x_min) / 2 - (double)y_min; ///////////////////////////////////////////////////////////// // For icecream cone shape diamond, need to use triangle mask ///////////////////////////////////////////////////////////// if (diamond_group == DIAMOND_GROUPING.RBC_HighDepth) { for (i = 0; i < hull.Count(); i++) { OpenCvSharp.Point p = hull.At <OpenCvSharp.Point>(i); if (y_x_max >= y_x_min) { if (p.Y > y_x_min) { p.X = x_max; p.Y = y_x_max; } } else { if (p.Y > y_x_max) { p.X = x_min; p.Y = y_x_min; } } } } ////////////////////////////////////////////////////////////// Cv2.FillConvexPoly(img_mask, hull, Scalar.White, LineTypes.AntiAlias, 0); //2013/11/3 Add erode function if (erode > 0) { for (i = 0; i < erode; i++) { Cv2.Erode(img_mask, img_mask, null); } } //Calc length and area of img_mask -> use for fancy shape diamonds //Cv.FindContours(img_mask, storage1, out contours, CvContour.SizeOf, ContourRetrieval.External, ContourChain.ApproxSimple); //Cv.FIndCOntours overwrites img_mask, need to use copy image //IplImage img_mask_copy = Cv.Clone(img_mask); //Cv2.Copy(img_mask, img_mask_copy); Mat hierarchy = new Mat(); Mat[] contours; img_mask.CopyTo(img_mask_copy); Cv2.FindContours(img_mask_copy, out contours, hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple); //Cv.ReleaseImage(img_mask_copy); mask_length = Cv2.ArcLength(contours[0], true); mask_area = Math.Abs(Cv2.ContourArea(contours[0])); //Cv.ClearSeq(contours); } else { mask_length = 0.0; mask_area = 0.0; } //Memory release //Cv.ReleaseImage(img_gray); //Cv.ReleaseImage(img_canny); //Cv.ReleaseImage(img_mask_copy); //Cv.ClearSeq(points); //Cv.ReleaseMemStorage(storage); //Cv.ReleaseMemStorage(storage1); //if the diamond is out of croped image, do not calc color values if (x_min == 0 | x_max == (img.Width - 1) | y_min == 0 | y_max == (img.Height - 1)) { return(dst); } //img_mask.SaveImage(@"P:\Projects\DustDetection\TestSamples\gColorFancyImages\temp\image_mask_hiroshi.jpg"); if (mask_length > 0) { dst = BitmapConverter.ToBitmap(img_mask); } return(dst); }