Tools.cs 117 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068
  1. using OpenCvSharp;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace SmartCoalApplication.Base.CommTool
  9. {
  10. public class Tools
  11. {
  12. /// <summary>
  13. /// 阴影校正
  14. /// </summary>
  15. /// <param name="src"></param>
  16. /// <returns></returns>
  17. public static Mat ShadingCorrection(Mat src)
  18. {
  19. if (src.Channels() == 1)
  20. return src;
  21. Mat temp = null, Ag = null, A0 = null, Aglp = null, dst = null;
  22. try
  23. {
  24. src.ConvertTo(src, MatType.CV_32FC3);
  25. temp = src.CvtColor(ColorConversionCodes.BGR2YCrCb);
  26. Mat[] tempArr = temp.Split();
  27. Ag = new Mat();
  28. tempArr[0].CopyTo(Ag); ;
  29. A0 = new Mat();
  30. Ag.CopyTo(A0);
  31. Aglp = ImageSmoothIIR(Ag, 0.99);
  32. tempArr[0] = A0 - Aglp + Cv2.Mean(Aglp);
  33. dst = new Mat();
  34. Cv2.Merge(tempArr, dst);
  35. dst = dst.CvtColor(ColorConversionCodes.YCrCb2BGR);
  36. dst.ConvertTo(dst, MatType.CV_8UC3);
  37. dst.CopyTo(src);
  38. return src;
  39. }
  40. catch (Exception e)
  41. {
  42. throw e;
  43. }
  44. finally
  45. {
  46. if (temp != null) temp.Dispose();
  47. if (Ag != null) Ag.Dispose();
  48. if (A0 != null) A0.Dispose();
  49. if (Aglp != null) Aglp.Dispose();
  50. if (dst != null) dst.Dispose();
  51. GC.Collect();
  52. }
  53. }
  54. public static Mat ImageSmoothIIR(Mat I_OUT, double threshold)
  55. {
  56. int M = I_OUT.Height;
  57. int N = I_OUT.Width;
  58. for (int P = 1; P < M; P++)
  59. {
  60. I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P - 1] - I_OUT.Row[P]) + I_OUT.Row[P];
  61. }
  62. for (int P = M - 2; P > -1; P--)
  63. {
  64. I_OUT.Row[P] = threshold * 1.0f * (I_OUT.Row[P + 1] - I_OUT.Row[P]) + I_OUT.Row[P];
  65. }
  66. for (int L = 1; L < N; L++)
  67. {
  68. I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L - 1] - I_OUT.Col[L]) + I_OUT.Col[L];
  69. }
  70. for (int L = N - 2; L > -1; L--)
  71. {
  72. I_OUT.Col[L] = threshold * 1.0f * (I_OUT.Col[L + 1] - I_OUT.Col[L]) + I_OUT.Col[L];
  73. }
  74. return I_OUT;
  75. }
  76. #region 分水岭分割
  77. /** the following constants are used to set bits corresponding to pixel types */
  78. static byte MAXIMUM = (byte)1; // marks local maxima (irrespective of noise tolerance)
  79. static byte LISTED = (byte)2; // marks points currently in the list
  80. static byte PROCESSED = (byte)4; // marks points processed previously
  81. static byte MAX_AREA = (byte)8; // marks areas near a maximum, within the tolerance
  82. //static byte EQUAL = (byte)16; // marks contigous maximum points of equal level
  83. //static byte MAX_POINT = (byte)32; // marks a single point standing for a maximum
  84. static byte ELIMINATED = (byte)64; // marks maxima that have been eliminated before watershed
  85. /// <summary>
  86. /// 分水岭分割
  87. /// </summary>
  88. /// <param name="mat"></param>
  89. /// <param name="lists"></param>
  90. /// <returns></returns>
  91. public static Mat WatershedSegment(Mat Inmat, int a)
  92. {
  93. int width = Inmat.Width;
  94. int height = Inmat.Height;
  95. Mat distance_temp = new Mat();
  96. //Cv2.ImShow("Inmat", Inmat);
  97. Cv2.DistanceTransform(Inmat, distance_temp, DistanceTypes.L2, DistanceMaskSize.Precise);
  98. //Mat dst_temp = new Mat();
  99. //Cv2.Normalize(src_temp, dst_temp, 0, 255, NormTypes.MinMax);
  100. //Mat dst = new Mat();
  101. //dst_temp.ConvertTo(dst, MatType.CV_8UC1);
  102. //Cv2.ImShow("DistanceTransform", dst);
  103. //getSortedMaxPoints............
  104. BitMap2d ip = new BitMap2d(distance_temp);
  105. MaximunFinder maximunFinder = new MaximunFinder(ip);
  106. List<Int16DoubleWithValue> maxPoints = maximunFinder.FindMaxima();
  107. //AnalyzeAndMarkMaxima.............
  108. BitMap2d types = new BitMap2d(width, height, 0);
  109. float globalMin = float.MaxValue;
  110. float globalMax = float.MinValue;
  111. foreach (Int16DoubleWithValue item in maxPoints)
  112. {
  113. if (item.V < globalMin) globalMin = item.V;
  114. if (item.V > globalMax) globalMax = item.V;
  115. types.SetPixel(item.O, MAXIMUM);
  116. }
  117. int nMax = maxPoints.Count();
  118. int[] pList = new int[width * height]; //here we enter points starting from a maximum
  119. int[] dirOffset = new int[] { -width, -width + 1, +1, +width + 1, +width, +width - 1, -1, -width - 1 };
  120. float maxSortingError = (float)(1.1 * (Math.Sqrt(2) / 2));//sorted sequence may be inaccurate by this value
  121. float tolerance = (float)0.5;// 05;
  122. for (int iMax = nMax - 1; iMax >= 0; iMax--)
  123. { //process all maxima now, starting from the highest
  124. int offset0 = maxPoints[iMax].O;
  125. if (((byte)types.GetPixel(offset0) & PROCESSED) != 0) //this maximum has been reached from another one, skip it
  126. continue;
  127. float v0 = ip.GetPixel(offset0);
  128. Boolean sortingError = false;
  129. do
  130. {
  131. pList[0] = offset0;
  132. types.SetPixel(offset0, (byte)((byte)types.GetPixel(offset0) | LISTED)); //mark first point as equal height (to itself) and listed
  133. int listLen = 1; //number of elements in the list
  134. int listI = 0; //index of current element in the list
  135. sortingError = false;
  136. Boolean maxPossible = true; //it may be a true maximum
  137. do
  138. { //while neigbor list is not fully processed (to listLen)
  139. int offset = pList[listI];
  140. int x = offset % width;
  141. int y = offset / width;
  142. Boolean isInner = (y != 0 && y != height - 1) && (x != 0 && x != width - 1); //not necessary, but faster than isWithin
  143. for (int d = 0; d < 8; d++)
  144. { //analyze all neighbors (in 8 directions) at the same level
  145. int offset2 = offset + dirOffset[d];
  146. if ((isInner || isWithin(x, y, d, width, height)) && ((byte)types.GetPixel(offset2) & LISTED) == 0)
  147. {
  148. float v2 = ip.GetPixel(offset2);
  149. if (ip.GetPixel(offset2) <= 0)
  150. {
  151. continue; //ignore the background (non-particles)
  152. }
  153. if (((byte)types.GetPixel(offset2) & PROCESSED) != 0)
  154. {
  155. maxPossible = false; //we have reached a point processed previously, thus it is no maximum now
  156. break;
  157. }
  158. if (v2 > v0 + maxSortingError)
  159. {
  160. maxPossible = false; //we have reached a higher point, thus it is no maximum
  161. break;
  162. }
  163. else if (v2 >= v0 - tolerance)
  164. {
  165. if (v2 > v0)
  166. {
  167. sortingError = true;
  168. offset0 = offset2;
  169. v0 = v2;
  170. }
  171. pList[listLen] = offset2;
  172. listLen++; //we have found a new point within the tolerance
  173. types.SetPixel(offset2, (byte)((byte)types.GetPixel(offset2) | LISTED));
  174. }
  175. } // if isWithin & not LISTED
  176. } // for directions d
  177. listI++;
  178. } while (listI < listLen);
  179. if (sortingError)
  180. { //if x0,y0 was not the true maximum but we have reached a higher one
  181. for (listI = 0; listI < listLen; listI++)
  182. types.SetPixel(pList[listI], (byte)0); //reset all points encountered, then retry
  183. }
  184. else
  185. {
  186. //...............................................................................//
  187. int resetMask = ~LISTED;
  188. for (listI = 0; listI < listLen; listI++)
  189. {
  190. int offset = pList[listI];
  191. types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) & resetMask)); //reset attributes no longer needed
  192. types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | PROCESSED)); //mark as processed
  193. if (maxPossible)
  194. {
  195. types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | MAX_AREA)); //reset attributes no longer needed
  196. }
  197. } // for listI
  198. }
  199. }
  200. while (sortingError);
  201. }// for all maxima iMax
  202. //if (nMax == 0) //no initial maxima at all? then consider all as 'within tolerance'
  203. // Arrays.fill(types, (byte)(PROCESSED | MAX_AREA));
  204. //makeUEPs:::
  205. double threshold = 0.5;
  206. //make8bit............
  207. double offset01 = globalMin - (globalMax - globalMin) * (1.0 / 253 / 2 - 1e-6); //everything above minValue should become >(byte)0
  208. double factor = 253 / (globalMax - globalMin);
  209. BitMap2d pixels = new BitMap2d(width, height, 0);
  210. int dataLen = height * width;
  211. for (int offset = 0; offset < dataLen; offset++)
  212. {
  213. float rawValue = ip.GetPixel(offset);
  214. if (rawValue < threshold) { }
  215. else if (((byte)types.GetPixel(offset) & MAX_AREA) != 0)
  216. pixels.SetPixel(offset, (byte)255); //prepare watershed by setting "true" maxima+surroundings to 255
  217. else
  218. {
  219. long v = (long)(1 + Math.Round((rawValue - offset01) * factor));
  220. if (v < 1) pixels.SetPixel(offset, (byte)1);
  221. else if (v <= 254) pixels.SetPixel(offset, (byte)(v & 255));
  222. else pixels.SetPixel(offset, (byte)254);
  223. }
  224. }
  225. //cleanupMaxima............
  226. for (int iMax = nMax - 1; iMax >= 0; iMax--)
  227. {
  228. int offset0 = maxPoints[iMax].O; //type cast gets lower 32 bits where pixel offset is encoded
  229. if (((int)types.GetPixel(offset0) & (MAX_AREA | ELIMINATED)) != 0) continue;
  230. int level = (byte)pixels.GetPixel(offset0) & 255;
  231. int loLevel = level + 1;
  232. pList[0] = offset0; //we start the list at the current maximum
  233. types.SetPixel(offset0, (byte)((byte)types.GetPixel(offset0) | LISTED)); //mark first point as listed
  234. int listLen = 1; //number of elements in the list
  235. int lastLen = 1;
  236. int listI = 0; //index of current element in the list
  237. Boolean saddleFound = false;
  238. while (!saddleFound && loLevel > 0)
  239. {
  240. loLevel--;
  241. lastLen = listLen; //remember end of list for previous level
  242. listI = 0; //in each level, start analyzing the neighbors of all pixels
  243. do
  244. { //for all pixels listed so far
  245. int offset = pList[listI];
  246. int x = offset % width;
  247. int y = offset / width;
  248. Boolean isInner = (y != 0 && y != height - 1) && (x != 0 && x != width - 1); //not necessary, but faster than isWithin
  249. for (int d = 0; d < 8; d++)
  250. { //analyze all neighbors (in 8 directions) at the same level
  251. int offset2 = offset + dirOffset[d];
  252. if ((isInner || isWithin(x, y, d, width, height)) && ((byte)types.GetPixel(offset2) & LISTED) == 0)
  253. {
  254. if (((byte)types.GetPixel(offset2) & MAX_AREA) != 0 || ((((byte)types.GetPixel(offset2) & ELIMINATED) != 0) && ((byte)pixels.GetPixel(offset2) & 255) >= loLevel))
  255. {
  256. saddleFound = true; //we have reached a point touching a "true" maximum...
  257. break; //...or a level not lower, but touching a "true" maximum
  258. }
  259. else if (((byte)pixels.GetPixel(offset2) & 255) >= loLevel && ((byte)types.GetPixel(offset2) & ELIMINATED) == 0)
  260. {
  261. pList[listLen] = offset2;
  262. listLen++; //we have found a new point to be processed
  263. types.SetPixel(offset2, (byte)((byte)types.GetPixel(offset2) | LISTED));
  264. }
  265. } // if isWithin & not LISTED
  266. } // for directions d
  267. if (saddleFound) break; //no reason to search any further
  268. listI++;
  269. } while (listI < listLen);
  270. } // while !levelFound && loLevel>=0
  271. for (listI = 0; listI < listLen; listI++) //reset attribute since we may come to this place again
  272. types.SetPixel(pList[listI], (byte)((byte)types.GetPixel(pList[listI]) & ~LISTED));
  273. for (listI = 0; listI < lastLen; listI++)
  274. { //for all points higher than the level of the saddle point
  275. int offset = pList[listI];
  276. pixels.SetPixel(offset, (byte)loLevel); //set pixel value to the level of the saddle point
  277. types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | ELIMINATED)); //mark as processed: there can't be a local maximum in this area
  278. }
  279. } // for all maxima iMax
  280. //watershedSegment
  281. int[] histogram = new int[256];
  282. for (int v1 = 0; v1 < 255; v1++)
  283. {
  284. histogram[v1] = 0;
  285. }
  286. for (int offset = 0; offset < dataLen; offset++)
  287. {
  288. int v1 = (byte)pixels.GetPixel(offset) & 255;
  289. if (v1 > 0 && v1 < 255)
  290. {
  291. histogram[v1]++;
  292. }
  293. }
  294. int arraySize = width * height - histogram[0] - histogram[255];
  295. int[] coordinates = new int[arraySize]; //from pixel coordinates, low bits x, high bits y
  296. int highestValue = 0;
  297. int maxBinSize = 0;
  298. int offset02 = 0;
  299. int[] levelStart = new int[256];
  300. for (int v1 = 1; v1 < 255; v1++)
  301. {
  302. levelStart[v1] = offset02;
  303. offset02 += histogram[v1];
  304. if (histogram[v1] > 0) highestValue = v1;
  305. if (histogram[v1] > maxBinSize) maxBinSize = histogram[v1];
  306. }
  307. int[] levelOffset = new int[highestValue + 1];
  308. for (int y = 0, i = 0; y < height; y++)
  309. {
  310. for (int x = 0; x < width; x++, i++)
  311. {
  312. int v1 = (byte)pixels.GetPixel(i) & 255;
  313. if (v1 > 0 && v1 < 255)
  314. {
  315. offset02 = levelStart[v1] + levelOffset[v1];
  316. coordinates[offset02] = x + y * width;
  317. levelOffset[v1]++;
  318. }
  319. } //for x
  320. } //for y
  321. // Create an array of the points (pixel offsets) that we set to 255 in one pass.
  322. // If we remember this list we need not create a snapshot of the ImageProcessor.
  323. int[] setPointList = new int[Math.Min(maxBinSize, (width * height + 2) / 3)];
  324. // now do the segmentation, starting at the highest level and working down.
  325. // At each level, dilate the particle (set pixels to 255), constrained to pixels
  326. // whose values are at that level and also constrained (by the fateTable)
  327. // to prevent features from merging.
  328. int[] table = makeFateTable();
  329. //IJ.showStatus("Segmenting (Esc to cancel)");
  330. /*final */
  331. int[] directionSequence = new int[] { 7, 3, 1, 5, 0, 4, 2, 6 }; // diagonal directions first
  332. for (int level = highestValue; level >= 1; level--)
  333. {
  334. int remaining = histogram[level]; //number of points in the level that have not been processed
  335. int idle = 0;
  336. while (remaining > 0 && idle < 8)
  337. {
  338. int sumN = 0;
  339. int dIndex = 0;
  340. do
  341. { // expand each level in 8 directions
  342. int n = processLevel(directionSequence[dIndex % 8], pixels, table,
  343. levelStart[level], remaining, coordinates, setPointList, width, height);
  344. //IJ.log("level="+level+" direction="+directionSequence[dIndex%8]+" remain="+remaining+"-"+n);
  345. remaining -= n; // number of points processed
  346. sumN += n;
  347. if (n > 0) idle = 0; // nothing processed in this direction?
  348. dIndex++;
  349. } while (remaining > 0 && idle++ < 8);
  350. }
  351. if (remaining > 0 && level > 1)
  352. { // any pixels that we have not reached?
  353. int nextLevel = level; // find the next level to process
  354. do
  355. nextLevel--;
  356. while (nextLevel > 1 && histogram[nextLevel] == 0);
  357. // in principle we should add all unprocessed pixels of this level to the
  358. // tasklist of the next level. This would make it very slow for some images,
  359. // however. Thus we only add the pixels if they are at the border (of the
  360. // image or a thresholded area) and correct unprocessed pixels at the very
  361. // end by CleanupExtraLines
  362. if (nextLevel > 0)
  363. {
  364. int newNextLevelEnd = levelStart[nextLevel] + histogram[nextLevel];
  365. for (int i = 0, p = levelStart[level]; i < remaining; i++, p++)
  366. {
  367. int pOffset = coordinates[p];
  368. int x = pOffset % width;
  369. int y = pOffset / width;
  370. //if ((pixels[pOffset] & 255) == 255) IJ.log("ERROR");
  371. Boolean addToNext = false;
  372. if (x == 0 || y == 0 || x == width - 1 || y == height - 1)
  373. addToNext = true; //image border
  374. else for (int d = 0; d < 8; d++)
  375. if (isWithin(x, y, d, width, height) && pixels.GetPixel(pOffset + dirOffset[d]) == 0)
  376. {
  377. addToNext = true; //border of area below threshold
  378. break;
  379. }
  380. if (addToNext)
  381. coordinates[newNextLevelEnd++] = pOffset;
  382. }
  383. //tasklist for the next level to process becomes longer by this:
  384. histogram[nextLevel] = newNextLevelEnd - levelStart[nextLevel];
  385. }
  386. }
  387. }
  388. System.Drawing.Color color = Color.Blue;
  389. Mat matPixels = OpenCvSharp.Extensions.BitmapConverter.ToMat(pixels.MakeBmp());
  390. for (int h = 0; h < matPixels.Height; h++)
  391. {
  392. for (int w = 0; w < matPixels.Width; w++)
  393. {
  394. if (matPixels.At<byte>(h, w) == 0)
  395. matPixels.Set<Vec4b>(h, w, new Vec4b(color.B, color.G, color.R, 255));
  396. else
  397. matPixels.Set<Vec4b>(h, w, new Vec4b(0, 0, 0, 0));
  398. }
  399. }
  400. return matPixels;
  401. }
  402. /** returns whether the neighbor in a given direction is within the image
  403. * NOTE: it is assumed that the pixel x,y itself is within the image!
  404. * Uses class variables width, height: dimensions of the image
  405. * @param x x-coordinate of the pixel that has a neighbor in the given direction
  406. * @param y y-coordinate of the pixel that has a neighbor in the given direction
  407. * @param direction the direction from the pixel towards the neighbor (see makeDirectionOffsets)
  408. * @return true if the neighbor is within the image (provided that x, y is within)
  409. */
  410. public static Boolean isWithin(int x, int y, int direction, int width, int height)
  411. {
  412. int xmax = width - 1;
  413. int ymax = height - 1;
  414. switch (direction)
  415. {
  416. case 0:
  417. return (y > 0);
  418. case 1:
  419. return (x < xmax && y > 0);
  420. case 2:
  421. return (x < xmax);
  422. case 3:
  423. return (x < xmax && y < ymax);
  424. case 4:
  425. return (y < ymax);
  426. case 5:
  427. return (x > 0 && y < ymax);
  428. case 6:
  429. return (x > 0);
  430. case 7:
  431. return (x > 0 && y > 0);
  432. }
  433. return false; //to make the compiler happy :-)
  434. } // isWithin
  435. /** dilate the UEP on one level by one pixel in the direction specified by step, i.e., set pixels to 255
  436. * @param pass gives direction of dilation, see makeFateTable
  437. * @param ip the EDM with the segmeted blobs successively getting set to 255
  438. * @param table The fateTable
  439. * @param levelStart offsets of the level in pixelPointers[]
  440. * @param levelNPoints number of points in the current level
  441. * @param pixelPointers[] list of pixel coordinates (x+y*width) sorted by level (in sequence of y, x within each level)
  442. * @param xCoordinates list of x Coorinates for the current level only (no offset levelStart)
  443. * @return number of pixels that have been changed
  444. */
  445. public static int processLevel(int pass, BitMap2d pixels, int[] fateTable,
  446. int levelStart, int levelNPoints, int[] coordinates, int[] setPointList, int width, int height)
  447. {
  448. int xmax = width - 1;
  449. int ymax = height - 1;
  450. //byte[] pixels = (byte[])ip.getPixels();
  451. ////byte[] pixels2 = (byte[])ip2.getPixels();
  452. int nChanged = 0;
  453. int nUnchanged = 0;
  454. for (int i = 0, p = levelStart; i < levelNPoints; i++, p++)
  455. {
  456. int offset = coordinates[p];
  457. int x = offset % width;
  458. int y = offset / width;
  459. int index = 0; //neighborhood pixel ocupation: index in fateTable
  460. if (y > 0 && ((byte)pixels.GetPixel(offset - width) & 255) == 255)
  461. index ^= 1;
  462. if (x < xmax && y > 0 && ((byte)pixels.GetPixel(offset - width + 1) & 255) == 255)
  463. index ^= 2;
  464. if (x < xmax && ((byte)pixels.GetPixel(offset + 1) & 255) == 255)
  465. index ^= 4;
  466. if (x < xmax && y < ymax && ((byte)pixels.GetPixel(offset + width + 1) & 255) == 255)
  467. index ^= 8;
  468. if (y < ymax && ((byte)pixels.GetPixel(offset + width) & 255) == 255)
  469. index ^= 16;
  470. if (x > 0 && y < ymax && ((byte)pixels.GetPixel(offset + width - 1) & 255) == 255)
  471. index ^= 32;
  472. if (x > 0 && ((byte)pixels.GetPixel(offset - 1) & 255) == 255)
  473. index ^= 64;
  474. if (x > 0 && y > 0 && ((byte)pixels.GetPixel(offset - width - 1) & 255) == 255)
  475. index ^= 128;
  476. int mask = 1 << pass;
  477. if ((fateTable[index] & mask) == mask)
  478. setPointList[nChanged++] = offset; //remember to set pixel to 255
  479. else
  480. coordinates[levelStart + (nUnchanged++)] = offset; //keep this pixel for future passes
  481. } // for pixel i
  482. //IJ.log("pass="+pass+", changed="+nChanged+" unchanged="+nUnchanged);
  483. for (int i = 0; i < nChanged; i++)
  484. pixels.SetPixel(setPointList[i], (byte)255);
  485. return nChanged;
  486. } //processLevel
  487. static public int[] makeFateTable()
  488. {
  489. int[] table = new int[256];
  490. Boolean[] isSet = new Boolean[8];
  491. for (int item = 0; item < 256; item++)
  492. { //dissect into pixels
  493. for (int i = 0, mask = 1; i < 8; i++)
  494. {
  495. isSet[i] = (item & mask) == mask;
  496. mask *= 2;
  497. }
  498. for (int i = 0, mask = 1; i < 8; i++)
  499. { //we dilate in the direction opposite to the direction of the existing neighbors
  500. if (isSet[(i + 4) % 8]) table[item] |= mask;
  501. mask *= 2;
  502. }
  503. 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
  504. if (isSet[i])
  505. {
  506. isSet[(i + 1) % 8] = true;
  507. isSet[(i + 7) % 8] = true;
  508. }
  509. int transitions = 0;
  510. for (int i = 0; i < 8; i++)
  511. {
  512. if (isSet[i] != isSet[(i + 1) % 8])
  513. transitions++;
  514. }
  515. if (transitions >= 4)
  516. { //if neighbors contain more than one region, dilation ito this pixel is forbidden
  517. table[item] = 0;
  518. }
  519. else
  520. {
  521. }
  522. }
  523. return table;
  524. } // int[] makeFateTable
  525. /// <summary>
  526. /// 分水岭分割
  527. /// </summary>
  528. /// <param name="mat"></param>
  529. /// <param name="lists"></param>
  530. /// <returns></returns>
  531. public static Mat WatershedSegment(Mat Inmat)
  532. {
  533. //BGR
  534. Mat Src_3 = new Mat();// .Clone();
  535. Mat[] arr = new Mat[3];
  536. arr[0] = Inmat;
  537. arr[1] = Inmat;
  538. arr[2] = Inmat;
  539. Cv2.Merge(arr, Src_3);
  540. //二值图
  541. Mat mat_bw = GetBW(Inmat);
  542. //Cv2.ImShow("mat_bw00", mat_bw);
  543. Mat result = Oper_Deal(mat_bw, Src_3);
  544. return result;// temp;
  545. }
  546. private static Mat Oper_Deal(Mat ImIn, Mat src_3)
  547. {
  548. #region 距离变换
  549. Mat Im1 = new Mat(ImIn.Size(), ImIn.Type());
  550. //归一化
  551. Cv2.Normalize(ImIn, Im1, 0, 1, NormTypes.MinMax);
  552. Mat Im_dis = new Mat(ImIn.Size(), MatType.CV_32FC1);
  553. Cv2.DistanceTransform(ImIn, Im_dis, DistanceTypes.L2, DistanceMaskSize.Precise);
  554. Cv2.Normalize(Im_dis, Im_dis, 0, 1, NormTypes.MinMax);
  555. Mat conv = new Mat(Im_dis.Size(), MatType.CV_8UC1);
  556. Im_dis.ConvertTo(conv, MatType.CV_8UC1);
  557. Cv2.Threshold(conv, conv, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
  558. #endregion
  559. #region 轮廓标记
  560. Mat dis_8U = conv;
  561. //提取标记
  562. OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchy;
  563. Cv2.FindContours(dis_8U, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point());
  564. #endregion
  565. #region 将标记存入markers,作分水岭注水点用
  566. var markers = new Mat(ImIn.Size(), MatType.CV_32SC1, Scalar.All(0));
  567. for (int i = 0; i < contours.Length; i++)
  568. {
  569. Cv2.DrawContours(markers, contours, i, Scalar.All(i + 1), 10, LineTypes.Link8, hierarchy);
  570. }
  571. #endregion
  572. Cv2.Watershed(src_3, markers);
  573. #region 分水岭结果图处理
  574. //连通域为1,线条为0
  575. var markers_ind = markers.GetGenericIndexer<int>();
  576. for (int i = 0; i < markers.Rows; i++)
  577. {
  578. for (int j = 0; j < markers.Cols; j++)
  579. {
  580. if (markers_ind[i, j] != -1)
  581. {
  582. markers_ind[i, j] = int.MaxValue;
  583. }
  584. else if (markers_ind[i, j] == -1)
  585. {
  586. markers_ind[i, j] = 0;
  587. }
  588. }
  589. }
  590. //结合初始二值图背景为0
  591. var ImIn_ind = ImIn.GetGenericIndexer<byte>();
  592. for (int i = 0; i < markers.Rows; i++)
  593. {
  594. for (int j = 0; j < markers.Cols; j++)
  595. {
  596. if (ImIn_ind[i, j] == 0)
  597. {
  598. markers_ind[i, j] = 0;
  599. }
  600. }
  601. }
  602. #endregion
  603. #region 连通域信息
  604. Mat water = new Mat(markers.Size(), MatType.CV_8UC1);
  605. markers.ConvertTo(water, MatType.CV_8UC1);
  606. var water_ind = water.GetGenericIndexer<byte>();
  607. Mat water_bw = new Mat();
  608. Cv2.Threshold(water, water_bw, 0, 255, ThresholdTypes.Otsu);
  609. //连通图的信息获取
  610. Mat labels = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat();
  611. int num = Cv2.ConnectedComponentsWithStats(water_bw, labels, stats, centroids);
  612. #endregion
  613. #region
  614. Vec3b[] color = new Vec3b[num + 1];
  615. color[0] = new Vec3b(0, 0, 0);
  616. var stats_ind = stats.GetGenericIndexer<int>();
  617. Random rand = new Random();
  618. byte ranB = (byte)rand.Next(100, 255); byte ranG = (byte)rand.Next(100, 255); byte ranR = (byte)rand.Next(100, 255);
  619. for (int i = 1; i < num; i++)
  620. {
  621. color[i] = new Vec3b(ranB, ranG, ranR);
  622. int S = stats_ind[i, 4];
  623. if (S < 200)
  624. {
  625. color[i] = new Vec3b(0, 0, 0);
  626. }
  627. }
  628. #endregion
  629. #region mat填色
  630. Mat final = new Mat(water.Size(), MatType.CV_8UC3);
  631. for (int i = 0; i < final.Rows; i++)
  632. {
  633. for (int j = 0; j < final.Cols; j++)
  634. {
  635. int label = labels.Get<int>(i, j);
  636. final.Set<Vec3b>(i, j, color[label]);
  637. }
  638. }
  639. #endregion
  640. return final;
  641. }
  642. private static Mat GetBW(Mat Src)
  643. {
  644. //(最大类间方差)二值化
  645. //Mat result = Src.Threshold(109.242, 255, ThresholdTypes.Otsu);
  646. Mat result = Src.AdaptiveThreshold(255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 35, 5);
  647. //Cv2.ImShow("test", result); Cv2.WaitKey();
  648. return result;
  649. }
  650. public struct Int16DoubleWithValue : IComparable<Int16DoubleWithValue>
  651. {
  652. public int O;
  653. public float V;
  654. public Int16DoubleWithValue(int offset, float value)
  655. {
  656. O = offset;
  657. V = value;
  658. }
  659. public int CompareTo(Int16DoubleWithValue other)
  660. {
  661. return this.V.CompareTo(other.V);
  662. }
  663. }
  664. public class BitMap2d
  665. {
  666. public float[] data;
  667. public int width;
  668. public int height;
  669. /// <summary>
  670. /// 初始化操作对象
  671. /// </summary>
  672. /// <param name="width"></param>
  673. /// <param name="height"></param>
  674. /// <param name="v">初始值</param>
  675. public BitMap2d(int width, int height, float v)
  676. {
  677. this.width = width;
  678. this.height = height;
  679. data = new float[width * height];
  680. for (int i = 0; i < width * height; i++)
  681. data[i] = v;
  682. }
  683. /// <summary>
  684. /// 根据mat初始化
  685. /// </summary>
  686. /// <param name="mat">初始EDM对象</param>
  687. public unsafe BitMap2d(Mat mat)
  688. {
  689. this.width = mat.Width;
  690. this.height = mat.Height;
  691. data = new float[width * height];
  692. mat.ForEachAsFloat(FunctionForEachAsFloat);
  693. }
  694. private unsafe void FunctionForEachAsFloat(float* value, int* position)
  695. {
  696. data[position[0] * width + position[1]] = *value;
  697. }
  698. public void SetPixel(int x, int y, byte v)
  699. {
  700. data[x + y * width] = v;
  701. }
  702. public float GetPixel(int x, int y)
  703. {
  704. return data[x + y * width];
  705. }
  706. public void SetPixel(int offset, byte v)
  707. {
  708. data[offset] = v;
  709. }
  710. public float GetPixel(int offset)
  711. {
  712. return data[offset];
  713. }
  714. public System.Drawing.Bitmap MakeBmp()
  715. {
  716. float min = float.MaxValue;
  717. float max = float.MinValue;
  718. for (int i = 0; i < width; i++)
  719. {
  720. for (int j = 0; j < height; j++)
  721. {
  722. float r = this.GetPixel(i, j);
  723. if (r > max)
  724. max = r;
  725. if (r < min)
  726. min = r;
  727. }
  728. }
  729. float delta = max - min;
  730. System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(this.width, this.height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  731. for (int i = 0; i < width; i++)
  732. {
  733. for (int j = 0; j < height; j++)
  734. {
  735. float r = this.GetPixel(i, j);
  736. int b = 255 - (int)(255 * (r - min) / delta);
  737. System.Drawing.Color c = System.Drawing.Color.FromArgb((byte)b, (byte)b, (byte)b);
  738. bmp.SetPixel(i, j, c);
  739. }
  740. }
  741. return bmp;
  742. }
  743. }
  744. public class MaximunFinder
  745. {
  746. BitMap2d bmp;
  747. int width;
  748. int height;
  749. public MaximunFinder(BitMap2d bmp)
  750. {
  751. this.bmp = bmp;
  752. this.width = bmp.width;
  753. this.height = bmp.height;
  754. }
  755. public List<Int16DoubleWithValue> FindMaxima()
  756. {
  757. List<Int16DoubleWithValue> list = new List<Int16DoubleWithValue>();
  758. int offset = 0;
  759. for (int j = 0; j < height; j++)
  760. {
  761. for (int i = 0; i < width; i++, offset++)
  762. {
  763. if (IsMaxima(i, j, offset))
  764. {
  765. list.Add(new Int16DoubleWithValue(offset, bmp.GetPixel(offset)));
  766. }
  767. }
  768. }
  769. list.Sort();
  770. return list;
  771. }
  772. private bool IsMaxima(int i, int j, int offset)
  773. {
  774. float v = bmp.GetPixel(offset);
  775. if (v == 0) return false;
  776. bool b1 = v >= bmp.GetPixel(Math.Max(0, i - 1), Math.Max(0, j - 1));
  777. bool b2 = v >= bmp.GetPixel(i, Math.Max(0, j - 1));
  778. bool b3 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), Math.Max(0, j - 1));
  779. bool b4 = v >= bmp.GetPixel(Math.Max(0, i - 1), j);
  780. bool b5 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), j);
  781. bool b6 = v >= bmp.GetPixel(Math.Max(0, i - 1), Math.Min(height - 1, j + 1));
  782. bool b7 = v >= bmp.GetPixel(i, Math.Min(height - 1, j + 1));
  783. bool b8 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), Math.Min(height - 1, j + 1));
  784. return b1 && b2 && b3 && b4 && b5 && b6 && b7 && b8 && (v > 0);
  785. }
  786. }
  787. #endregion
  788. //颜色集合,用于聚类
  789. public static OpenCvSharp.Scalar[] colorTab = {
  790. new OpenCvSharp.Scalar(0,0,255),
  791. new OpenCvSharp.Scalar(0,255,0),
  792. new OpenCvSharp.Scalar(255,0,0),
  793. new OpenCvSharp.Scalar(0,255,255),
  794. new OpenCvSharp.Scalar(255,0,255),
  795. new OpenCvSharp.Scalar(255,255,0),
  796. new OpenCvSharp.Scalar(127,127,0),
  797. new OpenCvSharp.Scalar(0,0,127)
  798. };
  799. /// <summary>
  800. /// 直方图平滑
  801. /// </summary>
  802. /// <param name="arr"></param>
  803. /// <param name="step"></param>
  804. /// <returns></returns>
  805. public static int[] Smooth(float[] arr, int step)
  806. {
  807. int start = step - step / 2;
  808. int end = 256 - step / 2;
  809. double temp = 0;
  810. int[] res = new int[256];
  811. for (int i = start; i < end; i++)
  812. {
  813. temp = 0;
  814. for (int j = 0 - step / 2; j < step / 2; j++)
  815. {
  816. temp += arr[i + j];
  817. }
  818. temp /= step;
  819. res[i] = (int)temp;
  820. }
  821. return res;
  822. }
  823. /// <summary>
  824. /// 寻找波峰
  825. /// </summary>
  826. /// <param name="hists_new"></param>
  827. /// <param name="leftValue"></param>
  828. /// <param name="rightValue"></param>
  829. /// <param name="mountainsList"></param>
  830. /// <param name="mountainsArrList"></param>
  831. /// <param name="mountainsArrListBackUp"></param>
  832. /// <param name="str"></param>
  833. /// <param name="smoothStep"></param>
  834. public static void FindTopAndBetween(int[] hists_new, int leftValue, int rightValue, List<int> mountainsList, List<int[]> mountainsArrList, List<int[]> mountainsArrListBackUp, List<string> str, int smoothStep)
  835. {
  836. //获得去除左右值的最高波峰
  837. int topValue = leftValue;
  838. for (int y = leftValue; y < rightValue; y++)
  839. {
  840. if (hists_new[y] > hists_new[topValue])
  841. {
  842. topValue = y;
  843. }
  844. }
  845. if (topValue == 10)
  846. {
  847. FindTopAndBetween(hists_new, 11, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  848. return;
  849. }
  850. mountainsList.Add(topValue);
  851. //获得波峰左右的波谷
  852. int leftTrough = topValue;
  853. int leftTroughBackUp = 0;
  854. //从波峰点向左侧找波谷点
  855. for (int y = topValue - 1; y > leftValue; y--)
  856. {
  857. if (hists_new[y] > 0 && hists_new[y] <= hists_new[leftTrough])
  858. {
  859. leftTrough = y;
  860. }
  861. else
  862. {
  863. break;
  864. }
  865. }
  866. //微调
  867. if (smoothStep > 2)
  868. {
  869. for (int y = leftTrough + 1; y < topValue; y++)
  870. {
  871. if (hists_new[y] == hists_new[leftTrough])// || hists_new[y] < hists_new[topValue] / 10)
  872. {
  873. leftTroughBackUp = y;
  874. }
  875. }
  876. }
  877. if (leftTroughBackUp == 0) leftTroughBackUp = leftTrough;
  878. int rightTrough = topValue;
  879. int rightTroughBackUp = 0;
  880. //从波峰点向右侧找波谷点
  881. for (int y = topValue + 1; y < rightValue; y++)
  882. {
  883. if (hists_new[y] > 0 && hists_new[y] <= hists_new[rightTrough])
  884. {
  885. rightTrough = y;
  886. }
  887. else
  888. {
  889. break;
  890. }
  891. }
  892. //微调
  893. if (smoothStep > 2)
  894. {
  895. for (int y = rightTrough - 1; y > topValue; y--)
  896. {
  897. if (hists_new[y] == hists_new[rightTrough])// || hists_new[y] < hists_new[topValue] / 10)
  898. {
  899. rightTroughBackUp = y;
  900. }
  901. }
  902. }
  903. if (rightTroughBackUp == 0) rightTroughBackUp = rightTrough;
  904. int[] arr = new int[2];
  905. arr[0] = leftTroughBackUp;
  906. arr[1] = rightTroughBackUp;
  907. mountainsArrList.Add(arr);
  908. int[] arr1 = new int[2];
  909. arr1[0] = leftTroughBackUp > 0 ? leftTroughBackUp : leftTrough;
  910. arr1[1] = rightTroughBackUp > 0 ? rightTroughBackUp : rightTrough;
  911. mountainsArrListBackUp.Add(arr1);
  912. if (leftValue < leftTrough - 1)
  913. {
  914. if (!str.Contains(leftValue + "|" + leftTrough))
  915. {
  916. str.Add(leftValue + "|" + leftTrough);
  917. FindTopAndBetween(hists_new, leftValue, leftTrough, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  918. }
  919. }
  920. if (rightValue > rightTrough + 1)
  921. {
  922. if (!str.Contains(rightValue + "|" + rightTrough))
  923. {
  924. str.Add(rightValue + "|" + rightTrough);
  925. FindTopAndBetween(hists_new, rightTrough, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  926. }
  927. }
  928. }
  929. public static void FindTopAndBetweenWithOutWT(int[] hists_new, int leftValue, int rightValue, List<int> mountainsList, List<int[]> mountainsArrList, List<int[]> mountainsArrListBackUp, List<string> str, int smoothStep)
  930. {
  931. //获得去除左右值的最高波峰
  932. int topValue = leftValue;
  933. for (int y = leftValue; y < rightValue; y++)
  934. {
  935. if (hists_new[y] > hists_new[topValue])
  936. {
  937. topValue = y;
  938. }
  939. }
  940. if (topValue == 10)
  941. {
  942. FindTopAndBetween(hists_new, 11, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  943. return;
  944. }
  945. mountainsList.Add(topValue);
  946. //获得波峰左右的波谷
  947. int leftTrough = topValue;
  948. int leftTroughBackUp = 0;
  949. //从波峰点向左侧找波谷点
  950. for (int y = topValue - 1; y > leftValue; y--)
  951. {
  952. if (hists_new[y] > 0 && hists_new[y] <= hists_new[leftTrough])
  953. {
  954. leftTrough = y;
  955. }
  956. else
  957. {
  958. break;
  959. }
  960. }
  961. //微调
  962. //if (smoothStep >= 30)
  963. {
  964. for (int y = leftTrough + 1; y < topValue; y++)
  965. {
  966. if (hists_new[y] == hists_new[leftTrough] || hists_new[y] < hists_new[topValue] / 10)
  967. {
  968. leftTroughBackUp = y;
  969. }
  970. }
  971. }
  972. if (leftTroughBackUp == 0) leftTroughBackUp = leftTrough;
  973. int rightTrough = topValue;
  974. int rightTroughBackUp = 0;
  975. //从波峰点向右侧找波谷点
  976. for (int y = topValue + 1; y < rightValue; y++)
  977. {
  978. if (hists_new[y] > 0 && hists_new[y] <= hists_new[rightTrough])
  979. {
  980. rightTrough = y;
  981. }
  982. else
  983. {
  984. break;
  985. }
  986. }
  987. //微调
  988. //if (smoothStep >= 30)
  989. {
  990. for (int y = rightTrough - 1; y > topValue; y--)
  991. {
  992. if (hists_new[y] == hists_new[rightTrough] || hists_new[y] < hists_new[topValue] / 10)
  993. {
  994. rightTroughBackUp = y;
  995. }
  996. }
  997. }
  998. if (rightTroughBackUp == 0) rightTroughBackUp = rightTrough;
  999. int[] arr = new int[2];
  1000. arr[0] = leftTroughBackUp;
  1001. arr[1] = rightTroughBackUp;
  1002. mountainsArrList.Add(arr);
  1003. int[] arr1 = new int[2];
  1004. arr1[0] = leftTroughBackUp > 0 ? leftTroughBackUp : leftTrough;
  1005. arr1[1] = rightTroughBackUp > 0 ? rightTroughBackUp : rightTrough;
  1006. mountainsArrListBackUp.Add(arr1);
  1007. if (leftValue < leftTrough - 1)
  1008. {
  1009. if (!str.Contains(leftValue + "|" + leftTrough))
  1010. {
  1011. str.Add(leftValue + "|" + leftTrough);
  1012. FindTopAndBetween(hists_new, leftValue, leftTrough, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  1013. }
  1014. }
  1015. if (rightValue > rightTrough + 1)
  1016. {
  1017. if (!str.Contains(rightValue + "|" + rightTrough))
  1018. {
  1019. str.Add(rightValue + "|" + rightTrough);
  1020. FindTopAndBetween(hists_new, rightTrough, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  1021. }
  1022. }
  1023. }
  1024. public unsafe static double Entropy(Mat img)
  1025. {
  1026. // 将输入的矩阵为图像
  1027. double[] temp = new double[256];
  1028. // 清零
  1029. for (int i = 0; i < 256; i++)
  1030. {
  1031. temp[i] = 0.0;
  1032. }
  1033. // 计算每个像素的累积值
  1034. for (int m = 0; m < img.Rows; m++)
  1035. {// 有效访问行列的方式
  1036. byte* t = (byte*)img.Ptr(m);
  1037. for (int n = 0; n < img.Cols; n++)
  1038. {
  1039. int i = t[n];
  1040. temp[i] = temp[i] + 1;
  1041. }
  1042. }
  1043. // 计算每个像素的概率
  1044. for (int i = 0; i < 256; i++)
  1045. {
  1046. temp[i] = temp[i] / (img.Rows * img.Cols);
  1047. }
  1048. double result = 0;
  1049. // 根据定义计算图像熵
  1050. for (int i = 0; i < 256; i++)
  1051. {
  1052. if (temp[i] == 0.0)
  1053. result = result;
  1054. else
  1055. result = result - temp[i] * (Math.Log(temp[i]) / Math.Log(2.0));
  1056. }
  1057. return result;
  1058. }
  1059. /// <summary>
  1060. /// 计算图像的熵
  1061. /// </summary>
  1062. /// <param name="bmp"></param>
  1063. /// <param name="w"></param>
  1064. /// <param name="h"></param>
  1065. /// <returns></returns>
  1066. public static double GetEntropy(Bitmap bmp, int w, int h)
  1067. {
  1068. int g;
  1069. double H = 0.0;
  1070. int[] pix = new int[256];
  1071. Array.Clear(pix, 0, 256);
  1072. //获取各灰度值的像素个数
  1073. for (int i = 0; i < h; i++)
  1074. {
  1075. for (int j = 0; j < w; j++)
  1076. {
  1077. Color c = bmp.GetPixel(j, i);
  1078. g = (int)(0.299 * c.R + 0.587 * c.B + 0.114 * c.G);
  1079. pix[g]++;
  1080. }
  1081. }
  1082. //计算熵
  1083. for (int i = 0; i < 256; i++)
  1084. {
  1085. if (pix[i] > 0)
  1086. {
  1087. H = H + pix[i] * Math.Log10(pix[i]);
  1088. }
  1089. }
  1090. H = Math.Log10(w * h) / Math.Log10(2) - H / (w * h * Math.Log10(2));
  1091. return H;
  1092. }
  1093. /// <summary>
  1094. /// 计算占比
  1095. /// </summary>
  1096. /// <param name="max"></param>
  1097. /// <param name="hists_new"></param>
  1098. /// <param name="toplow"></param>
  1099. /// <returns></returns>
  1100. public static double GetAreaRatio(int max, int[] hists_new, int[] toplow)
  1101. {
  1102. int all = 0;
  1103. int area = 0;
  1104. for (int i = toplow[0]; i < toplow[1]; i++)
  1105. {
  1106. all += hists_new[i];
  1107. if (i <= max + 10 && i >= max - 10)
  1108. {
  1109. area += hists_new[i];
  1110. }
  1111. }
  1112. return area * 1d * 100 / all;
  1113. }
  1114. /// <summary>
  1115. /// 计算阈值
  1116. /// </summary>
  1117. /// <param name="max">最大值</param>
  1118. /// <param name="min">最小值</param>
  1119. /// <param name="t">1左 2右</param>
  1120. /// <param name="hists_new">直方图</param>
  1121. /// <returns></returns>
  1122. public static double GetTriangleThreshold(int leftv, int topv, int rightv, int t, int[] hists_new)
  1123. {
  1124. int left_bound = leftv, right_bound = rightv, max_ind = topv, max = hists_new[topv];
  1125. int temp;
  1126. bool isflipped = false;
  1127. int i = 0, j = 0;
  1128. int N = 256;
  1129. // 如果最大值落在靠左侧这样就无法满足三角法求阈值,所以要检测是否最大值是否靠近左侧
  1130. // 如果靠近左侧则通过翻转到右侧位置。
  1131. if (max_ind - left_bound < right_bound - max_ind)//max_ind - left_bound < right_bound - max_ind
  1132. {
  1133. isflipped = true;
  1134. i = 0;
  1135. j = N - 1;
  1136. while (i < j)
  1137. {
  1138. // 左右交换
  1139. temp = hists_new[i]; hists_new[i] = hists_new[j]; hists_new[j] = temp;
  1140. i++; j--;
  1141. }
  1142. left_bound = N - 1 - right_bound;
  1143. max_ind = N - 1 - max_ind;
  1144. }
  1145. // 计算求得阈值
  1146. double thresh = left_bound;
  1147. double a, b, dist = 0, tempdist;
  1148. a = max; b = left_bound - max_ind;
  1149. for (i = left_bound + 1; i <= max_ind; i++)
  1150. {
  1151. // 计算距离 - 不需要真正计算
  1152. tempdist = a * i + b * hists_new[i];
  1153. if (tempdist > dist)
  1154. {
  1155. dist = tempdist;
  1156. thresh = i;
  1157. }
  1158. }
  1159. thresh--;
  1160. if (isflipped)
  1161. thresh = N - 1 - thresh;
  1162. return thresh;
  1163. }
  1164. /// <summary>
  1165. /// 计算K类均值的每个类的灰度均值,面积
  1166. /// </summary>
  1167. public static List<float> CalaKmeanMatMeans(OpenCvSharp.Mat origin, OpenCvSharp.Mat kmean, out List<int> nums)
  1168. {
  1169. OpenCvSharp.Mat gray = origin.CvtColor(OpenCvSharp.ColorConversionCodes.BGR2GRAY);
  1170. //像素点个数
  1171. List<int> points = new List<int>();
  1172. points.Add(0);
  1173. points.Add(0);
  1174. points.Add(0);
  1175. points.Add(0);
  1176. points.Add(0);
  1177. //像素点灰度值的和
  1178. List<int> grays = new List<int>();
  1179. grays.Add(0);
  1180. grays.Add(0);
  1181. grays.Add(0);
  1182. grays.Add(0);
  1183. grays.Add(0);
  1184. new OpenCvSharp.Scalar(0, 0, 255);
  1185. new OpenCvSharp.Scalar(0, 255, 0);
  1186. new OpenCvSharp.Scalar(255, 0, 0);
  1187. new OpenCvSharp.Scalar(0, 255, 255);
  1188. new OpenCvSharp.Scalar(255, 0, 255);
  1189. for (int h = 0; h < kmean.Height; h++)
  1190. {
  1191. for (int w = 0; w < kmean.Width; w++)
  1192. {
  1193. OpenCvSharp.Vec3b vec3B = kmean.At<OpenCvSharp.Vec3b>(h, w);
  1194. if (vec3B.Item0 == 0 && vec3B.Item1 == 0 && vec3B.Item2 == 255)
  1195. {
  1196. points[0] += 1;
  1197. grays[0] += gray.At<byte>(h, w);
  1198. }
  1199. else if (vec3B.Item0 == 0 && vec3B.Item1 == 255 && vec3B.Item2 == 0)
  1200. {
  1201. points[1] += 1;
  1202. grays[1] += gray.At<byte>(h, w);
  1203. }
  1204. else if (vec3B.Item0 == 255 && vec3B.Item1 == 0 && vec3B.Item2 == 0)
  1205. {
  1206. points[2] += 1;
  1207. grays[2] += gray.At<byte>(h, w);
  1208. }
  1209. else if (vec3B.Item0 == 0 && vec3B.Item1 == 255 && vec3B.Item2 == 255)
  1210. {
  1211. points[3] += 1;
  1212. grays[3] += gray.At<byte>(h, w);
  1213. }
  1214. else if (vec3B.Item0 == 255 && vec3B.Item1 == 0 && vec3B.Item2 == 255)
  1215. {
  1216. points[4] += 1;
  1217. grays[4] += gray.At<byte>(h, w);
  1218. }
  1219. }
  1220. }
  1221. nums = points;
  1222. List<float> vs = new List<float>();
  1223. for (int i = 0; i < 5; i++)
  1224. {
  1225. vs.Add(grays[i] * 1f / points[i]);
  1226. }
  1227. return vs;
  1228. }
  1229. /// <summary>
  1230. /// 判断点a和点b是否颜色一样
  1231. /// </summary>
  1232. /// <param name="v"></param>
  1233. /// <param name="b"></param>
  1234. /// <returns></returns>
  1235. public static bool AdjustNearColor(Vec3b v, Scalar b)
  1236. {
  1237. if (v.Item0 == b.Val0 && v.Item1 == b.Val1 && v.Item2 == b.Val2)
  1238. return true;
  1239. else
  1240. return false;
  1241. }
  1242. public static bool AdjustNearBy(Vec3b v, Vec3b b)
  1243. {
  1244. if (b.Item0 == 0 && b.Item1 == 0 && b.Item2 == 0)
  1245. {
  1246. return false;
  1247. }
  1248. else
  1249. {
  1250. if (v.Item0 != b.Item0 || v.Item1 != b.Item1 || v.Item2 != b.Item2)
  1251. return true;
  1252. else
  1253. return false;
  1254. }
  1255. }
  1256. public static void FindTopAndBetweenWithOutWT123(int[] hists_new, int leftValue, int rightValue, List<int> mountainsList, List<int[]> mountainsArrList, List<int[]> mountainsArrListBackUp, List<string> str, int smoothStep)
  1257. {
  1258. //获得去除左右值的最高波峰
  1259. int topValue = leftValue;
  1260. for (int y = leftValue; y < rightValue; y++)
  1261. {
  1262. if (hists_new[y] > hists_new[topValue])
  1263. {
  1264. topValue = y;
  1265. }
  1266. }
  1267. if (topValue == 0 || topValue == leftValue || topValue == rightValue)
  1268. return;
  1269. mountainsList.Add(topValue);
  1270. //获得波峰左右的波谷
  1271. int leftTrough = topValue;
  1272. int leftTroughBackUp = 0;
  1273. //从波峰点向左侧找波谷点
  1274. for (int y = topValue - 1; y > leftValue; y--)
  1275. {
  1276. if (hists_new[y] >= 0 && hists_new[y] <= hists_new[leftTrough])
  1277. {
  1278. leftTrough = y;
  1279. }
  1280. else
  1281. {
  1282. break;
  1283. }
  1284. }
  1285. //微调
  1286. //if (smoothStep >= 30)
  1287. {
  1288. for (int y = leftTrough + 1; y < topValue; y++)
  1289. {
  1290. if (hists_new[y] == hists_new[leftTrough])// || hists_new[y] < hists_new[topValue] / 10
  1291. {
  1292. leftTroughBackUp = y;
  1293. }
  1294. }
  1295. }
  1296. if (leftTroughBackUp == 0) leftTroughBackUp = leftTrough;
  1297. int rightTrough = topValue;
  1298. int rightTroughBackUp = 0;
  1299. //从波峰点向右侧找波谷点
  1300. for (int y = topValue + 1; y < rightValue; y++)
  1301. {
  1302. if (hists_new[y] >= 0 && hists_new[y] <= hists_new[rightTrough])
  1303. {
  1304. rightTrough = y;
  1305. }
  1306. else
  1307. {
  1308. break;
  1309. }
  1310. }
  1311. //微调
  1312. //if (smoothStep >= 30)
  1313. {
  1314. for (int y = rightTrough - 1; y > topValue; y--)
  1315. {
  1316. if (hists_new[y] == hists_new[rightTrough])// || hists_new[y] < hists_new[topValue] / 10
  1317. {
  1318. rightTroughBackUp = y;
  1319. }
  1320. }
  1321. }
  1322. if (rightTroughBackUp == 0) rightTroughBackUp = rightTrough;
  1323. int[] arr = new int[2];
  1324. arr[0] = leftTroughBackUp;
  1325. arr[1] = rightTroughBackUp;
  1326. mountainsArrList.Add(arr);
  1327. int[] arr1 = new int[2];
  1328. arr1[0] = leftTroughBackUp > 0 ? leftTroughBackUp : leftTrough;
  1329. arr1[1] = rightTroughBackUp > 0 ? rightTroughBackUp : rightTrough;
  1330. mountainsArrListBackUp.Add(arr1);
  1331. if (leftValue < leftTrough - 1)
  1332. {
  1333. if (!str.Contains(leftValue + "|" + leftTrough))
  1334. {
  1335. str.Add(leftValue + "|" + leftTrough);
  1336. FindTopAndBetweenWithOutWT123(hists_new, leftValue, leftTrough, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  1337. }
  1338. }
  1339. if (rightValue > rightTrough + 1)
  1340. {
  1341. if (!str.Contains(rightValue + "|" + rightTrough))
  1342. {
  1343. str.Add(rightValue + "|" + rightTrough);
  1344. FindTopAndBetweenWithOutWT123(hists_new, rightTrough, rightValue, mountainsList, mountainsArrList, mountainsArrListBackUp, str, smoothStep);
  1345. }
  1346. }
  1347. }
  1348. public static float areaRatio(int[] hists_new, int[] se)
  1349. {
  1350. int sum = hists_new.Sum();
  1351. int sum1 = 0;
  1352. for (int i = se[0]; i < se[1]; i++)
  1353. {
  1354. sum1 += hists_new[i];
  1355. }
  1356. return (sum1 * 1f / sum) * 100;
  1357. }
  1358. /// <summary>
  1359. /// 测试用标尺
  1360. /// </summary>
  1361. public static double bc = 5.3191 / 1000;
  1362. /// <summary>
  1363. /// 获取两点之间的距离
  1364. /// </summary>
  1365. /// <param name="pointO"></param>
  1366. /// <param name="pointA"></param>
  1367. /// <returns></returns>
  1368. public static double getDistance(OpenCvSharp.Point pointO, OpenCvSharp.Point pointA)
  1369. {
  1370. double distance;
  1371. distance = Math.Pow((pointO.X - pointA.X), 2) + Math.Pow((pointO.Y - pointA.Y), 2);
  1372. distance = Math.Sqrt(distance);
  1373. return distance;
  1374. }
  1375. /// <summary>
  1376. /// 获取点到直线的距离
  1377. /// </summary>
  1378. /// <param name="pointP"></param>
  1379. /// <param name="pointA"></param>
  1380. /// <param name="pointB"></param>
  1381. /// <returns></returns>
  1382. public static float getDist_P2L(OpenCvSharp.Point pointP, OpenCvSharp.Point pointA, OpenCvSharp.Point pointB)
  1383. {
  1384. int A = 0, B = 0, C = 0;
  1385. A = pointA.Y - pointB.Y;
  1386. B = pointB.X - pointA.X;
  1387. C = pointA.X * pointB.Y - pointA.Y * pointB.X;
  1388. float distance = 0;
  1389. distance = ((float)Math.Abs(A * pointP.X + B * pointP.Y + C)) / ((float)Math.Sqrt(A * A + B * B));
  1390. return distance;
  1391. }
  1392. /// <summary>
  1393. /// 原本是打算做返回随机颜色
  1394. /// </summary>
  1395. /// <returns></returns>
  1396. public static Scalar GetRandumScalar()
  1397. {
  1398. return new Scalar(0, 0, 255);
  1399. }
  1400. /// <summary>
  1401. /// 深度copy
  1402. /// </summary>
  1403. /// <param name="src"></param>
  1404. /// <returns></returns>
  1405. public static List<OpenCvSharp.Point> CopyPoints(List<OpenCvSharp.Point> src)
  1406. {
  1407. List<OpenCvSharp.Point> dst = new List<OpenCvSharp.Point>();
  1408. foreach (OpenCvSharp.Point point in src)
  1409. {
  1410. OpenCvSharp.Point p = new OpenCvSharp.Point();
  1411. p.X = point.X;
  1412. p.Y = point.Y;
  1413. dst.Add(p);
  1414. }
  1415. return dst;
  1416. }
  1417. /// <summary>
  1418. /// 获取周围的点的数量,并且判断结点
  1419. /// </summary>
  1420. /// <param name="points"></param>
  1421. /// <param name="jiedian"></param>
  1422. /// <param name="temp"></param>
  1423. /// <returns></returns>
  1424. public static int GetAroundNum(List<OpenCvSharp.Point> points, OpenCvSharp.Point jiedian, OpenCvSharp.Point temp)
  1425. {
  1426. if (points.IndexOf(temp) < 0)
  1427. {
  1428. return 2;
  1429. }
  1430. int i = 0;
  1431. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  1432. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  1433. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  1434. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  1435. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  1436. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  1437. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  1438. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  1439. if (points.IndexOf(zuo) >= 0)
  1440. {
  1441. if (zuo.X != jiedian.X || zuo.Y != jiedian.Y) i++;
  1442. }
  1443. if (points.IndexOf(zuo_shang) >= 0)
  1444. {
  1445. if (zuo_shang.X != jiedian.X || zuo_shang.Y != jiedian.Y) i++;
  1446. }
  1447. if (points.IndexOf(shang) >= 0)
  1448. {
  1449. if (shang.X != jiedian.X || shang.Y != jiedian.Y) i++;
  1450. }
  1451. if (points.IndexOf(you_shang) >= 0)
  1452. {
  1453. if (you_shang.X != jiedian.X || you_shang.Y != jiedian.Y) i++;
  1454. }
  1455. if (points.IndexOf(you) >= 0)
  1456. {
  1457. if (you.X != jiedian.X || you.Y != jiedian.Y) i++;
  1458. }
  1459. if (points.IndexOf(you_xia) >= 0)
  1460. {
  1461. if (you_xia.X != jiedian.X || you_xia.Y != jiedian.Y) i++;
  1462. }
  1463. if (points.IndexOf(xia) >= 0)
  1464. {
  1465. if (xia.X != jiedian.X || xia.Y != jiedian.Y) i++;
  1466. }
  1467. if (points.IndexOf(zuo_xia) >= 0)
  1468. {
  1469. if (zuo_xia.X != jiedian.X || zuo_xia.Y != jiedian.Y) i++;
  1470. }
  1471. return i;
  1472. }
  1473. /// <summary>
  1474. /// 获取起点和终点的路径上的所有点
  1475. /// </summary>
  1476. /// <returns></returns>
  1477. public static List<OpenCvSharp.Point> GetPassPoints(List<OpenCvSharp.Point> points,
  1478. List<OpenCvSharp.Point> jiedians,
  1479. OpenCvSharp.Point start,
  1480. OpenCvSharp.Point end)
  1481. {
  1482. List<OpenCvSharp.Point> passPoints = new List<OpenCvSharp.Point>();
  1483. List<OpenCvSharp.Point> copys = CopyPoints(points);
  1484. OpenCvSharp.Point temp = start;
  1485. bool loopFlag = true;
  1486. do
  1487. {
  1488. int num = 0;
  1489. copys.Remove(temp);
  1490. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  1491. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  1492. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  1493. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  1494. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  1495. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  1496. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  1497. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  1498. if (copys.IndexOf(zuo) >= 0)
  1499. {
  1500. temp = zuo;
  1501. passPoints.Add(zuo);
  1502. copys.Remove(zuo);
  1503. num++;
  1504. }
  1505. if (copys.IndexOf(zuo_shang) >= 0)
  1506. {
  1507. temp = zuo_shang;
  1508. passPoints.Add(zuo_shang);
  1509. copys.Remove(zuo_shang);
  1510. num++;
  1511. }
  1512. if (copys.IndexOf(shang) >= 0)
  1513. {
  1514. temp = shang;
  1515. passPoints.Add(shang);
  1516. copys.Remove(shang);
  1517. num++;
  1518. }
  1519. if (copys.IndexOf(you_shang) >= 0)
  1520. {
  1521. temp = you_shang;
  1522. passPoints.Add(you_shang);
  1523. copys.Remove(you_shang);
  1524. num++;
  1525. }
  1526. if (copys.IndexOf(you) >= 0)
  1527. {
  1528. temp = you;
  1529. passPoints.Add(you);
  1530. copys.Remove(you);
  1531. num++;
  1532. }
  1533. if (copys.IndexOf(you_xia) >= 0)
  1534. {
  1535. temp = you_xia;
  1536. passPoints.Add(you_xia);
  1537. copys.Remove(you_xia);
  1538. num++;
  1539. }
  1540. if (copys.IndexOf(xia) >= 0)
  1541. {
  1542. temp = xia;
  1543. passPoints.Add(xia);
  1544. copys.Remove(xia);
  1545. num++;
  1546. }
  1547. if (copys.IndexOf(zuo_xia) >= 0)
  1548. {
  1549. temp = zuo_xia;
  1550. passPoints.Add(zuo_xia);
  1551. copys.Remove(zuo_xia);
  1552. num++;
  1553. }
  1554. if (num > 1 || num == 0)
  1555. loopFlag = false;
  1556. }
  1557. while (loopFlag);
  1558. temp = end;
  1559. loopFlag = true;
  1560. do
  1561. {
  1562. int num = 0;
  1563. copys.Remove(temp);
  1564. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  1565. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  1566. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  1567. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  1568. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  1569. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  1570. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  1571. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  1572. if (copys.IndexOf(zuo) >= 0)
  1573. {
  1574. temp = zuo;
  1575. passPoints.Add(zuo);
  1576. copys.Remove(zuo);
  1577. num++;
  1578. }
  1579. if (copys.IndexOf(zuo_shang) >= 0)
  1580. {
  1581. temp = zuo_shang;
  1582. passPoints.Add(zuo_shang);
  1583. copys.Remove(zuo_shang);
  1584. num++;
  1585. }
  1586. if (copys.IndexOf(shang) >= 0)
  1587. {
  1588. temp = shang;
  1589. passPoints.Add(shang);
  1590. copys.Remove(shang);
  1591. num++;
  1592. }
  1593. if (copys.IndexOf(you_shang) >= 0)
  1594. {
  1595. temp = you_shang;
  1596. passPoints.Add(you_shang);
  1597. copys.Remove(you_shang);
  1598. num++;
  1599. }
  1600. if (copys.IndexOf(you) >= 0)
  1601. {
  1602. temp = you;
  1603. passPoints.Add(you);
  1604. copys.Remove(you);
  1605. num++;
  1606. }
  1607. if (copys.IndexOf(you_xia) >= 0)
  1608. {
  1609. temp = you_xia;
  1610. passPoints.Add(you_xia);
  1611. copys.Remove(you_xia);
  1612. num++;
  1613. }
  1614. if (copys.IndexOf(xia) >= 0)
  1615. {
  1616. temp = xia;
  1617. passPoints.Add(xia);
  1618. copys.Remove(xia);
  1619. num++;
  1620. }
  1621. if (copys.IndexOf(zuo_xia) >= 0)
  1622. {
  1623. temp = zuo_xia;
  1624. passPoints.Add(zuo_xia);
  1625. copys.Remove(zuo_xia);
  1626. num++;
  1627. }
  1628. if (num > 1 || num == 0)
  1629. loopFlag = false;
  1630. }
  1631. while (loopFlag);
  1632. return passPoints;
  1633. }
  1634. /// <summary>
  1635. /// 近似判断临近点是否再直线上
  1636. /// </summary>
  1637. /// <param name="points"></param>
  1638. /// <param name="seed"></param>
  1639. /// <returns></returns>
  1640. public static bool IsNearPoint(List<OpenCvSharp.Point> points, OpenCvSharp.Point seed)
  1641. {
  1642. if (points.IndexOf(seed) >= 0)
  1643. return true;
  1644. OpenCvSharp.Point zuo = new OpenCvSharp.Point(seed.X - 1, seed.Y);
  1645. if (points.IndexOf(zuo) >= 0)
  1646. return true;
  1647. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(seed.X - 1, seed.Y - 1);
  1648. if (points.IndexOf(zuo_shang) >= 0)
  1649. return true;
  1650. OpenCvSharp.Point shang = new OpenCvSharp.Point(seed.X, seed.Y - 1);
  1651. if (points.IndexOf(shang) >= 0)
  1652. return true;
  1653. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(seed.X + 1, seed.Y - 1);
  1654. if (points.IndexOf(you_shang) >= 0)
  1655. return true;
  1656. OpenCvSharp.Point you = new OpenCvSharp.Point(seed.X + 1, seed.Y);
  1657. if (points.IndexOf(you) >= 0)
  1658. return true;
  1659. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(seed.X + 1, seed.Y + 1);
  1660. if (points.IndexOf(you_xia) >= 0)
  1661. return true;
  1662. OpenCvSharp.Point xia = new OpenCvSharp.Point(seed.X, seed.Y + 1);
  1663. if (points.IndexOf(xia) >= 0)
  1664. return true;
  1665. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(seed.X - 1, seed.Y + 1);
  1666. if (points.IndexOf(zuo_xia) >= 0)
  1667. return true;
  1668. return false;
  1669. }
  1670. /// <summary>
  1671. /// 检测两个点之间是否连通
  1672. /// 程序不太对,还得在修改
  1673. /// </summary>
  1674. /// <param name="points"></param>
  1675. /// <param name="pointa"></param>
  1676. /// <param name="pointb"></param>
  1677. /// <returns></returns>
  1678. public static bool existLianTong(List<OpenCvSharp.Point> points, OpenCvSharp.Point pointa, OpenCvSharp.Point pointb)
  1679. {
  1680. List<OpenCvSharp.Point> copys = CopyPoints(points);
  1681. bool lt = false;
  1682. bool isis = true;
  1683. OpenCvSharp.Point temp = pointa;
  1684. do
  1685. {
  1686. bool inArr = false;
  1687. copys.Remove(temp);
  1688. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  1689. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  1690. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  1691. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  1692. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  1693. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  1694. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  1695. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  1696. if (points.IndexOf(zuo) >= 0)
  1697. {
  1698. if (zuo.X == pointb.X && zuo.Y == pointb.Y)
  1699. {
  1700. lt = true;
  1701. isis = false;
  1702. }
  1703. temp = zuo;
  1704. inArr = true;
  1705. }
  1706. if (points.IndexOf(zuo_shang) >= 0)
  1707. {
  1708. if (zuo_shang.X == pointb.X && zuo_shang.Y == pointb.Y)
  1709. {
  1710. lt = true;
  1711. isis = false;
  1712. }
  1713. temp = zuo_shang;
  1714. inArr = true;
  1715. }
  1716. if (points.IndexOf(shang) >= 0)
  1717. {
  1718. if (shang.X == pointb.X && shang.Y == pointb.Y)
  1719. {
  1720. lt = true;
  1721. isis = false;
  1722. }
  1723. temp = shang;
  1724. inArr = true;
  1725. }
  1726. if (points.IndexOf(you_shang) >= 0)
  1727. {
  1728. if (you_shang.X == pointb.X && you_shang.Y == pointb.Y)
  1729. {
  1730. lt = true;
  1731. isis = false;
  1732. }
  1733. temp = you_shang;
  1734. inArr = true;
  1735. }
  1736. if (points.IndexOf(you) >= 0)
  1737. {
  1738. if (you.X == pointb.X && you.Y == pointb.Y)
  1739. {
  1740. lt = true;
  1741. isis = false;
  1742. }
  1743. temp = you;
  1744. inArr = true;
  1745. }
  1746. if (points.IndexOf(you_xia) >= 0)
  1747. {
  1748. if (you_xia.X == pointb.X && you_xia.Y == pointb.Y)
  1749. {
  1750. lt = true;
  1751. isis = false;
  1752. }
  1753. temp = you_xia;
  1754. inArr = true;
  1755. }
  1756. if (points.IndexOf(xia) >= 0)
  1757. {
  1758. if (xia.X == pointb.X && xia.Y == pointb.Y)
  1759. {
  1760. lt = true;
  1761. isis = false;
  1762. }
  1763. temp = xia;
  1764. inArr = true;
  1765. }
  1766. if (points.IndexOf(zuo_xia) >= 0)
  1767. {
  1768. if (zuo_xia.X == pointb.X && zuo_xia.Y == pointb.Y)
  1769. {
  1770. lt = true;
  1771. isis = false;
  1772. }
  1773. temp = zuo_xia;
  1774. inArr = true;
  1775. }
  1776. if (!inArr) isis = false;
  1777. } while (isis);
  1778. return lt;
  1779. }
  1780. /// <summary>
  1781. /// 判断删除当前点是否破坏连通性
  1782. /// </summary>
  1783. /// <returns></returns>
  1784. public static bool panduanDestoryConn(List<OpenCvSharp.Point> points, OpenCvSharp.Point pointa)
  1785. {
  1786. List<OpenCvSharp.Point> copys = CopyPoints(points);
  1787. OpenCvSharp.Point temp = pointa;
  1788. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  1789. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  1790. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  1791. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  1792. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  1793. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  1794. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  1795. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  1796. int a1 = Tools.GetAroundNum(points, temp, zuo);
  1797. int a2 = Tools.GetAroundNum(points, temp, zuo_shang);
  1798. int a3 = Tools.GetAroundNum(points, temp, shang);
  1799. int a4 = Tools.GetAroundNum(points, temp, you_shang);
  1800. int a5 = Tools.GetAroundNum(points, temp, you);
  1801. int a6 = Tools.GetAroundNum(points, temp, you_xia);
  1802. int a7 = Tools.GetAroundNum(points, temp, xia);
  1803. int a8 = Tools.GetAroundNum(points, temp, zuo_xia);
  1804. if (a1 >= 2 && a2 >= 2 && a3 >= 2 && a4 >= 2 && a5 >= 2 && a6 >= 2 && a7 >= 2 && a8 >= 2)
  1805. {
  1806. return false;
  1807. }
  1808. return true;
  1809. }
  1810. /// <summary>
  1811. /// 寻找端点
  1812. /// </summary>
  1813. /// <param name="points"></param>
  1814. /// <returns></returns>
  1815. public static List<OpenCvSharp.Point> FindEndpoints(List<OpenCvSharp.Point> points)
  1816. {
  1817. List<OpenCvSharp.Point> endpoints = new List<OpenCvSharp.Point>();
  1818. foreach (OpenCvSharp.Point point in points)
  1819. {
  1820. OpenCvSharp.Point zuo = new OpenCvSharp.Point(point.X - 1, point.Y);
  1821. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(point.X - 1, point.Y - 1);
  1822. OpenCvSharp.Point shang = new OpenCvSharp.Point(point.X, point.Y - 1);
  1823. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(point.X + 1, point.Y - 1);
  1824. OpenCvSharp.Point you = new OpenCvSharp.Point(point.X + 1, point.Y);
  1825. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(point.X + 1, point.Y + 1);
  1826. OpenCvSharp.Point xia = new OpenCvSharp.Point(point.X, point.Y + 1);
  1827. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(point.X - 1, point.Y + 1);
  1828. int a = points.IndexOf(zuo) >= 0 ? 1 : 0;
  1829. int b = points.IndexOf(zuo_shang) >= 0 ? 1 : 0;
  1830. int c = points.IndexOf(shang) >= 0 ? 1 : 0;
  1831. int d = points.IndexOf(you_shang) >= 0 ? 1 : 0;
  1832. int e = points.IndexOf(you) >= 0 ? 1 : 0;
  1833. int f = points.IndexOf(you_xia) >= 0 ? 1 : 0;
  1834. int g = points.IndexOf(xia) >= 0 ? 1 : 0;
  1835. int h = points.IndexOf(zuo_xia) >= 0 ? 1 : 0;
  1836. int all = a + b + c + d + e + f + g + h;
  1837. if (all == 1)
  1838. {
  1839. endpoints.Add(point);
  1840. }
  1841. else if (all == 2)
  1842. {
  1843. if (a == 1 && b == 1) endpoints.Add(point);
  1844. if (b == 1 && c == 1) endpoints.Add(point);
  1845. if (c == 1 && d == 1) endpoints.Add(point);
  1846. if (d == 1 && e == 1) endpoints.Add(point);
  1847. if (e == 1 && f == 1) endpoints.Add(point);
  1848. if (f == 1 && g == 1) endpoints.Add(point);
  1849. if (g == 1 && h == 1) endpoints.Add(point);
  1850. if (h == 1 && a == 1) endpoints.Add(point);
  1851. }
  1852. }
  1853. return endpoints;
  1854. }
  1855. /// <summary>
  1856. /// 移除点
  1857. /// </summary>
  1858. /// <param name="points">连通域集合</param>
  1859. /// <param name="pairs">已用的端点集合</param>
  1860. public static List<OpenCvSharp.Point> RemoveSomePoint(List<OpenCvSharp.Point> points, List<OpenCvSharp.Point> pairs, List<OpenCvSharp.Point> jiedians)
  1861. {
  1862. List<OpenCvSharp.Point> copys = CopyPoints(points);
  1863. foreach (OpenCvSharp.Point p1 in pairs)
  1864. {
  1865. bool nkkk = true;
  1866. OpenCvSharp.Point temp = p1;
  1867. do
  1868. {
  1869. bool isexit = false;
  1870. copys.Remove(temp);
  1871. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  1872. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  1873. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  1874. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  1875. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  1876. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  1877. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  1878. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  1879. if (copys.IndexOf(zuo) >= 0)
  1880. {
  1881. isexit = true;
  1882. if (jiedians.IndexOf(zuo) >= 0)
  1883. {
  1884. nkkk = false;
  1885. }
  1886. else
  1887. {
  1888. temp = zuo;
  1889. copys.Remove(zuo);
  1890. }
  1891. }
  1892. if (copys.IndexOf(zuo_shang) >= 0)
  1893. {
  1894. isexit = true;
  1895. if (jiedians.IndexOf(zuo_shang) >= 0)
  1896. {
  1897. nkkk = false;
  1898. }
  1899. else
  1900. {
  1901. temp = zuo_shang;
  1902. copys.Remove(zuo_shang);
  1903. }
  1904. }
  1905. if (copys.IndexOf(shang) >= 0)
  1906. {
  1907. isexit = true;
  1908. if (jiedians.IndexOf(shang) >= 0)
  1909. {
  1910. nkkk = false;
  1911. }
  1912. else
  1913. {
  1914. temp = shang;
  1915. copys.Remove(shang);
  1916. }
  1917. }
  1918. if (copys.IndexOf(you_shang) >= 0)
  1919. {
  1920. isexit = true;
  1921. if (jiedians.IndexOf(you_shang) >= 0)
  1922. {
  1923. nkkk = false;
  1924. }
  1925. else
  1926. {
  1927. temp = you_shang;
  1928. copys.Remove(you_shang);
  1929. }
  1930. }
  1931. if (copys.IndexOf(you) >= 0)
  1932. {
  1933. isexit = true;
  1934. if (jiedians.IndexOf(you) >= 0)
  1935. {
  1936. nkkk = false;
  1937. }
  1938. else
  1939. {
  1940. temp = you;
  1941. copys.Remove(you);
  1942. }
  1943. }
  1944. if (copys.IndexOf(you_xia) >= 0)
  1945. {
  1946. isexit = true;
  1947. if (jiedians.IndexOf(you_xia) >= 0)
  1948. {
  1949. nkkk = false;
  1950. }
  1951. else
  1952. {
  1953. temp = you_xia;
  1954. copys.Remove(you_xia);
  1955. }
  1956. }
  1957. if (copys.IndexOf(xia) >= 0)
  1958. {
  1959. isexit = true;
  1960. if (jiedians.IndexOf(xia) >= 0)
  1961. {
  1962. nkkk = false;
  1963. }
  1964. else
  1965. {
  1966. temp = xia;
  1967. copys.Remove(xia);
  1968. }
  1969. }
  1970. if (copys.IndexOf(zuo_xia) >= 0)
  1971. {
  1972. isexit = true;
  1973. if (jiedians.IndexOf(zuo_xia) >= 0)
  1974. {
  1975. nkkk = false;
  1976. }
  1977. else
  1978. {
  1979. temp = zuo_xia;
  1980. copys.Remove(zuo_xia);
  1981. }
  1982. }
  1983. if (!isexit) nkkk = false;
  1984. }
  1985. while (nkkk);
  1986. }
  1987. return copys;
  1988. }
  1989. /// <summary>
  1990. /// 寻找结点
  1991. /// </summary>
  1992. /// <param name="points"></param>
  1993. /// <returns></returns>
  1994. public static List<OpenCvSharp.Point> FindIntersectionPoint(List<OpenCvSharp.Point> points)
  1995. {
  1996. List<OpenCvSharp.Point> ps = new List<OpenCvSharp.Point>();
  1997. //1左 2左上 3上 4右上 5右 6右下 7下 8左下
  1998. for (int i = 0; i < points.Count - 1; i++)
  1999. {
  2000. OpenCvSharp.Point point = points[i];
  2001. OpenCvSharp.Point zuo = new OpenCvSharp.Point(point.X - 1, point.Y);
  2002. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(point.X - 1, point.Y - 1);
  2003. OpenCvSharp.Point shang = new OpenCvSharp.Point(point.X, point.Y - 1);
  2004. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(point.X + 1, point.Y - 1);
  2005. OpenCvSharp.Point you = new OpenCvSharp.Point(point.X + 1, point.Y);
  2006. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(point.X + 1, point.Y + 1);
  2007. OpenCvSharp.Point xia = new OpenCvSharp.Point(point.X, point.Y + 1);
  2008. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(point.X - 1, point.Y + 1);
  2009. int a = points.IndexOf(zuo) >= 0 ? 1 : 0;
  2010. int b = points.IndexOf(zuo_shang) >= 0 ? 1 : 0;
  2011. int c = points.IndexOf(shang) >= 0 ? 1 : 0;
  2012. int d = points.IndexOf(you_shang) >= 0 ? 1 : 0;
  2013. int e = points.IndexOf(you) >= 0 ? 1 : 0;
  2014. int f = points.IndexOf(you_xia) >= 0 ? 1 : 0;
  2015. int g = points.IndexOf(xia) >= 0 ? 1 : 0;
  2016. int h = points.IndexOf(zuo_xia) >= 0 ? 1 : 0;
  2017. int all = a + b + c + d + e + f + g + h;
  2018. if (all > 2)
  2019. {
  2020. ps.Add(point);
  2021. }
  2022. }
  2023. if (ps.Count > 1)
  2024. {
  2025. List<OpenCvSharp.Point> copys = CopyPoints(ps);
  2026. for (int i = ps.Count - 1; i >= 0; i--)
  2027. {
  2028. OpenCvSharp.Point temp = ps[i];
  2029. ps.Remove(temp);
  2030. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  2031. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  2032. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  2033. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  2034. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  2035. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  2036. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  2037. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  2038. if (ps.IndexOf(zuo) >= 0)
  2039. {
  2040. copys.Remove(zuo);
  2041. }
  2042. if (ps.IndexOf(zuo_shang) >= 0)
  2043. {
  2044. copys.Remove(zuo_shang);
  2045. }
  2046. if (ps.IndexOf(shang) >= 0)
  2047. {
  2048. copys.Remove(shang);
  2049. }
  2050. if (ps.IndexOf(you_shang) >= 0)
  2051. {
  2052. copys.Remove(you_shang);
  2053. }
  2054. if (ps.IndexOf(you) >= 0)
  2055. {
  2056. copys.Remove(you);
  2057. }
  2058. if (ps.IndexOf(you_xia) >= 0)
  2059. {
  2060. copys.Remove(you_xia);
  2061. }
  2062. if (ps.IndexOf(xia) >= 0)
  2063. {
  2064. copys.Remove(xia);
  2065. }
  2066. if (ps.IndexOf(zuo_xia) >= 0)
  2067. {
  2068. copys.Remove(zuo_xia);
  2069. }
  2070. }
  2071. return copys;
  2072. }
  2073. return ps;
  2074. }
  2075. public static bool ExistInList(List<List<OpenCvSharp.Point>> lists, OpenCvSharp.Point point)
  2076. {
  2077. foreach (List<OpenCvSharp.Point> list in lists)
  2078. {
  2079. if (list.IndexOf(point) >= 0)
  2080. {
  2081. return true;
  2082. }
  2083. }
  2084. return false;
  2085. }
  2086. /// <summary>
  2087. /// 从一个端点出发,遇到结点,进行直线拟合
  2088. /// </summary>
  2089. /// <param name="copys"></param>
  2090. /// <param name="point"></param>
  2091. /// <returns></returns>
  2092. public static bool FindLineFromOnePoint(List<OpenCvSharp.Point> copys, OpenCvSharp.Point point, out Line2D line)
  2093. {
  2094. //原集合的copy
  2095. List<OpenCvSharp.Point> copys_1 = Tools.CopyPoints(copys);
  2096. //用于存放起始点
  2097. List<OpenCvSharp.Point> temps = new List<OpenCvSharp.Point>();
  2098. int num = 0;
  2099. OpenCvSharp.Point temp = point;
  2100. copys_1.Remove(temp);
  2101. do
  2102. {
  2103. num = 0;
  2104. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  2105. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  2106. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  2107. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  2108. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  2109. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  2110. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  2111. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  2112. if (copys_1.IndexOf(zuo) >= 0)
  2113. {
  2114. temp = zuo;
  2115. copys_1.Remove(temp);
  2116. temps.Add(zuo);
  2117. num++;
  2118. }
  2119. if (copys_1.IndexOf(zuo_shang) >= 0)
  2120. {
  2121. temp = zuo_shang;
  2122. copys_1.Remove(temp);
  2123. temps.Add(zuo_shang);
  2124. num++;
  2125. }
  2126. if (copys_1.IndexOf(shang) >= 0)
  2127. {
  2128. temp = shang;
  2129. copys_1.Remove(temp);
  2130. temps.Add(shang);
  2131. num++;
  2132. }
  2133. if (copys_1.IndexOf(you_shang) >= 0)
  2134. {
  2135. temp = you_shang;
  2136. copys_1.Remove(temp);
  2137. temps.Add(you_shang);
  2138. num++;
  2139. }
  2140. if (copys_1.IndexOf(you) >= 0)
  2141. {
  2142. temp = you;
  2143. copys_1.Remove(temp);
  2144. temps.Add(you);
  2145. num++;
  2146. }
  2147. if (copys_1.IndexOf(you_xia) >= 0)
  2148. {
  2149. temp = you_xia;
  2150. copys_1.Remove(temp);
  2151. temps.Add(you_xia);
  2152. num++;
  2153. }
  2154. if (copys_1.IndexOf(xia) >= 0)
  2155. {
  2156. temp = xia;
  2157. copys_1.Remove(temp);
  2158. temps.Add(xia);
  2159. num++;
  2160. }
  2161. if (copys_1.IndexOf(zuo_xia) >= 0)
  2162. {
  2163. temp = zuo_xia;
  2164. copys_1.Remove(temp);
  2165. temps.Add(zuo_xia);
  2166. num++;
  2167. }
  2168. }
  2169. while (num == 1);
  2170. if (temps.Count < 10)
  2171. {
  2172. temps.RemoveAt(temps.Count - 1);
  2173. temps.RemoveAt(temps.Count - 1);
  2174. }
  2175. else
  2176. {
  2177. int delNum = temps.Count / 5;
  2178. int min = temps.Count - delNum;
  2179. for (int i = temps.Count - 1; i > min; i--)
  2180. temps.Remove(temps[i]);
  2181. }
  2182. if (temps.Count >= 2)
  2183. line = Cv2.FitLine(temps, DistanceTypes.Huber, 0, 0.01, 0.01);
  2184. else
  2185. line = new Line2D(0, 0, 0, 0);
  2186. if (temps.Count < 4)
  2187. {
  2188. return false;
  2189. }
  2190. return true;
  2191. /*if (line2D.Y1 > 0)
  2192. {
  2193. //这是获取直线上的点方程
  2194. OpenCvSharp.Point a = new OpenCvSharp.Point((int)(line2D.X1 - 100 * line2D.Vx), (int)(line2D.Y1 - 100 * line2D.Vy));
  2195. OpenCvSharp.Point b = new OpenCvSharp.Point((int)(line2D.X1 - 10 * line2D.Vx), (int)(line2D.Y1 - 10 * line2D.Vy));
  2196. //Cv2.Line(origin, a, b, new Scalar(0, 0, 255), 2);
  2197. //Cv2.ImWrite("C:\\Users\\zyh\\Desktop\\fuck.png", origin);
  2198. }*/
  2199. }
  2200. /// <summary>
  2201. /// 使用mul获取直线上的点
  2202. /// </summary>
  2203. /// <param name="line2D"></param>
  2204. /// <param name="mul"></param>
  2205. /// <returns></returns>
  2206. public static OpenCvSharp.Point GetOnLineNextPoint(Line2D line2D, int mul)
  2207. {
  2208. //但是需要考虑直线垂直或平行x、y轴的时候
  2209. return new OpenCvSharp.Point((int)(line2D.X1 - mul * line2D.Vx), (int)(line2D.Y1 - mul * line2D.Vy));
  2210. }
  2211. /// <summary>
  2212. /// 使用直线方程获取直线上的点
  2213. /// </summary>
  2214. /// <param name="line2D"></param>
  2215. /// <param name="point"></param>
  2216. /// <returns></returns>
  2217. public static int GetMulByPoint(Line2D line2D, OpenCvSharp.Point point)
  2218. {
  2219. if (line2D.Vy == 1)
  2220. return (int)(line2D.Y1 - point.Y);
  2221. if (line2D.Vx == 1)
  2222. return (int)(line2D.X1 - point.X);
  2223. if (line2D.Vx > 0.01)
  2224. return (int)((line2D.X1 - point.X) / line2D.Vx);
  2225. else
  2226. return (int)((line2D.Y1 - point.Y) / line2D.Vy);
  2227. }
  2228. /// <summary>
  2229. /// 获取相邻的点的数量
  2230. /// </summary>
  2231. /// <param name="points"></param>
  2232. /// <param name="temp"></param>
  2233. /// <returns></returns>
  2234. public static int GetAroundNumWithNotJ(List<OpenCvSharp.Point> points, OpenCvSharp.Point temp)
  2235. {
  2236. int i = 0;
  2237. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  2238. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  2239. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  2240. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  2241. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  2242. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  2243. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  2244. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  2245. if (points.IndexOf(zuo) >= 0) i++;
  2246. if (points.IndexOf(zuo_shang) >= 0) i++;
  2247. if (points.IndexOf(shang) >= 0) i++;
  2248. if (points.IndexOf(you_shang) >= 0) i++;
  2249. if (points.IndexOf(you) >= 0) i++;
  2250. if (points.IndexOf(you_xia) >= 0) i++;
  2251. if (points.IndexOf(xia) >= 0) i++;
  2252. if (points.IndexOf(zuo_xia) >= 0) i++;
  2253. return i;
  2254. }
  2255. /// <summary>
  2256. /// 判断点是否是端点
  2257. /// </summary>
  2258. /// <param name="points"></param>
  2259. /// <param name="temp"></param>
  2260. /// <returns></returns>
  2261. public static bool FindEndpoints(List<OpenCvSharp.Point> points, OpenCvSharp.Point temp)
  2262. {
  2263. OpenCvSharp.Point zuo = new OpenCvSharp.Point(temp.X - 1, temp.Y);
  2264. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(temp.X - 1, temp.Y - 1);
  2265. OpenCvSharp.Point shang = new OpenCvSharp.Point(temp.X, temp.Y - 1);
  2266. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(temp.X + 1, temp.Y - 1);
  2267. OpenCvSharp.Point you = new OpenCvSharp.Point(temp.X + 1, temp.Y);
  2268. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(temp.X + 1, temp.Y + 1);
  2269. OpenCvSharp.Point xia = new OpenCvSharp.Point(temp.X, temp.Y + 1);
  2270. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(temp.X - 1, temp.Y + 1);
  2271. int a = points.IndexOf(zuo) >= 0 ? 1 : 0;
  2272. int b = points.IndexOf(zuo_shang) >= 0 ? 1 : 0;
  2273. int c = points.IndexOf(shang) >= 0 ? 1 : 0;
  2274. int d = points.IndexOf(you_shang) >= 0 ? 1 : 0;
  2275. int e = points.IndexOf(you) >= 0 ? 1 : 0;
  2276. int f = points.IndexOf(you_xia) >= 0 ? 1 : 0;
  2277. int g = points.IndexOf(xia) >= 0 ? 1 : 0;
  2278. int h = points.IndexOf(zuo_xia) >= 0 ? 1 : 0;
  2279. int all = a + b + c + d + e + f + g + h;
  2280. if (all == 1)
  2281. {
  2282. return true;
  2283. }
  2284. else if (all == 2)
  2285. {
  2286. if (a == 1 && b == 1) return true;
  2287. if (b == 1 && c == 1) return true;
  2288. if (c == 1 && d == 1) return true;
  2289. if (d == 1 && e == 1) return true;
  2290. if (e == 1 && f == 1) return true;
  2291. if (f == 1 && g == 1) return true;
  2292. if (g == 1 && h == 1) return true;
  2293. if (h == 1 && a == 1) return true;
  2294. }
  2295. return false;
  2296. }
  2297. /// <summary>
  2298. /// 移除临近点
  2299. /// </summary>
  2300. /// <param name="points"></param>
  2301. /// <param name="endPoint"></param>
  2302. public static void DeleteNearPoint(List<OpenCvSharp.Point> points, OpenCvSharp.Point startP)
  2303. {
  2304. points.Remove(startP);
  2305. OpenCvSharp.Point seed = startP;
  2306. int num;
  2307. do
  2308. {
  2309. num = 0;
  2310. int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0;
  2311. OpenCvSharp.Point a1 = new OpenCvSharp.Point(0, 0);
  2312. OpenCvSharp.Point b1 = new OpenCvSharp.Point(0, 0);
  2313. OpenCvSharp.Point c1 = new OpenCvSharp.Point(0, 0);
  2314. OpenCvSharp.Point d1 = new OpenCvSharp.Point(0, 0);
  2315. OpenCvSharp.Point e1 = new OpenCvSharp.Point(0, 0);
  2316. OpenCvSharp.Point f1 = new OpenCvSharp.Point(0, 0);
  2317. OpenCvSharp.Point g1 = new OpenCvSharp.Point(0, 0);
  2318. OpenCvSharp.Point h1 = new OpenCvSharp.Point(0, 0);
  2319. List<OpenCvSharp.Point> nears = new List<OpenCvSharp.Point>();
  2320. OpenCvSharp.Point zuo = new OpenCvSharp.Point(seed.X - 1, seed.Y);
  2321. if (points.IndexOf(zuo) >= 0)
  2322. {
  2323. a = 1;
  2324. num++;
  2325. a1 = zuo;
  2326. nears.Add(zuo);
  2327. }
  2328. OpenCvSharp.Point zuo_shang = new OpenCvSharp.Point(seed.X - 1, seed.Y - 1);
  2329. if (points.IndexOf(zuo_shang) >= 0)
  2330. {
  2331. b = 1;
  2332. num++;
  2333. b1 = zuo_shang;
  2334. nears.Add(zuo_shang);
  2335. }
  2336. OpenCvSharp.Point shang = new OpenCvSharp.Point(seed.X, seed.Y - 1);
  2337. if (points.IndexOf(shang) >= 0)
  2338. {
  2339. c = 1;
  2340. num++;
  2341. c1 = shang;
  2342. nears.Add(shang);
  2343. }
  2344. OpenCvSharp.Point you_shang = new OpenCvSharp.Point(seed.X + 1, seed.Y - 1);
  2345. if (points.IndexOf(you_shang) >= 0)
  2346. {
  2347. d = 1;
  2348. num++;
  2349. d1 = you_shang;
  2350. nears.Add(you_shang);
  2351. }
  2352. OpenCvSharp.Point you = new OpenCvSharp.Point(seed.X + 1, seed.Y);
  2353. if (points.IndexOf(you) >= 0)
  2354. {
  2355. e = 1;
  2356. num++;
  2357. e1 = you;
  2358. nears.Add(you);
  2359. }
  2360. OpenCvSharp.Point you_xia = new OpenCvSharp.Point(seed.X + 1, seed.Y + 1);
  2361. if (points.IndexOf(you_xia) >= 0)
  2362. {
  2363. f = 1;
  2364. num++;
  2365. f1 = you_xia;
  2366. nears.Add(you_xia);
  2367. }
  2368. OpenCvSharp.Point xia = new OpenCvSharp.Point(seed.X, seed.Y + 1);
  2369. if (points.IndexOf(xia) >= 0)
  2370. {
  2371. g = 1;
  2372. num++;
  2373. g1 = xia;
  2374. nears.Add(xia);
  2375. }
  2376. OpenCvSharp.Point zuo_xia = new OpenCvSharp.Point(seed.X - 1, seed.Y + 1);
  2377. if (points.IndexOf(zuo_xia) >= 0)
  2378. {
  2379. h = 1;
  2380. num++;
  2381. h1 = zuo_xia;
  2382. nears.Add(zuo_xia);
  2383. }
  2384. if (num == 1)
  2385. {
  2386. if (a == 1) seed = a1;
  2387. if (b == 1) seed = b1;
  2388. if (c == 1) seed = c1;
  2389. if (d == 1) seed = d1;
  2390. if (e == 1) seed = e1;
  2391. if (f == 1) seed = f1;
  2392. if (g == 1) seed = g1;
  2393. if (h == 1) seed = h1;
  2394. points.Remove(nears[0]);
  2395. }
  2396. else if (num == 2)
  2397. {
  2398. if ((a == 1 && b == 1) || (b == 1 && c == 1) || (c == 1 && d == 1) ||
  2399. (d == 1 && e == 1) || (e == 1 && f == 1) || (f == 1 && g == 1) ||
  2400. (g == 1 && h == 1) || (h == 1 && a == 1))
  2401. {
  2402. if (a == 1 && b == 1)
  2403. {
  2404. if (!FindEndpoints(points, a1)) seed = a1;
  2405. if (!FindEndpoints(points, b1)) seed = b1;
  2406. }
  2407. if (b == 1 && c == 1)
  2408. {
  2409. if (!FindEndpoints(points, c1)) seed = c1;
  2410. if (!FindEndpoints(points, b1)) seed = b1;
  2411. }
  2412. if (c == 1 && d == 1)
  2413. {
  2414. if (!FindEndpoints(points, c1)) seed = c1;
  2415. if (!FindEndpoints(points, d1)) seed = d1;
  2416. }
  2417. if (d == 1 && e == 1)
  2418. {
  2419. if (!FindEndpoints(points, e1)) seed = e1;
  2420. if (!FindEndpoints(points, d1)) seed = d1;
  2421. }
  2422. if (e == 1 && f == 1)
  2423. {
  2424. if (!FindEndpoints(points, e1)) seed = e1;
  2425. if (!FindEndpoints(points, f1)) seed = f1;
  2426. }
  2427. if (f == 1 && g == 1)
  2428. {
  2429. if (!FindEndpoints(points, g1)) seed = g1;
  2430. if (!FindEndpoints(points, f1)) seed = f1;
  2431. }
  2432. if (g == 1 && h == 1)
  2433. {
  2434. if (!FindEndpoints(points, g1)) seed = g1;
  2435. if (!FindEndpoints(points, h1)) seed = h1;
  2436. }
  2437. if (h == 1 && a == 1)
  2438. {
  2439. if (!FindEndpoints(points, a1)) seed = a1;
  2440. if (!FindEndpoints(points, h1)) seed = h1;
  2441. }
  2442. points.Remove(nears[0]);
  2443. points.Remove(nears[1]);
  2444. num = 1;
  2445. }
  2446. }
  2447. }
  2448. while (num == 1);
  2449. }
  2450. public static Mat MergeMatFromMatArr(Mat[] arr)
  2451. {
  2452. Mat[] mats = new Mat[3];
  2453. mats[0] = arr[0];
  2454. mats[1] = arr[1];
  2455. mats[2] = arr[2];
  2456. Mat dst = new Mat();
  2457. Cv2.Merge(mats, dst);
  2458. return dst;
  2459. }
  2460. /// <summary>
  2461. /// 形态学孔洞填充
  2462. /// </summary>
  2463. /// <param name="srcBw">二值图0/255</param>
  2464. /// <returns></returns>
  2465. public static Mat FillHole(Mat srcBw, Scalar scalar)
  2466. {
  2467. OpenCvSharp.Size m_Size = srcBw.Size();
  2468. //创建扩展边界的图像
  2469. Mat temp = Mat.Zeros(m_Size.Height + 2, m_Size.Width + 2, srcBw.Type());
  2470. srcBw.CopyTo(new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1)));
  2471. //new OpenCvSharp.Point(0, 0)
  2472. Cv2.FloodFill(temp, new OpenCvSharp.Point(0, 0), scalar);
  2473. //裁剪扩展边界的图像
  2474. Mat cutImg = new Mat();
  2475. new Mat(temp, new Range(1, m_Size.Height + 1), new Range(1, m_Size.Width + 1)).CopyTo(cutImg);
  2476. return srcBw | (~cutImg);
  2477. }
  2478. public static int GetRandomNumber(int[] a)
  2479. {
  2480. Random rnd = new Random();
  2481. int index = rnd.Next(a.Length);
  2482. return a[index];
  2483. }
  2484. /// <summary>
  2485. /// 寻找under cut
  2486. /// </summary>
  2487. /// <param name="temp"></param>
  2488. /// <param name="mat"></param>
  2489. /// <returns></returns>
  2490. public static OpenCvSharp.Point GetLeftPoint(OpenCvSharp.Point temp, Mat mat)
  2491. {
  2492. Rect rect = new Rect();
  2493. Mat mask = Mat.Zeros(mat.Rows + 2, mat.Cols + 2, MatType.CV_8UC1);
  2494. Cv2.FloodFill(mat, mask, temp, new Scalar(255), out rect, null, null, FloodFillFlags.Link8);
  2495. mask = mask * 255;
  2496. List<OpenCvSharp.Point> points = new List<OpenCvSharp.Point>();
  2497. for (int h=1; h< mask.Height-1; h++)
  2498. {
  2499. for (int w = temp.X-150; w < temp.X; w++)
  2500. {
  2501. byte v = mask.At<byte>(h, w);
  2502. if(v == 255)
  2503. {
  2504. //if(Cv2.FloodFill(mask, new OpenCvSharp.Point(w, h), new Scalar(255)) > 30)
  2505. points.Add(new OpenCvSharp.Point(w, h));
  2506. }
  2507. }
  2508. }
  2509. List<OpenCvSharp.Point> points1 = points.FindAll(a => a.X < temp.X);
  2510. if(points1.Count ==0)
  2511. {
  2512. return new OpenCvSharp.Point(0, 0);
  2513. }
  2514. int maxY = points1.Max(b => b.Y);
  2515. List<OpenCvSharp.Point> points2 = points.FindAll(a => a.Y > maxY - 20);
  2516. return points2.Find(a => a.X == points2.Min(b => b.X));
  2517. //return points1.Find(a => a.Y == points1.Max(b => b.Y));
  2518. }
  2519. /// <summary>
  2520. /// 找轮廓的最左、最右点
  2521. /// </summary>
  2522. /// <param name="temp"></param>
  2523. /// <param name="mat"></param>
  2524. /// <param name="type">1左 2右</param>
  2525. /// <returns></returns>
  2526. public static OpenCvSharp.Point GetLeftOrRightPoint(OpenCvSharp.Point temp, Mat mat, int type)
  2527. {
  2528. Rect rect = new Rect();
  2529. Mat mask = Mat.Zeros(mat.Rows + 2, mat.Cols + 2, MatType.CV_8UC1);
  2530. Cv2.FloodFill(mat, mask, temp, new Scalar(255), out rect, null, null, FloodFillFlags.Link8);
  2531. mask = mask * 255;
  2532. List<OpenCvSharp.Point> points = new List<OpenCvSharp.Point>();
  2533. if(type==2)
  2534. {
  2535. for (int h = 1; h < temp.Y-15/*mask.Height - 1*/; h++)
  2536. {
  2537. for (int w = temp.X; w < temp.X + 10/*0*/; w++)
  2538. {
  2539. byte v = mask.At<byte>(h, w);
  2540. if (v == 255)
  2541. {
  2542. points.Add(new OpenCvSharp.Point(w, h));
  2543. }
  2544. }
  2545. }
  2546. }
  2547. else
  2548. {
  2549. for (int h = temp.Y - 45; h < temp.Y-15/*mask.Height - 1*/; h++)
  2550. {
  2551. for (int w = temp.X - 200; w < temp.X + 200; w++)
  2552. {
  2553. byte v = mask.At<byte>(h, w);
  2554. if (v == 255)
  2555. {
  2556. points.Add(new OpenCvSharp.Point(w, h));
  2557. }
  2558. }
  2559. }
  2560. }
  2561. if (points.Count == 0) return temp;
  2562. if (type == 1)
  2563. {
  2564. return points.Find(a => a.X == points.Min(b => b.X));
  2565. }
  2566. else
  2567. {
  2568. return points.Find(a => a.X == points.Max(b => b.X));
  2569. }
  2570. }
  2571. public static int GetContoursHeight(OpenCvSharp.Point[] points, out OpenCvSharp.Point topPoint)
  2572. {
  2573. List<OpenCvSharp.Point> list = points.ToList();
  2574. topPoint = list.Find(a => a.Y == list.Min(b => b.Y));
  2575. OpenCvSharp.Point bottom = list.Find(a => a.Y == list.Max(b => b.Y));
  2576. return bottom.Y - topPoint.Y;
  2577. }
  2578. static Mat calMats, phaseTempMin, phaseTempMax, phaseTemp1;
  2579. static int dstChannel;
  2580. static int dstWidth;
  2581. static int localThreshold;
  2582. /// <summary>
  2583. /// 边缘增强
  2584. /// </summary>
  2585. /// <param name="mat"></param>
  2586. /// <param name="kernel"></param>
  2587. /// <param name="threshold"></param>
  2588. /// <returns></returns>
  2589. public unsafe static Mat adaptEdgeEnhancement(Mat mat, int kernel, int threshold)
  2590. {
  2591. Mat f = null;
  2592. try
  2593. {
  2594. localThreshold = threshold;
  2595. dstWidth = mat.Width;
  2596. dstChannel = mat.Channels();
  2597. phaseTemp1 = mat.Clone().CvtColor(ColorConversionCodes.GRAY2BGR);
  2598. calMats = mat.Clone();
  2599. //求最大值最小值
  2600. Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(kernel, kernel));
  2601. //腐蚀
  2602. phaseTempMin = new Mat();
  2603. Cv2.Erode(mat, phaseTempMin, element, null, 1, BorderTypes.Constant);
  2604. //膨胀
  2605. phaseTempMax = new Mat();
  2606. Cv2.Dilate(mat, phaseTempMax, element, null, 1, BorderTypes.Constant);
  2607. f = new Mat();
  2608. Cv2.Subtract(phaseTempMax, phaseTempMin, f);
  2609. f = f.CvtColor(ColorConversionCodes.GRAY2BGR);
  2610. //实现边界增强
  2611. f.ForEachAsVec3b(ForeachFunctionVeb3ForThreshold);
  2612. }
  2613. catch(Exception e)
  2614. {
  2615. }
  2616. finally
  2617. {
  2618. if(calMats != null && !calMats.IsDisposed)
  2619. {
  2620. calMats.Dispose();
  2621. calMats = null;
  2622. }
  2623. if (phaseTempMin != null && !phaseTempMin.IsDisposed)
  2624. {
  2625. phaseTempMin.Dispose();
  2626. phaseTempMin = null;
  2627. }
  2628. if (phaseTempMax != null && !phaseTempMax.IsDisposed)
  2629. {
  2630. phaseTempMax.Dispose();
  2631. phaseTempMax = null;
  2632. }
  2633. if (f != null && !f.IsDisposed)
  2634. {
  2635. f.Dispose();
  2636. f = null;
  2637. }
  2638. }
  2639. return phaseTemp1.CvtColor(ColorConversionCodes.BGR2GRAY);
  2640. }
  2641. private unsafe static void ForeachFunctionVeb3ForThreshold(Vec3b* value, int* position)
  2642. {
  2643. ////对每个像素点的操作
  2644. byte* pixels3 = (byte*)phaseTempMax.Data;
  2645. byte* pixels4 = (byte*)phaseTempMin.Data;
  2646. byte* pixels5 = (byte*)calMats.Data;
  2647. int offset = (position[0] * dstWidth + position[1]) * dstChannel;
  2648. Vec3b aa = new Vec3b(pixels5[offset], pixels5[offset + 1], pixels5[offset + 2]);
  2649. bool toedit = false;
  2650. if (value->Item0 > localThreshold)
  2651. {
  2652. toedit = true;
  2653. byte ff = pixels3[offset];
  2654. byte pp = pixels4[offset];
  2655. if ((ff + pp) / 2 < aa.Item0)
  2656. aa.Item0 = ff;
  2657. else
  2658. aa.Item0 = pp;
  2659. }
  2660. if (value->Item1 > localThreshold)
  2661. {
  2662. toedit = true;
  2663. byte ff = pixels3[offset + 1];
  2664. byte pp = pixels4[offset + 1];
  2665. if ((ff + pp) / 2 < aa.Item1)
  2666. aa.Item1 = ff;
  2667. else
  2668. aa.Item1 = pp;
  2669. }
  2670. if (value->Item2 > localThreshold)
  2671. {
  2672. toedit = true;
  2673. byte ff = pixels3[offset + 2];
  2674. byte pp = pixels4[offset + 2];
  2675. if ((ff + pp) / 2 < aa.Item2)
  2676. aa.Item2 = ff;
  2677. else
  2678. aa.Item2 = pp;
  2679. }
  2680. if (toedit)
  2681. {
  2682. phaseTemp1.Set(position[0], position[1], aa);
  2683. }
  2684. }
  2685. public static List<int> CalcRepeatLines(List<int> line, Mat mat)
  2686. {
  2687. int value = 0;
  2688. List<int> temp = new List<int>();
  2689. //if (line.Count> 2 && mat.Row[line[line.Count - 1] + 9].CountNonZero() <= 300)
  2690. // line.RemoveAt(line.Count - 1);
  2691. for (int i=line.Count-1; i>=0; i--)
  2692. {
  2693. if(Math.Abs(line[i]-value)>=20)
  2694. {
  2695. value = line[i];
  2696. temp.Add(line[i]);
  2697. }
  2698. }
  2699. return temp;
  2700. }
  2701. public static Mat ImageSobel(Mat src)
  2702. {
  2703. Mat gray = null, xgrad = null, ygrad = null, output = null;
  2704. try
  2705. {
  2706. //转为灰度
  2707. gray = src.Clone();
  2708. //Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
  2709. MatType m = src.Type();
  2710. //求 X 和 Y 方向的梯度 Sobel and scharr
  2711. xgrad = new Mat();
  2712. ygrad = new Mat();
  2713. Cv2.Sobel(gray, xgrad, MatType.CV_16S, 1, 0, 3);
  2714. Cv2.Sobel(gray, ygrad, MatType.CV_16S, 0, 1, 3);
  2715. Cv2.ConvertScaleAbs(xgrad, xgrad);//缩放、计算绝对值并将结果转换为8位。不做转换的化显示不了,显示图相只能是8U类型
  2716. Cv2.ConvertScaleAbs(ygrad, ygrad);
  2717. //加强边缘检测
  2718. //Cv2.Scharr(gray, xgrad, -1, 1, 0, 3);
  2719. //Cv2.Scharr(gray, ygrad, -1, 0, 1, 3);
  2720. output = new Mat(xgrad.Size(), xgrad.Type());
  2721. //图像混合相加(基于权重 0.5)不精确
  2722. //Cv2.AddWeighted(xgrad, 0.5, ygrad, 0.5, 0, output);
  2723. //基于 算法 G=|Gx|+|Gy|
  2724. int width = xgrad.Cols;
  2725. int hight = xgrad.Rows;
  2726. //基于 G= (Gx*Gx +Gy*Gy)的开方根
  2727. for (int x = 0; x < hight; x++)
  2728. {
  2729. for (int y = 0; y < width; y++)
  2730. {
  2731. int xg = xgrad.At<byte>(x, y);
  2732. int yg = ygrad.At<byte>(x, y);
  2733. double v1 = Math.Pow(xg, 2);
  2734. double v2 = Math.Pow(yg, 2);
  2735. int val = (int)Math.Sqrt(v1 + v2);
  2736. if (val > 255) //确保像素值在 0 -- 255 之间
  2737. {
  2738. val = 255;
  2739. }
  2740. if (val < 0)
  2741. {
  2742. val = 0;
  2743. }
  2744. byte xy = (byte)val;
  2745. output.Set<byte>(x, y, xy);
  2746. }
  2747. }
  2748. output.CopyTo(src);
  2749. return src;
  2750. }
  2751. catch (Exception ex)
  2752. {
  2753. throw ex;
  2754. }
  2755. finally
  2756. {
  2757. if (gray != null) gray.Dispose();
  2758. if (xgrad != null) gray.Dispose();
  2759. if (ygrad != null) gray.Dispose();
  2760. if (output != null) gray.Dispose();
  2761. GC.Collect();
  2762. }
  2763. }
  2764. }
  2765. }