using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SmartCoalApplication.Base.CommTool { public class Tools { /// /// 阴影校正 /// /// /// public static Mat ShadingCorrection(Mat src) { if (src.Channels() == 1) return src; Mat temp = null, Ag = null, A0 = null, Aglp = null, dst = null; try { src.ConvertTo(src, MatType.CV_32FC3); temp = src.CvtColor(ColorConversionCodes.BGR2YCrCb); Mat[] tempArr = temp.Split(); Ag = new Mat(); tempArr[0].CopyTo(Ag); ; A0 = new Mat(); Ag.CopyTo(A0); Aglp = ImageSmoothIIR(Ag, 0.99); tempArr[0] = A0 - Aglp + Cv2.Mean(Aglp); dst = new Mat(); Cv2.Merge(tempArr, dst); dst = dst.CvtColor(ColorConversionCodes.YCrCb2BGR); dst.ConvertTo(dst, MatType.CV_8UC3); dst.CopyTo(src); return src; } catch (Exception e) { throw e; } finally { if (temp != null) temp.Dispose(); if (Ag != null) Ag.Dispose(); if (A0 != null) A0.Dispose(); if (Aglp != null) Aglp.Dispose(); if (dst != null) dst.Dispose(); GC.Collect(); } } public static Mat ImageSmoothIIR(Mat I_OUT, double threshold) { int M = I_OUT.Height; int N = I_OUT.Width; for (int P = 1; P < M; P++) { I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P - 1] - I_OUT.Row[P]) + I_OUT.Row[P]; } for (int P = M - 2; P > -1; P--) { I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P + 1] - I_OUT.Row[P]) + I_OUT.Row[P]; } for (int L = 1; L < N; L++) { I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L - 1] - I_OUT.Col[L]) + I_OUT.Col[L]; } for (int L = N - 2; L > -1; L--) { I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L + 1] - I_OUT.Col[L]) + I_OUT.Col[L]; } return I_OUT; } #region 分水岭分割 /** the following constants are used to set bits corresponding to pixel types */ static byte MAXIMUM = (byte)1; // marks local maxima (irrespective of noise tolerance) static byte LISTED = (byte)2; // marks points currently in the list static byte PROCESSED = (byte)4; // marks points processed previously static byte MAX_AREA = (byte)8; // marks areas near a maximum, within the tolerance //static byte EQUAL = (byte)16; // marks contigous maximum points of equal level //static byte MAX_POINT = (byte)32; // marks a single point standing for a maximum static byte ELIMINATED = (byte)64; // marks maxima that have been eliminated before watershed /// /// 分水岭分割 /// /// /// /// public static Mat WatershedSegment(Mat Inmat, int a) { int width = Inmat.Width; int height = Inmat.Height; Mat distance_temp = new Mat(); //Cv2.ImShow("Inmat", Inmat); Cv2.DistanceTransform(Inmat, distance_temp, DistanceTypes.L2, DistanceMaskSize.Precise); //Mat dst_temp = new Mat(); //Cv2.Normalize(src_temp, dst_temp, 0, 255, NormTypes.MinMax); //Mat dst = new Mat(); //dst_temp.ConvertTo(dst, MatType.CV_8UC1); //Cv2.ImShow("DistanceTransform", dst); //getSortedMaxPoints............ BitMap2d ip = new BitMap2d(distance_temp); MaximunFinder maximunFinder = new MaximunFinder(ip); List maxPoints = maximunFinder.FindMaxima(); //AnalyzeAndMarkMaxima............. BitMap2d types = new BitMap2d(width, height, 0); float globalMin = float.MaxValue; float globalMax = float.MinValue; foreach (Int16DoubleWithValue item in maxPoints) { if (item.V < globalMin) globalMin = item.V; if (item.V > globalMax) globalMax = item.V; types.SetPixel(item.O, MAXIMUM); } int nMax = maxPoints.Count(); int[] pList = new int[width * height]; //here we enter points starting from a maximum int[] dirOffset = new int[] { -width, -width + 1, +1, +width + 1, +width, +width - 1, -1, -width - 1 }; float maxSortingError = (float)(1.1 * (Math.Sqrt(2) / 2));//sorted sequence may be inaccurate by this value float tolerance = (float)0.5;// 05; for (int iMax = nMax - 1; iMax >= 0; iMax--) { //process all maxima now, starting from the highest int offset0 = maxPoints[iMax].O; if (((byte)types.GetPixel(offset0) & PROCESSED) != 0) //this maximum has been reached from another one, skip it continue; float v0 = ip.GetPixel(offset0); Boolean sortingError = false; do { pList[0] = offset0; types.SetPixel(offset0, (byte)((byte)types.GetPixel(offset0) | LISTED)); //mark first point as equal height (to itself) and listed int listLen = 1; //number of elements in the list int listI = 0; //index of current element in the list sortingError = false; Boolean maxPossible = true; //it may be a true maximum do { //while neigbor list is not fully processed (to listLen) int offset = pList[listI]; int x = offset % width; int y = offset / width; Boolean isInner = (y != 0 && y != height - 1) && (x != 0 && x != width - 1); //not necessary, but faster than isWithin for (int d = 0; d < 8; d++) { //analyze all neighbors (in 8 directions) at the same level int offset2 = offset + dirOffset[d]; if ((isInner || isWithin(x, y, d, width, height)) && ((byte)types.GetPixel(offset2) & LISTED) == 0) { float v2 = ip.GetPixel(offset2); if (ip.GetPixel(offset2) <= 0) { continue; //ignore the background (non-particles) } if (((byte)types.GetPixel(offset2) & PROCESSED) != 0) { maxPossible = false; //we have reached a point processed previously, thus it is no maximum now break; } if (v2 > v0 + maxSortingError) { maxPossible = false; //we have reached a higher point, thus it is no maximum break; } else if (v2 >= v0 - tolerance) { if (v2 > v0) { sortingError = true; offset0 = offset2; v0 = v2; } pList[listLen] = offset2; listLen++; //we have found a new point within the tolerance types.SetPixel(offset2, (byte)((byte)types.GetPixel(offset2) | LISTED)); } } // if isWithin & not LISTED } // for directions d listI++; } while (listI < listLen); if (sortingError) { //if x0,y0 was not the true maximum but we have reached a higher one for (listI = 0; listI < listLen; listI++) types.SetPixel(pList[listI], (byte)0); //reset all points encountered, then retry } else { //...............................................................................// int resetMask = ~LISTED; for (listI = 0; listI < listLen; listI++) { int offset = pList[listI]; types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) & resetMask)); //reset attributes no longer needed types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | PROCESSED)); //mark as processed if (maxPossible) { types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | MAX_AREA)); //reset attributes no longer needed } } // for listI } } while (sortingError); }// for all maxima iMax //if (nMax == 0) //no initial maxima at all? then consider all as 'within tolerance' // Arrays.fill(types, (byte)(PROCESSED | MAX_AREA)); //makeUEPs::: double threshold = 0.5; //make8bit............ double offset01 = globalMin - (globalMax - globalMin) * (1.0 / 253 / 2 - 1e-6); //everything above minValue should become >(byte)0 double factor = 253 / (globalMax - globalMin); BitMap2d pixels = new BitMap2d(width, height, 0); int dataLen = height * width; for (int offset = 0; offset < dataLen; offset++) { float rawValue = ip.GetPixel(offset); if (rawValue < threshold) { } else if (((byte)types.GetPixel(offset) & MAX_AREA) != 0) pixels.SetPixel(offset, (byte)255); //prepare watershed by setting "true" maxima+surroundings to 255 else { long v = (long)(1 + Math.Round((rawValue - offset01) * factor)); if (v < 1) pixels.SetPixel(offset, (byte)1); else if (v <= 254) pixels.SetPixel(offset, (byte)(v & 255)); else pixels.SetPixel(offset, (byte)254); } } //cleanupMaxima............ for (int iMax = nMax - 1; iMax >= 0; iMax--) { int offset0 = maxPoints[iMax].O; //type cast gets lower 32 bits where pixel offset is encoded if (((int)types.GetPixel(offset0) & (MAX_AREA | ELIMINATED)) != 0) continue; int level = (byte)pixels.GetPixel(offset0) & 255; int loLevel = level + 1; pList[0] = offset0; //we start the list at the current maximum types.SetPixel(offset0, (byte)((byte)types.GetPixel(offset0) | LISTED)); //mark first point as listed int listLen = 1; //number of elements in the list int lastLen = 1; int listI = 0; //index of current element in the list Boolean saddleFound = false; while (!saddleFound && loLevel > 0) { loLevel--; lastLen = listLen; //remember end of list for previous level listI = 0; //in each level, start analyzing the neighbors of all pixels do { //for all pixels listed so far int offset = pList[listI]; int x = offset % width; int y = offset / width; Boolean isInner = (y != 0 && y != height - 1) && (x != 0 && x != width - 1); //not necessary, but faster than isWithin for (int d = 0; d < 8; d++) { //analyze all neighbors (in 8 directions) at the same level int offset2 = offset + dirOffset[d]; if ((isInner || isWithin(x, y, d, width, height)) && ((byte)types.GetPixel(offset2) & LISTED) == 0) { if (((byte)types.GetPixel(offset2) & MAX_AREA) != 0 || ((((byte)types.GetPixel(offset2) & ELIMINATED) != 0) && ((byte)pixels.GetPixel(offset2) & 255) >= loLevel)) { saddleFound = true; //we have reached a point touching a "true" maximum... break; //...or a level not lower, but touching a "true" maximum } else if (((byte)pixels.GetPixel(offset2) & 255) >= loLevel && ((byte)types.GetPixel(offset2) & ELIMINATED) == 0) { pList[listLen] = offset2; listLen++; //we have found a new point to be processed types.SetPixel(offset2, (byte)((byte)types.GetPixel(offset2) | LISTED)); } } // if isWithin & not LISTED } // for directions d if (saddleFound) break; //no reason to search any further listI++; } while (listI < listLen); } // while !levelFound && loLevel>=0 for (listI = 0; listI < listLen; listI++) //reset attribute since we may come to this place again types.SetPixel(pList[listI], (byte)((byte)types.GetPixel(pList[listI]) & ~LISTED)); for (listI = 0; listI < lastLen; listI++) { //for all points higher than the level of the saddle point int offset = pList[listI]; pixels.SetPixel(offset, (byte)loLevel); //set pixel value to the level of the saddle point types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | ELIMINATED)); //mark as processed: there can't be a local maximum in this area } } // for all maxima iMax //watershedSegment int[] histogram = new int[256]; for (int v1 = 0; v1 < 255; v1++) { histogram[v1] = 0; } for (int offset = 0; offset < dataLen; offset++) { int v1 = (byte)pixels.GetPixel(offset) & 255; if (v1 > 0 && v1 < 255) { histogram[v1]++; } } int arraySize = width * height - histogram[0] - histogram[255]; int[] coordinates = new int[arraySize]; //from pixel coordinates, low bits x, high bits y int highestValue = 0; int maxBinSize = 0; int offset02 = 0; int[] levelStart = new int[256]; for (int v1 = 1; v1 < 255; v1++) { levelStart[v1] = offset02; offset02 += histogram[v1]; if (histogram[v1] > 0) highestValue = v1; if (histogram[v1] > maxBinSize) maxBinSize = histogram[v1]; } int[] levelOffset = new int[highestValue + 1]; for (int y = 0, i = 0; y < height; y++) { for (int x = 0; x < width; x++, i++) { int v1 = (byte)pixels.GetPixel(i) & 255; if (v1 > 0 && v1 < 255) { offset02 = levelStart[v1] + levelOffset[v1]; coordinates[offset02] = x + y * width; levelOffset[v1]++; } } //for x } //for y // Create an array of the points (pixel offsets) that we set to 255 in one pass. // If we remember this list we need not create a snapshot of the ImageProcessor. int[] setPointList = new int[Math.Min(maxBinSize, (width * height + 2) / 3)]; // now do the segmentation, starting at the highest level and working down. // At each level, dilate the particle (set pixels to 255), constrained to pixels // whose values are at that level and also constrained (by the fateTable) // to prevent features from merging. int[] table = makeFateTable(); //IJ.showStatus("Segmenting (Esc to cancel)"); /*final */ int[] directionSequence = new int[] { 7, 3, 1, 5, 0, 4, 2, 6 }; // diagonal directions first for (int level = highestValue; level >= 1; level--) { int remaining = histogram[level]; //number of points in the level that have not been processed int idle = 0; while (remaining > 0 && idle < 8) { int sumN = 0; int dIndex = 0; do { // expand each level in 8 directions int n = processLevel(directionSequence[dIndex % 8], pixels, table, levelStart[level], remaining, coordinates, setPointList, width, height); //IJ.log("level="+level+" direction="+directionSequence[dIndex%8]+" remain="+remaining+"-"+n); remaining -= n; // number of points processed sumN += n; if (n > 0) idle = 0; // nothing processed in this direction? dIndex++; } while (remaining > 0 && idle++ < 8); } if (remaining > 0 && level > 1) { // any pixels that we have not reached? int nextLevel = level; // find the next level to process do nextLevel--; while (nextLevel > 1 && histogram[nextLevel] == 0); // in principle we should add all unprocessed pixels of this level to the // tasklist of the next level. This would make it very slow for some images, // however. Thus we only add the pixels if they are at the border (of the // image or a thresholded area) and correct unprocessed pixels at the very // end by CleanupExtraLines if (nextLevel > 0) { int newNextLevelEnd = levelStart[nextLevel] + histogram[nextLevel]; for (int i = 0, p = levelStart[level]; i < remaining; i++, p++) { int pOffset = coordinates[p]; int x = pOffset % width; int y = pOffset / width; //if ((pixels[pOffset] & 255) == 255) IJ.log("ERROR"); Boolean addToNext = false; if (x == 0 || y == 0 || x == width - 1 || y == height - 1) addToNext = true; //image border else for (int d = 0; d < 8; d++) if (isWithin(x, y, d, width, height) && pixels.GetPixel(pOffset + dirOffset[d]) == 0) { addToNext = true; //border of area below threshold break; } if (addToNext) coordinates[newNextLevelEnd++] = pOffset; } //tasklist for the next level to process becomes longer by this: histogram[nextLevel] = newNextLevelEnd - levelStart[nextLevel]; } } } System.Drawing.Color color = Color.Blue; Mat matPixels = OpenCvSharp.Extensions.BitmapConverter.ToMat(pixels.MakeBmp()); for (int h = 0; h < matPixels.Height; h++) { for (int w = 0; w < matPixels.Width; w++) { if (matPixels.At(h, w) == 0) matPixels.Set(h, w, new Vec4b(color.B, color.G, color.R, 255)); else matPixels.Set(h, w, new Vec4b(0, 0, 0, 0)); } } return matPixels; } /** returns whether the neighbor in a given direction is within the image * NOTE: it is assumed that the pixel x,y itself is within the image! * Uses class variables width, height: dimensions of the image * @param x x-coordinate of the pixel that has a neighbor in the given direction * @param y y-coordinate of the pixel that has a neighbor in the given direction * @param direction the direction from the pixel towards the neighbor (see makeDirectionOffsets) * @return true if the neighbor is within the image (provided that x, y is within) */ public static Boolean isWithin(int x, int y, int direction, int width, int height) { int xmax = width - 1; int ymax = height - 1; switch (direction) { case 0: return (y > 0); case 1: return (x < xmax && y > 0); case 2: return (x < xmax); case 3: return (x < xmax && y < ymax); case 4: return (y < ymax); case 5: return (x > 0 && y < ymax); case 6: return (x > 0); case 7: return (x > 0 && y > 0); } return false; //to make the compiler happy :-) } // isWithin /** dilate the UEP on one level by one pixel in the direction specified by step, i.e., set pixels to 255 * @param pass gives direction of dilation, see makeFateTable * @param ip the EDM with the segmeted blobs successively getting set to 255 * @param table The fateTable * @param levelStart offsets of the level in pixelPointers[] * @param levelNPoints number of points in the current level * @param pixelPointers[] list of pixel coordinates (x+y*width) sorted by level (in sequence of y, x within each level) * @param xCoordinates list of x Coorinates for the current level only (no offset levelStart) * @return number of pixels that have been changed */ public static int processLevel(int pass, BitMap2d pixels, int[] fateTable, int levelStart, int levelNPoints, int[] coordinates, int[] setPointList, int width, int height) { int xmax = width - 1; int ymax = height - 1; //byte[] pixels = (byte[])ip.getPixels(); ////byte[] pixels2 = (byte[])ip2.getPixels(); int nChanged = 0; int nUnchanged = 0; for (int i = 0, p = levelStart; i < levelNPoints; i++, p++) { int offset = coordinates[p]; int x = offset % width; int y = offset / width; int index = 0; //neighborhood pixel ocupation: index in fateTable if (y > 0 && ((byte)pixels.GetPixel(offset - width) & 255) == 255) index ^= 1; if (x < xmax && y > 0 && ((byte)pixels.GetPixel(offset - width + 1) & 255) == 255) index ^= 2; if (x < xmax && ((byte)pixels.GetPixel(offset + 1) & 255) == 255) index ^= 4; if (x < xmax && y < ymax && ((byte)pixels.GetPixel(offset + width + 1) & 255) == 255) index ^= 8; if (y < ymax && ((byte)pixels.GetPixel(offset + width) & 255) == 255) index ^= 16; if (x > 0 && y < ymax && ((byte)pixels.GetPixel(offset + width - 1) & 255) == 255) index ^= 32; if (x > 0 && ((byte)pixels.GetPixel(offset - 1) & 255) == 255) index ^= 64; if (x > 0 && y > 0 && ((byte)pixels.GetPixel(offset - width - 1) & 255) == 255) index ^= 128; int mask = 1 << pass; if ((fateTable[index] & mask) == mask) setPointList[nChanged++] = offset; //remember to set pixel to 255 else coordinates[levelStart + (nUnchanged++)] = offset; //keep this pixel for future passes } // for pixel i //IJ.log("pass="+pass+", changed="+nChanged+" unchanged="+nUnchanged); for (int i = 0; i < nChanged; i++) pixels.SetPixel(setPointList[i], (byte)255); return nChanged; } //processLevel static public int[] makeFateTable() { int[] table = new int[256]; Boolean[] isSet = new Boolean[8]; for (int item = 0; item < 256; item++) { //dissect into pixels for (int i = 0, mask = 1; i < 8; i++) { isSet[i] = (item & mask) == mask; mask *= 2; } for (int i = 0, mask = 1; i < 8; i++) { //we dilate in the direction opposite to the direction of the existing neighbors if (isSet[(i + 4) % 8]) table[item] |= mask; mask *= 2; } for (int i = 0; i < 8; i += 2) //if side pixels are set, for counting transitions it is as good as if the adjacent edges were also set if (isSet[i]) { isSet[(i + 1) % 8] = true; isSet[(i + 7) % 8] = true; } int transitions = 0; for (int i = 0; i < 8; i++) { if (isSet[i] != isSet[(i + 1) % 8]) transitions++; } if (transitions >= 4) { //if neighbors contain more than one region, dilation ito this pixel is forbidden table[item] = 0; } else { } } return table; } // int[] makeFateTable /// /// 分水岭分割 /// /// /// /// public static Mat WatershedSegment(Mat Inmat) { //BGR Mat Src_3 = new Mat();// .Clone(); Mat[] arr = new Mat[3]; arr[0] = Inmat; arr[1] = Inmat; arr[2] = Inmat; Cv2.Merge(arr, Src_3); //二值图 Mat mat_bw = GetBW(Inmat); //Cv2.ImShow("mat_bw00", mat_bw); Mat result = Oper_Deal(mat_bw, Src_3); return result;// temp; } private static Mat Oper_Deal(Mat ImIn, Mat src_3) { #region 距离变换 Mat Im1 = new Mat(ImIn.Size(), ImIn.Type()); //归一化 Cv2.Normalize(ImIn, Im1, 0, 1, NormTypes.MinMax); Mat Im_dis = new Mat(ImIn.Size(), MatType.CV_32FC1); Cv2.DistanceTransform(ImIn, Im_dis, DistanceTypes.L2, DistanceMaskSize.Precise); Cv2.Normalize(Im_dis, Im_dis, 0, 1, NormTypes.MinMax); Mat conv = new Mat(Im_dis.Size(), MatType.CV_8UC1); Im_dis.ConvertTo(conv, MatType.CV_8UC1); Cv2.Threshold(conv, conv, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary); #endregion #region 轮廓标记 Mat dis_8U = conv; //提取标记 OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchy; Cv2.FindContours(dis_8U, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point()); #endregion #region 将标记存入markers,作分水岭注水点用 var markers = new Mat(ImIn.Size(), MatType.CV_32SC1, Scalar.All(0)); for (int i = 0; i < contours.Length; i++) { Cv2.DrawContours(markers, contours, i, Scalar.All(i + 1), 10, LineTypes.Link8, hierarchy); } #endregion Cv2.Watershed(src_3, markers); #region 分水岭结果图处理 //连通域为1,线条为0 var markers_ind = markers.GetGenericIndexer(); for (int i = 0; i < markers.Rows; i++) { for (int j = 0; j < markers.Cols; j++) { if (markers_ind[i, j] != -1) { markers_ind[i, j] = int.MaxValue; } else if (markers_ind[i, j] == -1) { markers_ind[i, j] = 0; } } } //结合初始二值图背景为0 var ImIn_ind = ImIn.GetGenericIndexer(); for (int i = 0; i < markers.Rows; i++) { for (int j = 0; j < markers.Cols; j++) { if (ImIn_ind[i, j] == 0) { markers_ind[i, j] = 0; } } } #endregion #region 连通域信息 Mat water = new Mat(markers.Size(), MatType.CV_8UC1); markers.ConvertTo(water, MatType.CV_8UC1); var water_ind = water.GetGenericIndexer(); Mat water_bw = new Mat(); Cv2.Threshold(water, water_bw, 0, 255, ThresholdTypes.Otsu); //连通图的信息获取 Mat labels = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat(); int num = Cv2.ConnectedComponentsWithStats(water_bw, labels, stats, centroids); #endregion #region Vec3b[] color = new Vec3b[num + 1]; color[0] = new Vec3b(0, 0, 0); var stats_ind = stats.GetGenericIndexer(); Random rand = new Random(); byte ranB = (byte)rand.Next(100, 255); byte ranG = (byte)rand.Next(100, 255); byte ranR = (byte)rand.Next(100, 255); for (int i = 1; i < num; i++) { color[i] = new Vec3b(ranB, ranG, ranR); int S = stats_ind[i, 4]; if (S < 200) { color[i] = new Vec3b(0, 0, 0); } } #endregion #region mat填色 Mat final = new Mat(water.Size(), MatType.CV_8UC3); for (int i = 0; i < final.Rows; i++) { for (int j = 0; j < final.Cols; j++) { int label = labels.Get(i, j); final.Set(i, j, color[label]); } } #endregion return final; } private static Mat GetBW(Mat Src) { //(最大类间方差)二值化 //Mat result = Src.Threshold(109.242, 255, ThresholdTypes.Otsu); Mat result = Src.AdaptiveThreshold(255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 35, 5); //Cv2.ImShow("test", result); Cv2.WaitKey(); return result; } public struct Int16DoubleWithValue : IComparable { public int O; public float V; public Int16DoubleWithValue(int offset, float value) { O = offset; V = value; } public int CompareTo(Int16DoubleWithValue other) { return this.V.CompareTo(other.V); } } public class BitMap2d { public float[] data; public int width; public int height; /// /// 初始化操作对象 /// /// /// /// 初始值 public BitMap2d(int width, int height, float v) { this.width = width; this.height = height; data = new float[width * height]; for (int i = 0; i < width * height; i++) data[i] = v; } /// /// 根据mat初始化 /// /// 初始EDM对象 public unsafe BitMap2d(Mat mat) { this.width = mat.Width; this.height = mat.Height; data = new float[width * height]; mat.ForEachAsFloat(FunctionForEachAsFloat); } private unsafe void FunctionForEachAsFloat(float* value, int* position) { data[position[0] * width + position[1]] = *value; } public void SetPixel(int x, int y, byte v) { data[x + y * width] = v; } public float GetPixel(int x, int y) { return data[x + y * width]; } public void SetPixel(int offset, byte v) { data[offset] = v; } public float GetPixel(int offset) { return data[offset]; } public System.Drawing.Bitmap MakeBmp() { float min = float.MaxValue; float max = float.MinValue; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { float r = this.GetPixel(i, j); if (r > max) max = r; if (r < min) min = r; } } float delta = max - min; System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(this.width, this.height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { float r = this.GetPixel(i, j); int b = 255 - (int)(255 * (r - min) / delta); System.Drawing.Color c = System.Drawing.Color.FromArgb((byte)b, (byte)b, (byte)b); bmp.SetPixel(i, j, c); } } return bmp; } } public class MaximunFinder { BitMap2d bmp; int width; int height; public MaximunFinder(BitMap2d bmp) { this.bmp = bmp; this.width = bmp.width; this.height = bmp.height; } public List FindMaxima() { List list = new List(); int offset = 0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++, offset++) { if (IsMaxima(i, j, offset)) { list.Add(new Int16DoubleWithValue(offset, bmp.GetPixel(offset))); } } } list.Sort(); return list; } private bool IsMaxima(int i, int j, int offset) { float v = bmp.GetPixel(offset); if (v == 0) return false; bool b1 = v >= bmp.GetPixel(Math.Max(0, i - 1), Math.Max(0, j - 1)); bool b2 = v >= bmp.GetPixel(i, Math.Max(0, j - 1)); bool b3 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), Math.Max(0, j - 1)); bool b4 = v >= bmp.GetPixel(Math.Max(0, i - 1), j); bool b5 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), j); bool b6 = v >= bmp.GetPixel(Math.Max(0, i - 1), Math.Min(height - 1, j + 1)); bool b7 = v >= bmp.GetPixel(i, Math.Min(height - 1, j + 1)); bool b8 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), Math.Min(height - 1, j + 1)); return b1 && b2 && b3 && b4 && b5 && b6 && b7 && b8 && (v > 0); } } #endregion //颜色集合,用于聚类 public static OpenCvSharp.Scalar[] colorTab = { new OpenCvSharp.Scalar(0,0,255), new OpenCvSharp.Scalar(0,255,0), new OpenCvSharp.Scalar(255,0,0), new OpenCvSharp.Scalar(0,255,255), new OpenCvSharp.Scalar(255,0,255), new OpenCvSharp.Scalar(255,255,0), new OpenCvSharp.Scalar(127,127,0), new OpenCvSharp.Scalar(0,0,127) }; /// /// 直方图平滑 /// /// /// /// public static int[] Smooth(float[] arr, int step) { int start = step - step / 2; int end = 256 - step / 2; double temp = 0; int[] res = new int[256]; for (int i = start; i < end; i++) { temp = 0; for (int j = 0 - step / 2; j < step / 2; j++) { temp += arr[i + j]; } temp /= step; res[i] = (int)temp; } return res; } /// /// 寻找波峰 /// /// /// /// /// /// /// /// /// public static void FindTopAndBetween(int[] hists_new, int leftValue, int rightValue, List mountainsList, List mountainsArrList, List mountainsArrListBackUp, List str, int smoothStep) { //获得去除左右值的最高波峰 int topValue = leftValue; for (int y = leftValue; y < rightValue; y++) { if (hists_new[y] > hists_new[topValue]) { topValue = y; } } if (topValue == 10) { FindTopAndBetween(hists_new, 11, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); return; } mountainsList.Add(topValue); //获得波峰左右的波谷 int leftTrough = topValue; int leftTroughBackUp = 0; //从波峰点向左侧找波谷点 for (int y = topValue - 1; y > leftValue; y--) { if (hists_new[y] > 0 && hists_new[y] <= hists_new[leftTrough]) { leftTrough = y; } else { break; } } //微调 if (smoothStep > 2) { for (int y = leftTrough + 1; y < topValue; y++) { if (hists_new[y] == hists_new[leftTrough])// || hists_new[y] < hists_new[topValue] / 10) { leftTroughBackUp = y; } } } if (leftTroughBackUp == 0) leftTroughBackUp = leftTrough; int rightTrough = topValue; int rightTroughBackUp = 0; //从波峰点向右侧找波谷点 for (int y = topValue + 1; y < rightValue; y++) { if (hists_new[y] > 0 && hists_new[y] <= hists_new[rightTrough]) { rightTrough = y; } else { break; } } //微调 if (smoothStep > 2) { for (int y = rightTrough - 1; y > topValue; y--) { if (hists_new[y] == hists_new[rightTrough])// || hists_new[y] < hists_new[topValue] / 10) { rightTroughBackUp = y; } } } if (rightTroughBackUp == 0) rightTroughBackUp = rightTrough; int[] arr = new int[2]; arr[0] = leftTroughBackUp; arr[1] = rightTroughBackUp; mountainsArrList.Add(arr); int[] arr1 = new int[2]; arr1[0] = leftTroughBackUp > 0 ? leftTroughBackUp : leftTrough; arr1[1] = rightTroughBackUp > 0 ? rightTroughBackUp : rightTrough; mountainsArrListBackUp.Add(arr1); if (leftValue < leftTrough - 1) { if (!str.Contains(leftValue + "|" + leftTrough)) { str.Add(leftValue + "|" + leftTrough); FindTopAndBetween(hists_new, leftValue, leftTrough, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); } } if (rightValue > rightTrough + 1) { if (!str.Contains(rightValue + "|" + rightTrough)) { str.Add(rightValue + "|" + rightTrough); FindTopAndBetween(hists_new, rightTrough, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); } } } public static void FindTopAndBetweenWithOutWT(int[] hists_new, int leftValue, int rightValue, List mountainsList, List mountainsArrList, List mountainsArrListBackUp, List str, int smoothStep) { //获得去除左右值的最高波峰 int topValue = leftValue; for (int y = leftValue; y < rightValue; y++) { if (hists_new[y] > hists_new[topValue]) { topValue = y; } } if (topValue == 10) { FindTopAndBetween(hists_new, 11, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); return; } mountainsList.Add(topValue); //获得波峰左右的波谷 int leftTrough = topValue; int leftTroughBackUp = 0; //从波峰点向左侧找波谷点 for (int y = topValue - 1; y > leftValue; y--) { if (hists_new[y] > 0 && hists_new[y] <= hists_new[leftTrough]) { leftTrough = y; } else { break; } } //微调 //if (smoothStep >= 30) { for (int y = leftTrough + 1; y < topValue; y++) { if (hists_new[y] == hists_new[leftTrough] || hists_new[y] < hists_new[topValue] / 10) { leftTroughBackUp = y; } } } if (leftTroughBackUp == 0) leftTroughBackUp = leftTrough; int rightTrough = topValue; int rightTroughBackUp = 0; //从波峰点向右侧找波谷点 for (int y = topValue + 1; y < rightValue; y++) { if (hists_new[y] > 0 && hists_new[y] <= hists_new[rightTrough]) { rightTrough = y; } else { break; } } //微调 //if (smoothStep >= 30) { for (int y = rightTrough - 1; y > topValue; y--) { if (hists_new[y] == hists_new[rightTrough] || hists_new[y] < hists_new[topValue] / 10) { rightTroughBackUp = y; } } } if (rightTroughBackUp == 0) rightTroughBackUp = rightTrough; int[] arr = new int[2]; arr[0] = leftTroughBackUp; arr[1] = rightTroughBackUp; mountainsArrList.Add(arr); int[] arr1 = new int[2]; arr1[0] = leftTroughBackUp > 0 ? leftTroughBackUp : leftTrough; arr1[1] = rightTroughBackUp > 0 ? rightTroughBackUp : rightTrough; mountainsArrListBackUp.Add(arr1); if (leftValue < leftTrough - 1) { if (!str.Contains(leftValue + "|" + leftTrough)) { str.Add(leftValue + "|" + leftTrough); FindTopAndBetween(hists_new, leftValue, leftTrough, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); } } if (rightValue > rightTrough + 1) { if (!str.Contains(rightValue + "|" + rightTrough)) { str.Add(rightValue + "|" + rightTrough); FindTopAndBetween(hists_new, rightTrough, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); } } } public unsafe static double Entropy(Mat img) { // 将输入的矩阵为图像 double[] temp = new double[256]; // 清零 for (int i = 0; i < 256; i++) { temp[i] = 0.0; } // 计算每个像素的累积值 for (int m = 0; m < img.Rows; m++) {// 有效访问行列的方式 byte* t = (byte*)img.Ptr(m); for (int n = 0; n < img.Cols; n++) { int i = t[n]; temp[i] = temp[i] + 1; } } // 计算每个像素的概率 for (int i = 0; i < 256; i++) { temp[i] = temp[i] / (img.Rows * img.Cols); } double result = 0; // 根据定义计算图像熵 for (int i = 0; i < 256; i++) { if (temp[i] == 0.0) result = result; else result = result - temp[i] * (Math.Log(temp[i]) / Math.Log(2.0)); } return result; } /// /// 计算图像的熵 /// /// /// /// /// public static double GetEntropy(Bitmap bmp, int w, int h) { int g; double H = 0.0; int[] pix = new int[256]; Array.Clear(pix, 0, 256); //获取各灰度值的像素个数 for (int i = 0; i < h; i++) { for (int j = 0; j < w; j++) { Color c = bmp.GetPixel(j, i); g = (int)(0.299 * c.R + 0.587 * c.B + 0.114 * c.G); pix[g]++; } } //计算熵 for (int i = 0; i < 256; i++) { if (pix[i] > 0) { H = H + pix[i] * Math.Log10(pix[i]); } } H = Math.Log10(w * h) / Math.Log10(2) - H / (w * h * Math.Log10(2)); return H; } /// /// 计算占比 /// /// /// /// /// public static double GetAreaRatio(int max, int[] hists_new, int[] toplow) { int all = 0; int area = 0; for (int i = toplow[0]; i < toplow[1]; i++) { all += hists_new[i]; if (i <= max + 10 && i >= max - 10) { area += hists_new[i]; } } return area * 1d * 100 / all; } /// /// 计算阈值 /// /// 最大值 /// 最小值 /// 1左 2右 /// 直方图 /// public static double GetTriangleThreshold(int leftv, int topv, int rightv, int t, int[] hists_new) { int left_bound = leftv, right_bound = rightv, max_ind = topv, max = hists_new[topv]; int temp; bool isflipped = false; int i = 0, j = 0; int N = 256; // 如果最大值落在靠左侧这样就无法满足三角法求阈值,所以要检测是否最大值是否靠近左侧 // 如果靠近左侧则通过翻转到右侧位置。 if (max_ind - left_bound < right_bound - max_ind)//max_ind - left_bound < right_bound - max_ind { isflipped = true; i = 0; j = N - 1; while (i < j) { // 左右交换 temp = hists_new[i]; hists_new[i] = hists_new[j]; hists_new[j] = temp; i++; j--; } left_bound = N - 1 - right_bound; max_ind = N - 1 - max_ind; } // 计算求得阈值 double thresh = left_bound; double a, b, dist = 0, tempdist; a = max; b = left_bound - max_ind; for (i = left_bound + 1; i <= max_ind; i++) { // 计算距离 - 不需要真正计算 tempdist = a * i + b * hists_new[i]; if (tempdist > dist) { dist = tempdist; thresh = i; } } thresh--; if (isflipped) thresh = N - 1 - thresh; return thresh; } /// /// 计算K类均值的每个类的灰度均值,面积 /// public static List CalaKmeanMatMeans(OpenCvSharp.Mat origin, OpenCvSharp.Mat kmean, out List nums) { OpenCvSharp.Mat gray = origin.CvtColor(OpenCvSharp.ColorConversionCodes.BGR2GRAY); //像素点个数 List points = new List(); points.Add(0); points.Add(0); points.Add(0); points.Add(0); points.Add(0); //像素点灰度值的和 List grays = new List(); grays.Add(0); grays.Add(0); grays.Add(0); grays.Add(0); grays.Add(0); new OpenCvSharp.Scalar(0, 0, 255); new OpenCvSharp.Scalar(0, 255, 0); new OpenCvSharp.Scalar(255, 0, 0); new OpenCvSharp.Scalar(0, 255, 255); new OpenCvSharp.Scalar(255, 0, 255); for (int h = 0; h < kmean.Height; h++) { for (int w = 0; w < kmean.Width; w++) { OpenCvSharp.Vec3b vec3B = kmean.At(h, w); if (vec3B.Item0 == 0 && vec3B.Item1 == 0 && vec3B.Item2 == 255) { points[0] += 1; grays[0] += gray.At(h, w); } else if (vec3B.Item0 == 0 && vec3B.Item1 == 255 && vec3B.Item2 == 0) { points[1] += 1; grays[1] += gray.At(h, w); } else if (vec3B.Item0 == 255 && vec3B.Item1 == 0 && vec3B.Item2 == 0) { points[2] += 1; grays[2] += gray.At(h, w); } else if (vec3B.Item0 == 0 && vec3B.Item1 == 255 && vec3B.Item2 == 255) { points[3] += 1; grays[3] += gray.At(h, w); } else if (vec3B.Item0 == 255 && vec3B.Item1 == 0 && vec3B.Item2 == 255) { points[4] += 1; grays[4] += gray.At(h, w); } } } nums = points; List vs = new List(); for (int i = 0; i < 5; i++) { vs.Add(grays[i] * 1f / points[i]); } return vs; } /// /// 判断点a和点b是否颜色一样 /// /// /// /// public static bool AdjustNearColor(Vec3b v, Scalar b) { if (v.Item0 == b.Val0 && v.Item1 == b.Val1 && v.Item2 == b.Val2) return true; else return false; } public static bool AdjustNearBy(Vec3b v, Vec3b b) { if (b.Item0 == 0 && b.Item1 == 0 && b.Item2 == 0) { return false; } else { if (v.Item0 != b.Item0 || v.Item1 != b.Item1 || v.Item2 != b.Item2) return true; else return false; } } public static void FindTopAndBetweenWithOutWT123(int[] hists_new, int leftValue, int rightValue, List mountainsList, List mountainsArrList, List mountainsArrListBackUp, List str, int smoothStep) { //获得去除左右值的最高波峰 int topValue = leftValue; for (int y = leftValue; y < rightValue; y++) { if (hists_new[y] > hists_new[topValue]) { topValue = y; } } if (topValue == 0 || topValue == leftValue || topValue == rightValue) return; mountainsList.Add(topValue); //获得波峰左右的波谷 int leftTrough = topValue; int leftTroughBackUp = 0; //从波峰点向左侧找波谷点 for (int y = topValue - 1; y > leftValue; y--) { if (hists_new[y] >= 0 && hists_new[y] <= hists_new[leftTrough]) { leftTrough = y; } else { break; } } //微调 //if (smoothStep >= 30) { for (int y = leftTrough + 1; y < topValue; y++) { if (hists_new[y] == hists_new[leftTrough])// || hists_new[y] < hists_new[topValue] / 10 { leftTroughBackUp = y; } } } if (leftTroughBackUp == 0) leftTroughBackUp = leftTrough; int rightTrough = topValue; int rightTroughBackUp = 0; //从波峰点向右侧找波谷点 for (int y = topValue + 1; y < rightValue; y++) { if (hists_new[y] >= 0 && hists_new[y] <= hists_new[rightTrough]) { rightTrough = y; } else { break; } } //微调 //if (smoothStep >= 30) { for (int y = rightTrough - 1; y > topValue; y--) { if (hists_new[y] == hists_new[rightTrough])// || hists_new[y] < hists_new[topValue] / 10 { rightTroughBackUp = y; } } } if (rightTroughBackUp == 0) rightTroughBackUp = rightTrough; int[] arr = new int[2]; arr[0] = leftTroughBackUp; arr[1] = rightTroughBackUp; mountainsArrList.Add(arr); int[] arr1 = new int[2]; arr1[0] = leftTroughBackUp > 0 ? leftTroughBackUp : leftTrough; arr1[1] = rightTroughBackUp > 0 ? rightTroughBackUp : rightTrough; mountainsArrListBackUp.Add(arr1); if (leftValue < leftTrough - 1) { if (!str.Contains(leftValue + "|" + leftTrough)) { str.Add(leftValue + "|" + leftTrough); FindTopAndBetweenWithOutWT123(hists_new, leftValue, leftTrough, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); } } if (rightValue > rightTrough + 1) { if (!str.Contains(rightValue + "|" + rightTrough)) { str.Add(rightValue + "|" + rightTrough); FindTopAndBetweenWithOutWT123(hists_new, rightTrough, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep); } } } public static float areaRatio(int[] hists_new, int[] se) { int sum = hists_new.Sum(); int sum1 = 0; for (int i = se[0]; i < se[1]; i++) { sum1 += hists_new[i]; } return (sum1 * 1f / sum) * 100; } /// /// 测试用标尺 /// public static double bc = 5.3191 / 1000; /// /// 获取两点之间的距离 /// /// /// /// public static double getDistance(OpenCvSharp.Point pointO, OpenCvSharp.Point pointA) { double distance; distance = Math.Pow((pointO.X - pointA.X), 2) + Math.Pow((pointO.Y - pointA.Y), 2); distance = Math.Sqrt(distance); return distance; } /// /// 获取点到直线的距离 /// /// /// /// /// public static float getDist_P2L(OpenCvSharp.Point pointP, OpenCvSharp.Point pointA, OpenCvSharp.Point pointB) { int A = 0, B = 0, C = 0; A = pointA.Y - pointB.Y; B = pointB.X - pointA.X; C = pointA.X * pointB.Y - pointA.Y * pointB.X; float distance = 0; distance = ((float)Math.Abs(A * pointP.X + B * pointP.Y + C)) / ((float)Math.Sqrt(A * A + B * B)); return distance; } /// /// 原本是打算做返回随机颜色 /// /// public static Scalar GetRandumScalar() { return new Scalar(0, 0, 255); } /// /// 深度copy /// /// /// public static List CopyPoints(List src) { List dst = new List(); foreach (OpenCvSharp.Point point in src) { OpenCvSharp.Point p = new OpenCvSharp.Point(); p.X = point.X; p.Y = point.Y; dst.Add(p); } return dst; } /// /// 获取周围的点的数量,并且判断结点 /// /// /// /// /// public static int GetAroundNum(List points, OpenCvSharp.Point jiedian, OpenCvSharp.Point temp) { if (points.IndexOf(temp) < 0) { return 2; } int i = 0; OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (points.IndexOf(zuo) >= 0) { if (zuo.X != jiedian.X || zuo.Y != jiedian.Y) i++; } if (points.IndexOf(zuo_shang) >= 0) { if (zuo_shang.X != jiedian.X || zuo_shang.Y != jiedian.Y) i++; } if (points.IndexOf(shang) >= 0) { if (shang.X != jiedian.X || shang.Y != jiedian.Y) i++; } if (points.IndexOf(you_shang) >= 0) { if (you_shang.X != jiedian.X || you_shang.Y != jiedian.Y) i++; } if (points.IndexOf(you) >= 0) { if (you.X != jiedian.X || you.Y != jiedian.Y) i++; } if (points.IndexOf(you_xia) >= 0) { if (you_xia.X != jiedian.X || you_xia.Y != jiedian.Y) i++; } if (points.IndexOf(xia) >= 0) { if (xia.X != jiedian.X || xia.Y != jiedian.Y) i++; } if (points.IndexOf(zuo_xia) >= 0) { if (zuo_xia.X != jiedian.X || zuo_xia.Y != jiedian.Y) i++; } return i; } /// /// 获取起点和终点的路径上的所有点 /// /// public static List GetPassPoints(List points, List jiedians, OpenCvSharp.Point start, OpenCvSharp.Point end) { List passPoints = new List(); List copys = CopyPoints(points); OpenCvSharp.Point temp = start; bool loopFlag = true; do { int num = 0; copys.Remove(temp); OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (copys.IndexOf(zuo) >= 0) { temp = zuo; passPoints.Add(zuo); copys.Remove(zuo); num++; } if (copys.IndexOf(zuo_shang) >= 0) { temp = zuo_shang; passPoints.Add(zuo_shang); copys.Remove(zuo_shang); num++; } if (copys.IndexOf(shang) >= 0) { temp = shang; passPoints.Add(shang); copys.Remove(shang); num++; } if (copys.IndexOf(you_shang) >= 0) { temp = you_shang; passPoints.Add(you_shang); copys.Remove(you_shang); num++; } if (copys.IndexOf(you) >= 0) { temp = you; passPoints.Add(you); copys.Remove(you); num++; } if (copys.IndexOf(you_xia) >= 0) { temp = you_xia; passPoints.Add(you_xia); copys.Remove(you_xia); num++; } if (copys.IndexOf(xia) >= 0) { temp = xia; passPoints.Add(xia); copys.Remove(xia); num++; } if (copys.IndexOf(zuo_xia) >= 0) { temp = zuo_xia; passPoints.Add(zuo_xia); copys.Remove(zuo_xia); num++; } if (num > 1 || num == 0) loopFlag = false; } while (loopFlag); temp = end; loopFlag = true; do { int num = 0; copys.Remove(temp); OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (copys.IndexOf(zuo) >= 0) { temp = zuo; passPoints.Add(zuo); copys.Remove(zuo); num++; } if (copys.IndexOf(zuo_shang) >= 0) { temp = zuo_shang; passPoints.Add(zuo_shang); copys.Remove(zuo_shang); num++; } if (copys.IndexOf(shang) >= 0) { temp = shang; passPoints.Add(shang); copys.Remove(shang); num++; } if (copys.IndexOf(you_shang) >= 0) { temp = you_shang; passPoints.Add(you_shang); copys.Remove(you_shang); num++; } if (copys.IndexOf(you) >= 0) { temp = you; passPoints.Add(you); copys.Remove(you); num++; } if (copys.IndexOf(you_xia) >= 0) { temp = you_xia; passPoints.Add(you_xia); copys.Remove(you_xia); num++; } if (copys.IndexOf(xia) >= 0) { temp = xia; passPoints.Add(xia); copys.Remove(xia); num++; } if (copys.IndexOf(zuo_xia) >= 0) { temp = zuo_xia; passPoints.Add(zuo_xia); copys.Remove(zuo_xia); num++; } if (num > 1 || num == 0) loopFlag = false; } while (loopFlag); return passPoints; } /// /// 近似判断临近点是否再直线上 /// /// /// /// public static bool IsNearPoint(List points, OpenCvSharp.Point seed) { if (points.IndexOf(seed) >= 0) return true; OpenCvSharp.Point zuo = new OpenCvSharp.Point(seed.X - 1, seed.Y); if (points.IndexOf(zuo) >= 0) return true; OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(seed.X - 1, seed.Y - 1); if (points.IndexOf(zuo_shang) >= 0) return true; OpenCvSharp.Point shang = new OpenCvSharp.Point(seed.X, seed.Y - 1); if (points.IndexOf(shang) >= 0) return true; OpenCvSharp.Point you_shang = new OpenCvSharp.Point(seed.X + 1, seed.Y - 1); if (points.IndexOf(you_shang) >= 0) return true; OpenCvSharp.Point you = new OpenCvSharp.Point(seed.X + 1, seed.Y); if (points.IndexOf(you) >= 0) return true; OpenCvSharp.Point you_xia = new OpenCvSharp.Point(seed.X + 1, seed.Y + 1); if (points.IndexOf(you_xia) >= 0) return true; OpenCvSharp.Point xia = new OpenCvSharp.Point(seed.X, seed.Y + 1); if (points.IndexOf(xia) >= 0) return true; OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(seed.X - 1, seed.Y + 1); if (points.IndexOf(zuo_xia) >= 0) return true; return false; } /// /// 检测两个点之间是否连通 /// 程序不太对,还得在修改 /// /// /// /// /// public static bool existLianTong(List points, OpenCvSharp.Point pointa, OpenCvSharp.Point pointb) { List copys = CopyPoints(points); bool lt = false; bool isis = true; OpenCvSharp.Point temp = pointa; do { bool inArr = false; copys.Remove(temp); OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (points.IndexOf(zuo) >= 0) { if (zuo.X == pointb.X && zuo.Y == pointb.Y) { lt = true; isis = false; } temp = zuo; inArr = true; } if (points.IndexOf(zuo_shang) >= 0) { if (zuo_shang.X == pointb.X && zuo_shang.Y == pointb.Y) { lt = true; isis = false; } temp = zuo_shang; inArr = true; } if (points.IndexOf(shang) >= 0) { if (shang.X == pointb.X && shang.Y == pointb.Y) { lt = true; isis = false; } temp = shang; inArr = true; } if (points.IndexOf(you_shang) >= 0) { if (you_shang.X == pointb.X && you_shang.Y == pointb.Y) { lt = true; isis = false; } temp = you_shang; inArr = true; } if (points.IndexOf(you) >= 0) { if (you.X == pointb.X && you.Y == pointb.Y) { lt = true; isis = false; } temp = you; inArr = true; } if (points.IndexOf(you_xia) >= 0) { if (you_xia.X == pointb.X && you_xia.Y == pointb.Y) { lt = true; isis = false; } temp = you_xia; inArr = true; } if (points.IndexOf(xia) >= 0) { if (xia.X == pointb.X && xia.Y == pointb.Y) { lt = true; isis = false; } temp = xia; inArr = true; } if (points.IndexOf(zuo_xia) >= 0) { if (zuo_xia.X == pointb.X && zuo_xia.Y == pointb.Y) { lt = true; isis = false; } temp = zuo_xia; inArr = true; } if (!inArr) isis = false; } while (isis); return lt; } /// /// 判断删除当前点是否破坏连通性 /// /// public static bool panduanDestoryConn(List points, OpenCvSharp.Point pointa) { List copys = CopyPoints(points); OpenCvSharp.Point temp = pointa; OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); int a1 = Tools.GetAroundNum(points, temp, zuo); int a2 = Tools.GetAroundNum(points, temp, zuo_shang); int a3 = Tools.GetAroundNum(points, temp, shang); int a4 = Tools.GetAroundNum(points, temp, you_shang); int a5 = Tools.GetAroundNum(points, temp, you); int a6 = Tools.GetAroundNum(points, temp, you_xia); int a7 = Tools.GetAroundNum(points, temp, xia); int a8 = Tools.GetAroundNum(points, temp, zuo_xia); if (a1 >= 2 && a2 >= 2 && a3 >= 2 && a4 >= 2 && a5 >= 2 && a6 >= 2 && a7 >= 2 && a8 >= 2) { return false; } return true; } /// /// 寻找端点 /// /// /// public static List FindEndpoints(List points) { List endpoints = new List(); foreach (OpenCvSharp.Point point in points) { OpenCvSharp.Point zuo = new OpenCvSharp.Point(point.X - 1, point.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(point.X - 1, point.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(point.X, point.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(point.X + 1, point.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(point.X + 1, point.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(point.X + 1, point.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(point.X, point.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(point.X - 1, point.Y + 1); int a = points.IndexOf(zuo) >= 0 ? 1 : 0; int b = points.IndexOf(zuo_shang) >= 0 ? 1 : 0; int c = points.IndexOf(shang) >= 0 ? 1 : 0; int d = points.IndexOf(you_shang) >= 0 ? 1 : 0; int e = points.IndexOf(you) >= 0 ? 1 : 0; int f = points.IndexOf(you_xia) >= 0 ? 1 : 0; int g = points.IndexOf(xia) >= 0 ? 1 : 0; int h = points.IndexOf(zuo_xia) >= 0 ? 1 : 0; int all = a + b + c + d + e + f + g + h; if (all == 1) { endpoints.Add(point); } else if (all == 2) { if (a == 1 && b == 1) endpoints.Add(point); if (b == 1 && c == 1) endpoints.Add(point); if (c == 1 && d == 1) endpoints.Add(point); if (d == 1 && e == 1) endpoints.Add(point); if (e == 1 && f == 1) endpoints.Add(point); if (f == 1 && g == 1) endpoints.Add(point); if (g == 1 && h == 1) endpoints.Add(point); if (h == 1 && a == 1) endpoints.Add(point); } } return endpoints; } /// /// 移除点 /// /// 连通域集合 /// 已用的端点集合 public static List RemoveSomePoint(List points, List pairs, List jiedians) { List copys = CopyPoints(points); foreach (OpenCvSharp.Point p1 in pairs) { bool nkkk = true; OpenCvSharp.Point temp = p1; do { bool isexit = false; copys.Remove(temp); OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (copys.IndexOf(zuo) >= 0) { isexit = true; if (jiedians.IndexOf(zuo) >= 0) { nkkk = false; } else { temp = zuo; copys.Remove(zuo); } } if (copys.IndexOf(zuo_shang) >= 0) { isexit = true; if (jiedians.IndexOf(zuo_shang) >= 0) { nkkk = false; } else { temp = zuo_shang; copys.Remove(zuo_shang); } } if (copys.IndexOf(shang) >= 0) { isexit = true; if (jiedians.IndexOf(shang) >= 0) { nkkk = false; } else { temp = shang; copys.Remove(shang); } } if (copys.IndexOf(you_shang) >= 0) { isexit = true; if (jiedians.IndexOf(you_shang) >= 0) { nkkk = false; } else { temp = you_shang; copys.Remove(you_shang); } } if (copys.IndexOf(you) >= 0) { isexit = true; if (jiedians.IndexOf(you) >= 0) { nkkk = false; } else { temp = you; copys.Remove(you); } } if (copys.IndexOf(you_xia) >= 0) { isexit = true; if (jiedians.IndexOf(you_xia) >= 0) { nkkk = false; } else { temp = you_xia; copys.Remove(you_xia); } } if (copys.IndexOf(xia) >= 0) { isexit = true; if (jiedians.IndexOf(xia) >= 0) { nkkk = false; } else { temp = xia; copys.Remove(xia); } } if (copys.IndexOf(zuo_xia) >= 0) { isexit = true; if (jiedians.IndexOf(zuo_xia) >= 0) { nkkk = false; } else { temp = zuo_xia; copys.Remove(zuo_xia); } } if (!isexit) nkkk = false; } while (nkkk); } return copys; } /// /// 寻找结点 /// /// /// public static List FindIntersectionPoint(List points) { List ps = new List(); //1左 2左上 3上 4右上 5右 6右下 7下 8左下 for (int i = 0; i < points.Count - 1; i++) { OpenCvSharp.Point point = points[i]; OpenCvSharp.Point zuo = new OpenCvSharp.Point(point.X - 1, point.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(point.X - 1, point.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(point.X, point.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(point.X + 1, point.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(point.X + 1, point.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(point.X + 1, point.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(point.X, point.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(point.X - 1, point.Y + 1); int a = points.IndexOf(zuo) >= 0 ? 1 : 0; int b = points.IndexOf(zuo_shang) >= 0 ? 1 : 0; int c = points.IndexOf(shang) >= 0 ? 1 : 0; int d = points.IndexOf(you_shang) >= 0 ? 1 : 0; int e = points.IndexOf(you) >= 0 ? 1 : 0; int f = points.IndexOf(you_xia) >= 0 ? 1 : 0; int g = points.IndexOf(xia) >= 0 ? 1 : 0; int h = points.IndexOf(zuo_xia) >= 0 ? 1 : 0; int all = a + b + c + d + e + f + g + h; if (all > 2) { ps.Add(point); } } if (ps.Count > 1) { List copys = CopyPoints(ps); for (int i = ps.Count - 1; i >= 0; i--) { OpenCvSharp.Point temp = ps[i]; ps.Remove(temp); OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (ps.IndexOf(zuo) >= 0) { copys.Remove(zuo); } if (ps.IndexOf(zuo_shang) >= 0) { copys.Remove(zuo_shang); } if (ps.IndexOf(shang) >= 0) { copys.Remove(shang); } if (ps.IndexOf(you_shang) >= 0) { copys.Remove(you_shang); } if (ps.IndexOf(you) >= 0) { copys.Remove(you); } if (ps.IndexOf(you_xia) >= 0) { copys.Remove(you_xia); } if (ps.IndexOf(xia) >= 0) { copys.Remove(xia); } if (ps.IndexOf(zuo_xia) >= 0) { copys.Remove(zuo_xia); } } return copys; } return ps; } public static bool ExistInList(List> lists, OpenCvSharp.Point point) { foreach (List list in lists) { if (list.IndexOf(point) >= 0) { return true; } } return false; } /// /// 从一个端点出发,遇到结点,进行直线拟合 /// /// /// /// public static bool FindLineFromOnePoint(List copys, OpenCvSharp.Point point, out Line2D line) { //原集合的copy List copys_1 = Tools.CopyPoints(copys); //用于存放起始点 List temps = new List(); int num = 0; OpenCvSharp.Point temp = point; copys_1.Remove(temp); do { num = 0; OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (copys_1.IndexOf(zuo) >= 0) { temp = zuo; copys_1.Remove(temp); temps.Add(zuo); num++; } if (copys_1.IndexOf(zuo_shang) >= 0) { temp = zuo_shang; copys_1.Remove(temp); temps.Add(zuo_shang); num++; } if (copys_1.IndexOf(shang) >= 0) { temp = shang; copys_1.Remove(temp); temps.Add(shang); num++; } if (copys_1.IndexOf(you_shang) >= 0) { temp = you_shang; copys_1.Remove(temp); temps.Add(you_shang); num++; } if (copys_1.IndexOf(you) >= 0) { temp = you; copys_1.Remove(temp); temps.Add(you); num++; } if (copys_1.IndexOf(you_xia) >= 0) { temp = you_xia; copys_1.Remove(temp); temps.Add(you_xia); num++; } if (copys_1.IndexOf(xia) >= 0) { temp = xia; copys_1.Remove(temp); temps.Add(xia); num++; } if (copys_1.IndexOf(zuo_xia) >= 0) { temp = zuo_xia; copys_1.Remove(temp); temps.Add(zuo_xia); num++; } } while (num == 1); if (temps.Count < 10) { temps.RemoveAt(temps.Count - 1); temps.RemoveAt(temps.Count - 1); } else { int delNum = temps.Count / 5; int min = temps.Count - delNum; for (int i = temps.Count - 1; i > min; i--) temps.Remove(temps[i]); } if (temps.Count >= 2) line = Cv2.FitLine(temps, DistanceTypes.Huber, 0, 0.01, 0.01); else line = new Line2D(0, 0, 0, 0); if (temps.Count < 4) { return false; } return true; /*if (line2D.Y1 > 0) { //这是获取直线上的点方程 OpenCvSharp.Point a = new OpenCvSharp.Point((int)(line2D.X1 - 100 * line2D.Vx), (int)(line2D.Y1 - 100 * line2D.Vy)); OpenCvSharp.Point b = new OpenCvSharp.Point((int)(line2D.X1 - 10 * line2D.Vx), (int)(line2D.Y1 - 10 * line2D.Vy)); //Cv2.Line(origin, a, b, new Scalar(0, 0, 255), 2); //Cv2.ImWrite("C:\\Users\\zyh\\Desktop\\fuck.png", origin); }*/ } /// /// 使用mul获取直线上的点 /// /// /// /// public static OpenCvSharp.Point GetOnLineNextPoint(Line2D line2D, int mul) { //但是需要考虑直线垂直或平行x、y轴的时候 return new OpenCvSharp.Point((int)(line2D.X1 - mul * line2D.Vx), (int)(line2D.Y1 - mul * line2D.Vy)); } /// /// 使用直线方程获取直线上的点 /// /// /// /// public static int GetMulByPoint(Line2D line2D, OpenCvSharp.Point point) { if (line2D.Vy == 1) return (int)(line2D.Y1 - point.Y); if (line2D.Vx == 1) return (int)(line2D.X1 - point.X); if (line2D.Vx > 0.01) return (int)((line2D.X1 - point.X) / line2D.Vx); else return (int)((line2D.Y1 - point.Y) / line2D.Vy); } /// /// 获取相邻的点的数量 /// /// /// /// public static int GetAroundNumWithNotJ(List points, OpenCvSharp.Point temp) { int i = 0; OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); if (points.IndexOf(zuo) >= 0) i++; if (points.IndexOf(zuo_shang) >= 0) i++; if (points.IndexOf(shang) >= 0) i++; if (points.IndexOf(you_shang) >= 0) i++; if (points.IndexOf(you) >= 0) i++; if (points.IndexOf(you_xia) >= 0) i++; if (points.IndexOf(xia) >= 0) i++; if (points.IndexOf(zuo_xia) >= 0) i++; return i; } /// /// 判断点是否是端点 /// /// /// /// public static bool FindEndpoints(List points, OpenCvSharp.Point temp) { OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y); OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1); OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1); OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1); OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y); OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1); OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1); OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1); int a = points.IndexOf(zuo) >= 0 ? 1 : 0; int b = points.IndexOf(zuo_shang) >= 0 ? 1 : 0; int c = points.IndexOf(shang) >= 0 ? 1 : 0; int d = points.IndexOf(you_shang) >= 0 ? 1 : 0; int e = points.IndexOf(you) >= 0 ? 1 : 0; int f = points.IndexOf(you_xia) >= 0 ? 1 : 0; int g = points.IndexOf(xia) >= 0 ? 1 : 0; int h = points.IndexOf(zuo_xia) >= 0 ? 1 : 0; int all = a + b + c + d + e + f + g + h; if (all == 1) { return true; } else if (all == 2) { if (a == 1 && b == 1) return true; if (b == 1 && c == 1) return true; if (c == 1 && d == 1) return true; if (d == 1 && e == 1) return true; if (e == 1 && f == 1) return true; if (f == 1 && g == 1) return true; if (g == 1 && h == 1) return true; if (h == 1 && a == 1) return true; } return false; } /// /// 移除临近点 /// /// /// public static void DeleteNearPoint(List points, OpenCvSharp.Point startP) { points.Remove(startP); OpenCvSharp.Point seed = startP; int num; do { num = 0; int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0; OpenCvSharp.Point a1 = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point b1 = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point c1 = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point d1 = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point e1 = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point f1 = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point g1 = new OpenCvSharp.Point(0, 0); OpenCvSharp.Point h1 = new OpenCvSharp.Point(0, 0); List nears = new List(); OpenCvSharp.Point zuo = new OpenCvSharp.Point(seed.X - 1, seed.Y); if (points.IndexOf(zuo) >= 0) { a = 1; num++; a1 = zuo; nears.Add(zuo); } OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(seed.X - 1, seed.Y - 1); if (points.IndexOf(zuo_shang) >= 0) { b = 1; num++; b1 = zuo_shang; nears.Add(zuo_shang); } OpenCvSharp.Point shang = new OpenCvSharp.Point(seed.X, seed.Y - 1); if (points.IndexOf(shang) >= 0) { c = 1; num++; c1 = shang; nears.Add(shang); } OpenCvSharp.Point you_shang = new OpenCvSharp.Point(seed.X + 1, seed.Y - 1); if (points.IndexOf(you_shang) >= 0) { d = 1; num++; d1 = you_shang; nears.Add(you_shang); } OpenCvSharp.Point you = new OpenCvSharp.Point(seed.X + 1, seed.Y); if (points.IndexOf(you) >= 0) { e = 1; num++; e1 = you; nears.Add(you); } OpenCvSharp.Point you_xia = new OpenCvSharp.Point(seed.X + 1, seed.Y + 1); if (points.IndexOf(you_xia) >= 0) { f = 1; num++; f1 = you_xia; nears.Add(you_xia); } OpenCvSharp.Point xia = new OpenCvSharp.Point(seed.X, seed.Y + 1); if (points.IndexOf(xia) >= 0) { g = 1; num++; g1 = xia; nears.Add(xia); } OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(seed.X - 1, seed.Y + 1); if (points.IndexOf(zuo_xia) >= 0) { h = 1; num++; h1 = zuo_xia; nears.Add(zuo_xia); } if (num == 1) { if (a == 1) seed = a1; if (b == 1) seed = b1; if (c == 1) seed = c1; if (d == 1) seed = d1; if (e == 1) seed = e1; if (f == 1) seed = f1; if (g == 1) seed = g1; if (h == 1) seed = h1; points.Remove(nears[0]); } else if (num == 2) { if ((a == 1 && b == 1) || (b == 1 && c == 1) || (c == 1 && d == 1) || (d == 1 && e == 1) || (e == 1 && f == 1) || (f == 1 && g == 1) || (g == 1 && h == 1) || (h == 1 && a == 1)) { if (a == 1 && b == 1) { if (!FindEndpoints(points, a1)) seed = a1; if (!FindEndpoints(points, b1)) seed = b1; } if (b == 1 && c == 1) { if (!FindEndpoints(points, c1)) seed = c1; if (!FindEndpoints(points, b1)) seed = b1; } if (c == 1 && d == 1) { if (!FindEndpoints(points, c1)) seed = c1; if (!FindEndpoints(points, d1)) seed = d1; } if (d == 1 && e == 1) { if (!FindEndpoints(points, e1)) seed = e1; if (!FindEndpoints(points, d1)) seed = d1; } if (e == 1 && f == 1) { if (!FindEndpoints(points, e1)) seed = e1; if (!FindEndpoints(points, f1)) seed = f1; } if (f == 1 && g == 1) { if (!FindEndpoints(points, g1)) seed = g1; if (!FindEndpoints(points, f1)) seed = f1; } if (g == 1 && h == 1) { if (!FindEndpoints(points, g1)) seed = g1; if (!FindEndpoints(points, h1)) seed = h1; } if (h == 1 && a == 1) { if (!FindEndpoints(points, a1)) seed = a1; if (!FindEndpoints(points, h1)) seed = h1; } points.Remove(nears[0]); points.Remove(nears[1]); num = 1; } } } while (num == 1); } public static Mat MergeMatFromMatArr(Mat[] arr) { Mat[] mats = new Mat[3]; mats[0] = arr[0]; mats[1] = arr[1]; mats[2] = arr[2]; Mat dst = new Mat(); Cv2.Merge(mats, dst); return dst; } /// /// 形态学孔洞填充 /// /// 二值图0/255 /// public static Mat FillHole(Mat srcBw, Scalar scalar) { OpenCvSharp.Size m_Size = srcBw.Size(); //创建扩展边界的图像 Mat temp = Mat.Zeros(m_Size.Height + 2, m_Size.Width + 2, srcBw.Type()); srcBw.CopyTo(new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1))); //new OpenCvSharp.Point(0, 0) Cv2.FloodFill(temp, new OpenCvSharp.Point(0, 0), scalar); //裁剪扩展边界的图像 Mat cutImg = new Mat(); new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1)).CopyTo(cutImg); return srcBw | (~cutImg); } public static int GetRandomNumber(int[] a) { Random rnd = new Random(); int index = rnd.Next(a.Length); return a[index]; } /// /// 寻找under cut /// /// /// /// public static OpenCvSharp.Point GetLeftPoint(OpenCvSharp.Point temp, Mat mat) { Rect rect = new Rect(); Mat mask = Mat.Zeros(mat.Rows + 2, mat.Cols + 2, MatType.CV_8UC1); Cv2.FloodFill(mat, mask, temp, new Scalar(255), out rect, null, null, FloodFillFlags.Link8); mask = mask * 255; List points = new List(); for (int h=1; h< mask.Height-1; h++) { for (int w = temp.X-150; w < temp.X; w++) { byte v = mask.At(h, w); if(v == 255) { //if(Cv2.FloodFill(mask, new OpenCvSharp.Point(w, h), new Scalar(255)) > 30) points.Add(new OpenCvSharp.Point(w, h)); } } } List points1 = points.FindAll(a => a.X < temp.X); if(points1.Count ==0) { return new OpenCvSharp.Point(0, 0); } int maxY = points1.Max(b => b.Y); List points2 = points.FindAll(a => a.Y > maxY - 20); return points2.Find(a => a.X == points2.Min(b => b.X)); //return points1.Find(a => a.Y == points1.Max(b => b.Y)); } /// /// 找轮廓的最左、最右点 /// /// /// /// 1左 2右 /// public static OpenCvSharp.Point GetLeftOrRightPoint(OpenCvSharp.Point temp, Mat mat, int type) { Rect rect = new Rect(); Mat mask = Mat.Zeros(mat.Rows + 2, mat.Cols + 2, MatType.CV_8UC1); Cv2.FloodFill(mat, mask, temp, new Scalar(255), out rect, null, null, FloodFillFlags.Link8); mask = mask * 255; List points = new List(); if(type==2) { for (int h = 1; h < temp.Y-15/*mask.Height - 1*/; h++) { for (int w = temp.X; w < temp.X + 10/*0*/; w++) { byte v = mask.At(h, w); if (v == 255) { points.Add(new OpenCvSharp.Point(w, h)); } } } } else { for (int h = temp.Y - 45; h < temp.Y-15/*mask.Height - 1*/; h++) { for (int w = temp.X - 200; w < temp.X + 200; w++) { byte v = mask.At(h, w); if (v == 255) { points.Add(new OpenCvSharp.Point(w, h)); } } } } if (points.Count == 0) return temp; if (type == 1) { return points.Find(a => a.X == points.Min(b => b.X)); } else { return points.Find(a => a.X == points.Max(b => b.X)); } } public static int GetContoursHeight(OpenCvSharp.Point[] points, out OpenCvSharp.Point topPoint) { List list = points.ToList(); topPoint = list.Find(a => a.Y == list.Min(b => b.Y)); OpenCvSharp.Point bottom = list.Find(a => a.Y == list.Max(b => b.Y)); return bottom.Y - topPoint.Y; } static Mat calMats, phaseTempMin, phaseTempMax, phaseTemp1; static int dstChannel; static int dstWidth; static int localThreshold; /// /// 边缘增强 /// /// /// /// /// public unsafe static Mat adaptEdgeEnhancement(Mat mat, int kernel, int threshold) { Mat f = null; try { localThreshold = threshold; dstWidth = mat.Width; dstChannel = mat.Channels(); phaseTemp1 = mat.Clone().CvtColor(ColorConversionCodes.GRAY2BGR); calMats = mat.Clone(); //求最大值最小值 Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(kernel, kernel)); //腐蚀 phaseTempMin = new Mat(); Cv2.Erode(mat, phaseTempMin, element, null, 1, BorderTypes.Constant); //膨胀 phaseTempMax = new Mat(); Cv2.Dilate(mat, phaseTempMax, element, null, 1, BorderTypes.Constant); f = new Mat(); Cv2.Subtract(phaseTempMax, phaseTempMin, f); f = f.CvtColor(ColorConversionCodes.GRAY2BGR); //实现边界增强 f.ForEachAsVec3b(ForeachFunctionVeb3ForThreshold); } catch(Exception e) { } finally { if(calMats != null && !calMats.IsDisposed) { calMats.Dispose(); calMats = null; } if (phaseTempMin != null && !phaseTempMin.IsDisposed) { phaseTempMin.Dispose(); phaseTempMin = null; } if (phaseTempMax != null && !phaseTempMax.IsDisposed) { phaseTempMax.Dispose(); phaseTempMax = null; } if (f != null && !f.IsDisposed) { f.Dispose(); f = null; } } return phaseTemp1.CvtColor(ColorConversionCodes.BGR2GRAY); } private unsafe static void ForeachFunctionVeb3ForThreshold(Vec3b* value, int* position) { ////对每个像素点的操作 byte* pixels3 = (byte*)phaseTempMax.Data; byte* pixels4 = (byte*)phaseTempMin.Data; byte* pixels5 = (byte*)calMats.Data; int offset = (position[0] * dstWidth + position[1]) * dstChannel; Vec3b aa = new Vec3b(pixels5[offset], pixels5[offset + 1], pixels5[offset + 2]); bool toedit = false; if (value->Item0 > localThreshold) { toedit = true; byte ff = pixels3[offset]; byte pp = pixels4[offset]; if ((ff + pp) / 2 < aa.Item0) aa.Item0 = ff; else aa.Item0 = pp; } if (value->Item1 > localThreshold) { toedit = true; byte ff = pixels3[offset + 1]; byte pp = pixels4[offset + 1]; if ((ff + pp) / 2 < aa.Item1) aa.Item1 = ff; else aa.Item1 = pp; } if (value->Item2 > localThreshold) { toedit = true; byte ff = pixels3[offset + 2]; byte pp = pixels4[offset + 2]; if ((ff + pp) / 2 < aa.Item2) aa.Item2 = ff; else aa.Item2 = pp; } if (toedit) { phaseTemp1.Set(position[0], position[1], aa); } } public static List CalcRepeatLines(List line, Mat mat) { int value = 0; List temp = new List(); //if (line.Count> 2 && mat.Row[line[line.Count - 1] + 9].CountNonZero() <= 300) // line.RemoveAt(line.Count - 1); for (int i=line.Count-1; i>=0; i--) { if(Math.Abs(line[i]-value)>=20) { value = line[i]; temp.Add(line[i]); } } return temp; } public static Mat ImageSobel(Mat src) { Mat gray = null, xgrad = null, ygrad = null, output = null; try { //转为灰度 gray = src.Clone(); //Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY); MatType m = src.Type(); //求 X 和 Y 方向的梯度 Sobel and scharr xgrad = new Mat(); ygrad = new Mat(); Cv2.Sobel(gray, xgrad, MatType.CV_16S, 1, 0, 3); Cv2.Sobel(gray, ygrad, MatType.CV_16S, 0, 1, 3); Cv2.ConvertScaleAbs(xgrad, xgrad);//缩放、计算绝对值并将结果转换为8位。不做转换的化显示不了,显示图相只能是8U类型 Cv2.ConvertScaleAbs(ygrad, ygrad); //加强边缘检测 //Cv2.Scharr(gray, xgrad, -1, 1, 0, 3); //Cv2.Scharr(gray, ygrad, -1, 0, 1, 3); output = new Mat(xgrad.Size(), xgrad.Type()); //图像混合相加(基于权重 0.5)不精确 //Cv2.AddWeighted(xgrad, 0.5, ygrad, 0.5, 0, output); //基于 算法 G=|Gx|+|Gy| int width = xgrad.Cols; int hight = xgrad.Rows; //基于 G= (Gx*Gx +Gy*Gy)的开方根 for (int x = 0; x < hight; x++) { for (int y = 0; y < width; y++) { int xg = xgrad.At(x, y); int yg = ygrad.At(x, y); double v1 = Math.Pow(xg, 2); double v2 = Math.Pow(yg, 2); int val = (int)Math.Sqrt(v1 + v2); if (val > 255) //确保像素值在 0 -- 255 之间 { val = 255; } if (val < 0) { val = 0; } byte xy = (byte)val; output.Set(x, y, xy); } } output.CopyTo(src); return src; } catch (Exception ex) { throw ex; } finally { if (gray != null) gray.Dispose(); if (xgrad != null) gray.Dispose(); if (ygrad != null) gray.Dispose(); if (output != null) gray.Dispose(); GC.Collect(); } } } }