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();
}
}
}
}