using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace SmartCoalApplication.Base.CommTool { public class BinaryTools { public static Dictionary keyValuePairs = new Dictionary(); public static Mat rgb_ap, temp_ap, original; public static Vec4b vec4B; /// /// 新碎屑删除,使用连通分量找寻碎屑 /// /// /// public unsafe static Mat DebrisRemoval_New(Mat src, int v = 20) { try { Mat[] arr = src.Split(); rgb_ap = Tools.MergeMatFromMatArr(arr); if(arr.Length>3) temp_ap = arr[3].Clone(); //寻找连通分量 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nonenum = Cv2.ConnectedComponentsWithStats(src.CvtColor(ColorConversionCodes.BGRA2GRAY), labelMat, stats, centroids, PixelConnectivity.Connectivity8); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); for (int h = 1; h < centroids.Height; h++) { int areaField1 = stats.At(h, 4); if (0 <= areaField1 && areaField1 <= v) { keyValuePairs.Add(h, 1); } } labelMat.ForEachAsInt32(CommonForEachForInt32); //合并rgb和透明度 Mat[] mats = rgb_ap.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; if (arr.Length > 3) arr[3] = temp_ap; Cv2.Merge(arr, src); } catch (Exception) { } finally { keyValuePairs.Clear(); if (rgb_ap != null && !rgb_ap.IsDisposed) { rgb_ap.Dispose(); rgb_ap = null; } if (temp_ap != null && !temp_ap.IsDisposed) { temp_ap.Dispose(); temp_ap = null; } System.GC.Collect(); } return src; } public unsafe static Mat DebrisRemoval_New_1(Mat src, int v = 20) { try { temp_ap = src.Clone(); //寻找连通分量 Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int nonenum = Cv2.ConnectedComponentsWithStats(src, labelMat, stats, centroids, PixelConnectivity.Connectivity8); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); for (int h = 1; h < centroids.Height; h++) { int areaField1 = stats.At(h, 4); if (0 <= areaField1 && areaField1 <= v) { keyValuePairs.Add(h, 1); } } labelMat.ForEachAsInt32(CommonForEachForInt32_1); temp_ap.CopyTo(src); } catch (Exception) { } finally { keyValuePairs.Clear(); if (rgb_ap != null && !rgb_ap.IsDisposed) { rgb_ap.Dispose(); rgb_ap = null; } if (temp_ap != null && !temp_ap.IsDisposed) { temp_ap.Dispose(); temp_ap = null; } System.GC.Collect(); } return src; } private unsafe static void CommonForEachForInt32(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && keyValuePairs.ContainsKey(v)) { rgb_ap.Set(y, x, new Vec3b(0, 0, 0)); if(temp_ap!=null) temp_ap.Set(y, x, 0); } } private unsafe static void CommonForEachForInt32_1(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && keyValuePairs.ContainsKey(v)) { if (temp_ap != null) temp_ap.Set(y, x, 0); } } public unsafe static Mat HoleFilling_NewWithView(Mat src, Vec4b vec4b) { vec4B = vec4b; Mat[] arr2 = src.Split(); Mat tempc = arr2[3]; //去掉透明层 Mat mat = src.CvtColor(ColorConversionCodes.BGRA2BGR); //填充孔洞 mat = Tools.FillHole(mat, new Scalar(255 - vec4B.Item0, 255 - vec4B.Item1, 255 - vec4B.Item2)); tempc = Tools.FillHole(tempc, new Scalar(255)); //循环处理 mat.ForEachAsVec3b(RGBForEachAsByteForHoleFillingNewWithView); Mat[] arr1 = mat.Split(); arr2[0] = arr1[0]; arr2[1] = arr1[1]; arr2[2] = arr1[2]; arr2[3] = tempc; Cv2.Merge(arr2, src); if (mat != null && !mat.IsDisposed) mat.Dispose(); if (tempc != null && !tempc.IsDisposed) tempc.Dispose(); System.GC.Collect(); return src; } private unsafe static void RGBForEachAsByteForHoleFillingNewWithView(Vec3b* value, int* position) { int y = position[0]; int x = position[1]; if (value->Item0 == 255 && value->Item1 == 255 && value->Item2 == 255) { value->Item0 = vec4B.Item0; value->Item1 = vec4B.Item1; value->Item2 = vec4B.Item2; } else { value->Item0 = 255; value->Item1 = 255; value->Item2 = 255; } } public static double CalcNodularity(OpenCvSharp.Point[] contours) { Point2f point; float radius; double area = Cv2.ContourArea(contours); if (contours.Length > 500) { Cv2.MinEnclosingCircle(Cv2.ConvexHull(contours, true), out point, out radius); } else { Cv2.MinEnclosingCircle(contours, out point, out radius); } return area / (Math.PI * radius * radius); } public static bool WithinContour(List contoursAll, OpenCvSharp.Point[] now) { foreach (OpenCvSharp.Point[] ps in contoursAll) { double inside = Cv2.PointPolygonTest(now, ps[0], true); if (inside > 0) return true; } return false; } /// /// 估算适合的阈值 /// /// /// /// public static float CalcSuitableValue(Mat edge, bool first = true) { //寻找较适合的阈值 float[] hist_float = HistTools.CalcHist(edge); //直方图平滑 int[] hist_int = HistTools.Smooth(hist_float, 5);//10 //寻找所有的峰 List mountainsList = new List(); List mountainsArrList = new List(); List mountainsArrListBackUp = new List(); Tools.FindTopAndBetweenWithOutWT123(hist_int, 0, 255, mountainsList, mountainsArrList, mountainsArrListBackUp, new List(), 15); mountainsList.Sort(); if (first) return (mountainsList.Min() - 10) <= 0 ? 70 : (mountainsList.Min() - 10); else return mountainsList[mountainsList.IndexOf(mountainsList.Min()) + 1]; } public static float CalcSuitableValueForUnderCut(Mat edge, bool first = true) { //寻找较适合的阈值 float[] hist_float = HistTools.CalcHist(edge); //直方图平滑 int[] hist_int = HistTools.Smooth(hist_float, 10); //寻找所有的峰 List mountainsList = new List(); List mountainsArrList = new List(); List mountainsArrListBackUp = new List(); Tools.FindTopAndBetweenWithOutWT123(hist_int, 0, 255, mountainsList, mountainsArrList, mountainsArrListBackUp, new List(), 15); mountainsList.Sort(); if (first) return (mountainsList.Min() - 10) <= 0 ? 70 : (mountainsList.Min()); else return mountainsList[mountainsList.IndexOf(mountainsList.Min()) + 1]; } /// /// 最找最大的峰的右侧的谷 /// /// /// public static float CalcSuitableValueForMax(Mat edge) { //寻找较适合的阈值 float[] hist_float = HistTools.CalcHist(edge); //直方图平滑 int[] hist_int = HistTools.Smooth(hist_float, 20); for (int i = 0; i < hist_int.Length; i++) if (hist_int[i] < 3000) hist_int[i] = 0; //寻找所有的峰 List mountainsList = new List(); List mountainsArrList = new List(); List mountainsArrListBackUp = new List(); Tools.FindTopAndBetweenWithOutWT123(hist_int, 0, 255, mountainsList, mountainsArrList, mountainsArrListBackUp, new List(), 15); int returnV = 0; int temp = 0; int l = 0; for(int i=0; i< mountainsList.Count; i++) { if(mountainsList[i]<200 && temp < mountainsList[i]) { temp = mountainsList[i]; returnV = mountainsArrList[i][1]; l = i; } } if(returnV > 200) return mountainsArrList[l-1][1]; return returnV; } /// /// 新版本删除边界 /// /// /// public static Mat DeleteContours_New(Mat src) { Rect rect; Mat[] arr = src.Split(); Mat rgb = Tools.MergeMatFromMatArr(arr); Mat temp_1 = arr[3].Clone(); for (int h = 0; h < temp_1.Width; h++) { byte vec4B_top = temp_1.At(0, h); if (vec4B_top > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(h, 0), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(h, 0), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } for (int h = 0; h < temp_1.Width; h++) { byte vec4B_bottom = temp_1.At(temp_1.Height - 1, h); if (vec4B_bottom > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(h, temp_1.Height - 1), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(h, temp_1.Height - 1), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } for (int y = 0; y < temp_1.Height; y++) { Vec4b vec4B_top = temp_1.At(y, 0); if (vec4B_top.Item3 > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(0, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(0, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } for (int y = 0; y < temp_1.Height; y++) { byte vec4B_top = temp_1.At(y, temp_1.Width - 1); if (vec4B_top > 0) { Cv2.FloodFill(rgb, new OpenCvSharp.Point(temp_1.Width - 1, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); Cv2.FloodFill(temp_1, new OpenCvSharp.Point(temp_1.Width - 1, y), new Scalar(0), out rect, null, null, FloodFillFlags.Link8); } } Mat[] mats = rgb.Split(); arr[0] = mats[0]; arr[1] = mats[1]; arr[2] = mats[2]; arr[3] = temp_1; Cv2.Merge(arr, src); return src; } static Mat phaseTemp1; static double contrast = 2; static int brightness = 0; /// /// 亮度/对比度/伽马值 /// /// /// public unsafe static Mat BCGTransferFunction(Mat src) { if (phaseTemp1 != null) phaseTemp1 = null; contrast = 1.7; phaseTemp1 = new Mat(src.Size(), MatType.CV_8UC3, Scalar.All(0)); //创建一个和原图像大小相同,类型相同,像素值为0的图像。 Mat imageGamma = null; try { double gamma = 1; src = src.CvtColor(ColorConversionCodes.GRAY2BGR); contrast = (contrast - 1.0) / 2.0 + 1.0;//待确认参数范围 src.ForEachAsVec3b(ForeachFunctionByteForBCGTransferMultiChannel); imageGamma = new Mat(); //灰度归一化 phaseTemp1.ConvertTo(imageGamma, MatType.CV_64F, 1.0 / 255, 0); Cv2.Pow(imageGamma, gamma, imageGamma); imageGamma.ConvertTo(imageGamma, MatType.CV_8U, 255, 0); imageGamma.CopyTo(phaseTemp1); phaseTemp1.CopyTo(src); return src.CvtColor(ColorConversionCodes.BGR2GRAY); } catch (Exception ex) { throw ex; } finally { if (imageGamma != null && !imageGamma.IsDisposed) { imageGamma.Dispose(); } if (phaseTemp1 != null && !phaseTemp1.IsDisposed) { phaseTemp1.Dispose(); phaseTemp1 = null; } GC.Collect(); } } private unsafe static void ForeachFunctionByteForBCGTransferMultiChannel(Vec3b* value, int* position) { int y = position[0]; int x = position[1]; double v0 = contrast * (value->Item0 - 128.0) + 128.0 + brightness; double v1 = contrast * (value->Item1 - 128.0) + 128.0 + brightness; double v2 = contrast * (value->Item2 - 128.0) + 128.0 + brightness; if (v0 > 255) v0 = 255; else if (v0 < 0) v0 = 0; if (v1 > 255) v1 = 255; else if (v1 < 0) v1 = 0; if (v2 > 255) v2 = 255; else if (v2 < 0) v2 = 0; Vec3b vec = new Vec3b(); vec[0] = (byte)v0; vec[1] = (byte)v1; vec[2] = (byte)v2; phaseTemp1.Set(y, x, vec); } private unsafe static void ForeachFunctionByteForBCGTransferOneChannel(double* value, int* position) { int y = position[0]; int x = position[1]; double v = contrast * (*value - 128.0) + 128.0 + 0; if (v > 255) v = 255; else if (v < 0) v = 0; phaseTemp1.Set(y, x, v); } /// /// unsharp mask /// /// /// public static Mat BlurMaskFunction(Mat src, float radius= 4f * 3.14f, int threshold = 1, float amount = 300f) { Bitmap map = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src); //像素矩阵 var inPixels = ByteArray(map); var workPixels = new int[inPixels.Length]; var outPixels = new int[inPixels.Length]; //半径 if (radius > 0) { Kernel kernel = CreateKernel(radius); ConvolveAndTranspose(kernel, inPixels, workPixels, map.Width, map.Height, true, true, false, 1); ConvolveAndTranspose(kernel, workPixels, outPixels, map.Height, map.Width, true, false, true, 1); } for (int index = 0; index < inPixels.Length; index++) { int rgb1 = inPixels[index]; int r1 = (rgb1 >> 16) & 0xff; int g1 = (rgb1 >> 8) & 0xff; int b1 = rgb1 & 0xff; int rgb2 = outPixels[index]; int r2 = (rgb2 >> 16) & 0xff; int g2 = (rgb2 >> 8) & 0xff; int b2 = rgb2 & 0xff; if (Math.Abs(r1 - r2) >= threshold) { r1 = (int)((amount + 1) * (r1 - r2) + r2); if (r1 < 0) r1 = 0; if (r1 > 255) r1 = 255; } if (Math.Abs(g1 - g2) >= threshold) { g1 = (int)((amount + 1) * (g1 - g2) + g2); if (g1 < 0) g1 = 0; if (g1 > 255) g1 = 255; } if (Math.Abs(b1 - b2) >= threshold) { b1 = (int)((amount + 1) * (b1 - b2) + b2); if (b1 < 0) b1 = 0; if (b1 > 255) b1 = 255; } inPixels[index] = (int)(rgb1 & 0xff000000) | (r1 << 16) | (g1 << 8) | b1; } var byteArray = new byte[inPixels.Length * 4]; for (int i = 0; i < inPixels.Length; i++) { Array.Copy(BitConverter.GetBytes(inPixels[i]), 0, byteArray, i * 4, 4); } Bitmap Image = new Bitmap(map.Width, map.Height, PixelFormat.Format32bppArgb); var data = ((Bitmap)Image).LockBits(new Rectangle(0, 0, Image.Width, Image.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); if (data.Stride == Image.Width * 4) { Marshal.Copy(byteArray, 0, data.Scan0, byteArray.Length); } else { for (int i = 0, l = Image.Height; i < l; i++) { var p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i); Marshal.Copy(byteArray, i * Image.Width * 4, p, Image.Width * 4); } } ((Bitmap)Image).UnlockBits(data); return OpenCvSharp.Extensions.BitmapConverter.ToMat((Bitmap)Image); } /// /// Blur and transpose a block of ARGB pixels. /// /// /// /// /// /// /// /// /// /// public static void ConvolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, bool alpha, bool premultiply, bool unpremultiply, int edgeAction) { float[] matrix = kernel.GetKernel(); int cols = kernel.Width; int cols2 = cols / 2; for (int y = 0; y < height; y++) { int index = y; int ioffset = y * width; for (int x = 0; x < width; x++) { float r = 0, g = 0, b = 0, a = 0; int moffset = cols2; for (int col = -cols2; col <= cols2; col++) { float f = matrix[moffset + col]; if (f != 0) { int ix = x + col; if (ix < 0) { if (edgeAction == 1) ix = 0; else if (edgeAction == 2) ix = (x + width) % width; } else if (ix >= width) { if (edgeAction == 1) ix = width - 1; else if (edgeAction == 2) ix = (x + width) % width; } int rgb = inPixels[ioffset + ix]; int pa = (rgb >> 24) & 0xff; int pr = (rgb >> 16) & 0xff; int pg = (rgb >> 8) & 0xff; int pb = rgb & 0xff; if (premultiply) { float a255 = pa * (1.0f / 255.0f); pr = (int)(pr * a255); pg = (int)(pg * a255); pb = (int)(pb * a255); } a += f * pa; r += f * pr; g += f * pg; b += f * pb; } } if (unpremultiply && a != 0 && a != 255) { float f = 255.0f / a; r *= f; g *= f; b *= f; } int ff = (int)(a + 0.5); if (ff > 255) ff = 255; if (ff < 0) ff = 0; int ia = alpha ? ff : 0xff; int ir = (int)(r + 0.5); if (ir > 255) ir = 255; if (ir < 0) ir = 0; int ig = (int)(g + 0.5); if (ig > 255) ig = 255; if (ig < 0) ig = 0; int ib = (int)(b + 0.5); if (ib > 255) ib = 255; if (ib < 0) ib = 0; outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib; index += height; } } } public static int[] ByteArray(Bitmap map) { var data = map.LockBits(new Rectangle(0, 0, map.Width, map.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); var length = map.Width * map.Height * 4; byte[] _byteArray = new byte[length]; if (data.Stride == map.Width * 4) { Marshal.Copy(data.Scan0, _byteArray, 0, length); } else { for (int i = 0, l = map.Height; i < l; i++) { var p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i); Marshal.Copy(p, _byteArray, i * map.Width * 4, map.Width * 4); } } map.UnlockBits(data); var intArray = new int[_byteArray.Length / 4]; for (int i = 0; i < _byteArray.Length; i += 4) { intArray[i / 4] = BitConverter.ToInt32(_byteArray, i); } return intArray; } /// /// 创建一个高斯滤波核 /// /// 半径 /// kernel public static Kernel CreateKernel(float radius) { var r = (int)Math.Ceiling(radius); int rows = r * 2 + 1; var matrix = new float[rows]; float sigma = radius / 3; float sigma22 = 2 * sigma * sigma; var sigmaPi2 = (float)(2 * Math.PI * sigma); var sqrtSigmaPi2 = (float)Math.Sqrt(sigmaPi2); float radius2 = radius * radius; float total = 0; int index = 0; for (int row = -r; row <= r; row++) { float distance = row * row; if (distance > radius2) matrix[index] = 0; else matrix[index] = (float)Math.Exp(-(distance) / sigma22) / sqrtSigmaPi2; total += matrix[index]; index++; } for (int i = 0; i < rows; i++) { matrix[i] /= total; } return new Kernel(rows, 1, matrix); } /// /// 单通道碎屑删除 /// /// /// public unsafe static Mat SingleChannelDebrisRemoval(Mat src, int v = 20) { Mat labelMat = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); try { original = src; //寻找连通分量 int nonenum = Cv2.ConnectedComponentsWithStats(original, labelMat, stats, centroids, PixelConnectivity.Connectivity8); //寻找在范围内需要删除的碎屑 keyValuePairs.Clear(); for (int h = 1; h < centroids.Height; h++) { int areaField1 = stats.At(h, 4); if (0 <= areaField1 && areaField1 <= v) { keyValuePairs.Add(h, 1); } } labelMat.ForEachAsInt32(SingleCommonForEachForInt32); } catch (Exception ex) { } finally { keyValuePairs.Clear(); if (labelMat != null && !labelMat.IsDisposed) { labelMat.Dispose(); } if (stats != null && !stats.IsDisposed) { stats.Dispose(); } if (centroids != null && !centroids.IsDisposed) { centroids.Dispose(); } System.GC.Collect(); } return src; } private unsafe static void SingleCommonForEachForInt32(int* value, int* position) { int y = position[0]; int x = position[1]; int v = *value; if (v > 0 && keyValuePairs.ContainsKey(v)) { original.Set(y, x, 0); } } /// /// 单通道孔洞填充 /// /// /// /// public unsafe static Mat SingleChannelHoleFilling(Mat src, Vec4b vec4b) { vec4B = vec4b; //去掉透明层 Mat mat = src.CvtColor(ColorConversionCodes.BGRA2BGR); //填充孔洞 mat = Tools.FillHole(mat, new Scalar(255 - vec4B.Item0, 255 - vec4B.Item1, 255 - vec4B.Item2)); src = Tools.FillHole(src, new Scalar(255)); //循环处理 mat.ForEachAsVec3b(RGBForEachAsByteForHoleFillingNewWithView); if (mat != null && !mat.IsDisposed) mat.Dispose(); System.GC.Collect(); return src; } /*private unsafe static void RGBForEachAsByteForHoleFillingNewWithView(Vec3b* value, int* position) { int y = position[0]; int x = position[1]; if (value->Item0 == 255 && value->Item1 == 255 && value->Item2 == 255) { value->Item0 = vec4B.Item0; value->Item1 = vec4B.Item1; value->Item2 = vec4B.Item2; } else { value->Item0 = 255; value->Item1 = 255; value->Item2 = 255; } }*/ } }