12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309 |
- using OpenCvSharp;
- using OpenCvSharp.XImgProc;
- using PaintDotNet.Adjust.BaseImage;
- using PaintDotNet.Base;
- using PaintDotNet.Base.Enum;
- using PaintDotNet.Base.Functionodel;
- using PaintDotNet.Base.CommTool;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Windows.Forms;
- namespace PaintDotNet.Adjust
- {
- /// <summary>
- /// 形态学处理
- /// </summary>
- public class MorphologyIntent
- {
- #region 腐蚀
- /// <summary>
- /// 腐蚀
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat ImageErosion(Mat mat, List<Args> lists)
- {
- int count = 1;
- Structure structure = Structure.horizon;
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "Count":
- count = int.Parse(args.Value.ToString());
- break;
- case "Structures":
- structure = (Structure)args.Value;
- break;
- default:
- break;
- }
- }
- Mat element = null;
- switch (structure)
- {
- case Structure.horizon:
- InputArray kernel1 = InputArray.Create<int>(new int[1, 3] { { 1, 1, 1 } });
- element = kernel1.GetMat();
- break;
- case Structure.angle45:
- InputArray kernel2 = InputArray.Create<int>(new int[3, 3] { { 0, 0, 1 }, { 0, 1, 0 }, { 1, 0, 0 } });
- element = kernel2.GetMat();
- break;
- case Structure.vertical:
- InputArray kernel3 = InputArray.Create<int>(new int[3, 1] { { 1 }, { 1 }, { 1 } });
- element = kernel3.GetMat();
- break;
- case Structure.angle135:
- InputArray kernel4 = InputArray.Create<int>(new int[3, 3] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } });
- element = kernel4.GetMat();
- break;
- case Structure.cross:
- element = Cv2.GetStructuringElement(MorphShapes.Cross, new Size(3, 3));
- break;
- case Structure.square:
- element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
- break;
- case Structure.octagon:
- InputArray kernel7 = InputArray.Create<int>(new int[7, 7] {
- { 0, 0, 1, 1, 1, 0, 0 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 0, 0, 1, 1, 1, 0, 0 }
- });
- element = kernel7.GetMat();
- break;
- }
- if (structure == Structure.conventional)
- {
- Cv2.Erode(mat, mat, null, null, count);
- }
- else
- {
- element.ConvertTo(element, MatType.CV_8UC1);
- Cv2.Erode(mat, mat, element, null, count, BorderTypes.Constant);
- if (element != null)
- {
- element.Dispose();
- }
- }
- return mat;
- }
- #endregion
- #region 膨胀
- /// <summary>
- /// 膨胀
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat ImageDilation(Mat mat, List<Args> lists)
- {
- int count = 1;
- Structure structure = Structure.horizon;
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "Count":
- count = int.Parse(args.Value.ToString());
- break;
- case "Structures":
- structure = (Structure)args.Value;
- break;
- default:
- break;
- }
- }
- Mat element = null;
- switch (structure)
- {
- case Structure.horizon:
- InputArray kernel1 = InputArray.Create<int>(new int[1, 3] { { 1, 1, 1 } });
- element = kernel1.GetMat();
- break;
- case Structure.angle45:
- InputArray kernel2 = InputArray.Create<int>(new int[3, 3] { { 0, 0, 1 }, { 0, 1, 0 }, { 1, 0, 0 } });
- element = kernel2.GetMat();
- break;
- case Structure.vertical:
- InputArray kernel3 = InputArray.Create<int>(new int[3, 1] { { 1 }, { 1 }, { 1 } });
- element = kernel3.GetMat();
- break;
- case Structure.angle135:
- InputArray kernel4 = InputArray.Create<int>(new int[3, 3] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } });
- element = kernel4.GetMat();
- break;
- case Structure.cross:
- element = Cv2.GetStructuringElement(MorphShapes.Cross, new Size(3, 3));
- break;
- case Structure.square:
- element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
- break;
- case Structure.octagon:
- InputArray kernel7 = InputArray.Create<int>(new int[7, 7] {
- { 0, 0, 1, 1, 1, 0, 0 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 0, 0, 1, 1, 1, 0, 0 }
- });
- element = kernel7.GetMat();
- break;
- }
- if (structure == Structure.conventional)
- {
- Cv2.Dilate(mat, mat, null, null, count);
- }
- else
- {
- element.ConvertTo(element, MatType.CV_8UC1);
- Cv2.Dilate(mat, mat, element, null, count, BorderTypes.Constant);
- }
- return mat;
- }
- #endregion
- #region 开运算
- /// <summary>
- /// 开运算
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat ImageOpen(Mat mat, List<Args> lists)
- {
- int count = 1;
- Structure structure = Structure.horizon;
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "Count":
- count = int.Parse(args.Value.ToString());
- break;
- case "Structures":
- structure = (Structure)args.Value;
- break;
- default:
- break;
- }
- }
- Mat element = null;
- switch (structure)
- {
- case Structure.horizon:
- InputArray kernel1 = InputArray.Create<int>(new int[1, 3] { { 1, 1, 1 } });
- element = kernel1.GetMat();
- break;
- case Structure.angle45:
- InputArray kernel2 = InputArray.Create<int>(new int[3, 3] { { 0, 0, 1 }, { 0, 1, 0 }, { 1, 0, 0 } });
- element = kernel2.GetMat();
- break;
- case Structure.vertical:
- InputArray kernel3 = InputArray.Create<int>(new int[3, 1] { { 1 }, { 1 }, { 1 } });
- element = kernel3.GetMat();
- break;
- case Structure.angle135:
- InputArray kernel4 = InputArray.Create<int>(new int[3, 3] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } });
- element = kernel4.GetMat();
- break;
- case Structure.cross:
- element = Cv2.GetStructuringElement(MorphShapes.Cross, new Size(3, 3));
- break;
- case Structure.square:
- element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
- break;
- case Structure.octagon:
- InputArray kernel7 = InputArray.Create<int>(new int[7, 7] {
- { 0, 0, 1, 1, 1, 0, 0 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 0, 0, 1, 1, 1, 0, 0 }
- });
- element = kernel7.GetMat();
- break;
- }
- if (structure == Structure.conventional)
- {
- Cv2.MorphologyEx(mat, mat, MorphTypes.Open, null, null, count, BorderTypes.Constant);
- }
- else
- {
- element.ConvertTo(element, MatType.CV_8UC1);
- Cv2.MorphologyEx(mat, mat, MorphTypes.Open, element, null, count, BorderTypes.Constant);
- if (element != null)
- {
- element.Dispose();
- }
- }
- return mat;
- }
- #endregion
- #region 闭运算
- /// <summary>
- /// 闭运算
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat ImageClose(Mat mat, List<Args> lists)
- {
- int count = 1;
- Structure structure = Structure.horizon;
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "Count":
- count = int.Parse(args.Value.ToString());
- break;
- case "Structures":
- structure = (Structure)args.Value;
- break;
- default:
- break;
- }
- }
- Mat element = null;
- switch (structure)
- {
- case Structure.horizon:
- InputArray kernel1 = InputArray.Create<int>(new int[1, 3] { { 1, 1, 1 } });
- element = kernel1.GetMat();
- break;
- case Structure.angle45:
- InputArray kernel2 = InputArray.Create<int>(new int[3, 3] { { 0, 0, 1 }, { 0, 1, 0 }, { 1, 0, 0 } });
- element = kernel2.GetMat();
- break;
- case Structure.vertical:
- InputArray kernel3 = InputArray.Create<int>(new int[3, 1] { { 1 }, { 1 }, { 1 } });
- element = kernel3.GetMat();
- break;
- case Structure.angle135:
- InputArray kernel4 = InputArray.Create<int>(new int[3, 3] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } });
- element = kernel4.GetMat();
- break;
- case Structure.cross:
- element = Cv2.GetStructuringElement(MorphShapes.Cross, new Size(3, 3));
- break;
- case Structure.square:
- element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
- break;
- case Structure.octagon:
- InputArray kernel7 = InputArray.Create<int>(new int[7, 7] {
- { 0, 0, 1, 1, 1, 0, 0 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1, 1, 1 },
- { 0, 1, 1, 1, 1, 1, 0 },
- { 0, 0, 1, 1, 1, 0, 0 }
- });
- element = kernel7.GetMat();
- break;
- }
- if (structure == Structure.conventional)
- {
- Cv2.MorphologyEx(mat, mat, MorphTypes.Close, null, null, count, BorderTypes.Constant);
- }
- else
- {
- element.ConvertTo(element, MatType.CV_8UC1);
- Cv2.MorphologyEx(mat, mat, MorphTypes.Close, element, null, count, BorderTypes.Constant);
- if (element != null)
- {
- element.Dispose();
- }
- }
- return mat;
- }
- #endregion
- #region 粗化/细化
- private static int GetArgCount(List<Args> lists)
- {
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- if (args.Key == "Count")
- {
- return int.Parse(args.Value.ToString());
- }
- }
- return 0;
- }
- /// <summary>
- /// 粗化,需要二值化的图像
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat Thickening(Mat mat, List<Args> lists, int color)
- {
- System.Drawing.Color color1 = System.Drawing.Color.FromArgb(color);
- Mat dstC1 = null;
- Mat dstC4 = null;
- Mat scrC1 = null;
- try
- {
- scrC1 = new Mat(mat.Size(), MatType.CV_8UC1);
- for (int o = 0; o < scrC1.Height; o++)
- for (int p = 0; p < scrC1.Width; p++)
- {
- var v = mat.At<Vec4b>(o, p).Item3;
- if (v == 0)
- {
- scrC1.Set(o, p, 255);
- }
- else
- {
- scrC1.Set(o, p, 0);
- }
- }
- //扩充图像边界,方便处理,最后在统一截掉
- var times = GetArgCount(lists);//细化执行次数
- Thinning(scrC1, out dstC1, times);
- dstC4 = new Mat(mat.Size(), OpenCvSharp.MatType.CV_8UC4);
- for (int o = 0; o < dstC1.Height; o++)
- {
- for (int p = 0; p < dstC1.Width; p++)
- {
- byte v = dstC1.At<byte>(o, p);
- if (v > 0)
- {
- dstC4.Set<Vec4b>(o, p, new Vec4b(0, 0, 0, 0));
- }
- else
- {
- dstC4.Set<Vec4b>(o, p, new Vec4b(color1.B, color1.G, color1.R, 255));
- }
- }
- }
- dstC4.CopyTo(mat);
- return mat;
- }
- catch (Exception)
- {
- return mat;
- }
- finally
- {
- if (dstC1 != null && !dstC1.IsDisposed) dstC1.Dispose();
- if (scrC1 != null && !scrC1.IsDisposed) scrC1.Dispose();
- if (dstC4 != null && !dstC4.IsDisposed) dstC4.Dispose();
- GC.Collect();
- }
- }
- /// <summary>
- /// 细化,需要黑白二值图
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat Thinning(Mat mat, List<Args> lists, int color)
- {
- System.Drawing.Color color1 = System.Drawing.Color.FromArgb(color);
- Mat dstC4 = null;
- Mat dstC1 = null;
- Mat scrC1 = null;
- try
- {
- scrC1 = new Mat(mat.Size(), MatType.CV_8UC1);
- for (int o = 0; o < scrC1.Height; o++)
- for (int p = 0; p < scrC1.Width; p++)
- {
- var v = mat.At<Vec4b>(o, p).Item3;
- if (v > 0)
- {
- scrC1.Set(o, p, 255);
- }
- else
- {
- scrC1.Set(o, p, 0);
- }
- }
- var times = GetArgCount(lists);//细化执行次数
- Thinning(scrC1, out dstC1, times);
- dstC4 = new Mat(mat.Size(), OpenCvSharp.MatType.CV_8UC4);
- for (int o = 0; o < mat.Height; o++)
- {
- for (int p = 0; p < mat.Width; p++)
- {
- byte v = dstC1.At<byte>(o, p);
- if (v > 0)
- {
- dstC4.Set<Vec4b>(o, p, new Vec4b(color1.B, color1.G, color1.R, 255));
- }
- else
- {
- dstC4.Set<Vec4b>(o, p, new Vec4b(0, 0, 0, 0));
- }
- }
- }
- dstC4.CopyTo(mat);
- return mat;
- }
- catch (Exception)
- {
- return mat;
- }
- finally
- {
- if (dstC4 != null && !dstC4.IsDisposed) dstC4.Dispose();
- if (dstC1 != null && !dstC1.IsDisposed) dstC1.Dispose();
- if (scrC1 != null && !scrC1.IsDisposed) scrC1.Dispose();
- }
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="src"> Source 8-bit single-channel image, containing binary blobs, with blobs having</param>
- /// <returns>Destination image of the same size and the same type as src. The function can</returns>
- private static unsafe int Thinning(Mat src, out Mat dst, int times = 0)
- {
- int i, j, n;
- int width, height;
- int count = 0;
- int edge = 2;
- //之所以减1,是方便处理8邻域,防止越界
- int p2, p3, p4, p5, p6, p7, p8, p9;
- byte* img;
- bool ifEnd;
- var temp = new Mat(new OpenCvSharp.Size(src.Width + 2 * edge, src.Height + 2 * edge), MatType.CV_8U);
- Cv2.CopyMakeBorder(src, temp, edge, edge, edge, edge, BorderTypes.Constant, Scalar.All(255));
- dst = temp;
- int step = (int)dst.Step();
- int[] dir = new int[4] { -step, step, 1, -1 };
- width = dst.Cols - 2;
- height = dst.Rows - 2;
- using (Mat tmpimg = new Mat())
- {
- do
- {
- count++;
- //分四个子迭代过程,分别对应北,南,东,西四个边界点的情况
- ifEnd = false;
- for (n = 0; n < 4; n++)
- {
- dst.CopyTo(tmpimg);
- img = tmpimg.DataPointer;
- for (i = 1; i < height; i++)
- {
- img += step;
- for (j = 1; j < width; j++)
- {
- byte* p = img + j;
- //如果p点是背景点或者且为方向边界点,依次为北南东西,继续循环
- if (p[0] == 0 || p[dir[n]] > 0) continue;
- p2 = p[-step] > 0 ? 1 : 0;
- p3 = p[-step + 1] > 0 ? 1 : 0;
- p4 = p[1] > 0 ? 1 : 0;
- p5 = p[step + 1] > 0 ? 1 : 0;
- p6 = p[step] > 0 ? 1 : 0;
- p7 = p[step - 1] > 0 ? 1 : 0;
- p8 = p[-1] > 0 ? 1 : 0;
- p9 = p[-step - 1] > 0 ? 1 : 0;
- int adjsum;
- adjsum = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
- //判断是否是邻接点或孤立点,0,1分别对于那个孤立点和端点
- if (adjsum > 1)
- {
- //8 simple判定
- int is8simple = 1;
- if ((p2 == 0 && p6 == 0) && ((p9 == 1 || p8 == 1 || p7 == 1) && (p3 == 1 || p4 == 1 || p5 == 1)))
- is8simple = 0;
- else if ((p4 == 0 && p8 == 0) && ((p9 == 1 || p2 == 1 || p3 == 1) && (p5 == 1 || p6 == 1 || p7 == 1)))
- is8simple = 0;
- else if ((p8 == 0 && p2 == 0) && (p9 == 1 && (p3 == 1 || p4 == 1 || p5 == 1 || p6 == 1 || p7 == 1)))
- is8simple = 0;
- else if ((p4 == 0 && p2 == 0) && (p3 == 1 && (p5 == 1 || p6 == 1 || p7 == 1 || p8 == 1 || p9 == 1)))
- is8simple = 0;
- else if ((p8 == 0 && p6 == 0) && (p7 == 1 && (p3 == 9 || p2 == 1 || p3 == 1 || p4 == 1 || p5 == 1)))
- is8simple = 0;
- else if ((p4 == 0 && p6 == 0) && (p5 == 1 && (p7 == 1 || p8 == 1 || p9 == 1 || p2 == 1 || p3 == 1)))
- is8simple = 0;
- if (is8simple == 1)
- {
- dst.Set<byte>(i, j, 0); //满足删除条件,设置当前像素为0
- ifEnd = true;
- }
- }
- }
- }
- }
- } while (ifEnd && (times == 0 || count < times));//已经没有可以细化的像素了,则退出迭代
- }
- dst = new Mat(dst, new Rect(edge, edge, src.Width, src.Height));
- return count;
- }
- /// <summary>
- /// OpenCV's Thinning
- /// </summary>
- private static Mat ThinningCv(Mat src)
- {
- Mat dst = new Mat(src.Size(), src.Type());
- Mat[] arr = src.Split();
- CvXImgProc.Thinning(arr[0], dst, ThinningTypes.ZHANGSUEN);
- return dst;
- }
- #endregion
- #region 划痕处理 & 污迹处理
- /// <summary>
- /// 污迹处理
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <param name="mask">除了需要修复的部分之外其他部分的像素值全部为0</param>
- /// <returns></returns>
- public static Mat SmudgeTreatment(Mat mat, List<Args> lists, Mat mask)
- {
- //获取通道数量
- int channels = mat.Channels();
- //如果是四通道转成三通道
- if (channels == 4)
- OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.BGRA2BGR);
- //处理因子
- double inpaintRadius = 5.0;
- //读取参数信息
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "InpaintRadius":
- inpaintRadius = double.Parse(args.Value.ToString());
- break;
- }
- }
- Mat matCopy = mat.Clone();
- //图像修复
- Cv2.Inpaint(mat, mask, matCopy, inpaintRadius, InpaintMethod.Telea);
- //如果原图是四通道,将处理完之后mat转为四通道
- if (channels == 4)
- OpenCvSharp.Cv2.CvtColor(matCopy, matCopy, OpenCvSharp.ColorConversionCodes.BGR2BGRA);
- return matCopy;
- }
- /// <summary>
- /// 划痕处理
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <param name="mask">除了需要修复的部分之外其他部分的像素值全部为0</param>
- /// <returns></returns>
- public static Mat ScratchTreatment(Mat mat, List<Args> lists, Mat mask)
- {
- //获取通道数量
- int channels = mat.Channels();
- //如果是四通道转成三通道
- if (channels == 4)
- OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.BGRA2BGR);
- Mat matCopy = mat.Clone();
- ////痕宽
- //double inpaintRadius = 5.0;
- ////读取参数信息
- //for (int i = 0; i < lists.Count; i++)
- //{
- // Args args = lists[i];
- // switch (args.Key)
- // {
- // case "InpaintRadius":
- // inpaintRadius = double.Parse(args.Value.ToString());
- // break;
- // }
- //}
- //Cv2.ImShow("mat", mat);
- //图像修复
- Cv2.Inpaint(mat, mask, matCopy/*, inpaintRadius*/, 5.0, InpaintMethod.Telea);
- //Cv2.ImShow("matCopy", matCopy);
- //如果原图是四通道,将处理完之后mat转为四通道
- if (channels == 4)
- OpenCvSharp.Cv2.CvtColor(matCopy, matCopy, OpenCvSharp.ColorConversionCodes.BGR2BGRA);
- return matCopy;
- }
- #endregion
- #region 分水岭分割
- /** the following constants are used to set bits corresponding to pixel types */
- static byte MAXIMUM = (byte)1; // marks local maxima (irrespective of noise tolerance)
- static byte LISTED = (byte)2; // marks points currently in the list
- static byte PROCESSED = (byte)4; // marks points processed previously
- static byte MAX_AREA = (byte)8; // marks areas near a maximum, within the tolerance
- //static byte EQUAL = (byte)16; // marks contigous maximum points of equal level
- //static byte MAX_POINT = (byte)32; // marks a single point standing for a maximum
- static byte ELIMINATED = (byte)64; // marks maxima that have been eliminated before watershed
- /// <summary>
- /// 分水岭分割
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat WatershedSegment(Mat mat, PhaseModel phase, List<Args> lists)
- {
- //中间变量
- //Mat temp = new Mat();
- int paramCount = 0;
- //读取参数信息
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "Count":
- paramCount = int.Parse(args.Value.ToString());
- break;
- }
- }
- //灰度图
- Mat Inmat = phase.mat.CvtColor(ColorConversionCodes.BGR2GRAY);
- int width = Inmat.Width;
- int height = Inmat.Height;
- Mat distance_temp = new Mat();
- //Cv2.ImShow("Inmat", Inmat);
- Cv2.DistanceTransform(Inmat, distance_temp, DistanceTypes.L2, DistanceMaskSize.Precise);
- //Mat dst_temp = new Mat();
- //Cv2.Normalize(src_temp, dst_temp, 0, 255, NormTypes.MinMax);
- //Mat dst = new Mat();
- //dst_temp.ConvertTo(dst, MatType.CV_8UC1);
- //Cv2.ImShow("DistanceTransform", dst);
- //getSortedMaxPoints............
- BitMap2d ip = new BitMap2d(distance_temp);
- MaximunFinder maximunFinder = new MaximunFinder(ip);
- List<Int16DoubleWithValue> maxPoints = maximunFinder.FindMaxima();
- //AnalyzeAndMarkMaxima.............
- BitMap2d types = new BitMap2d(width, height, 0);
- float globalMin = float.MaxValue;
- float globalMax = float.MinValue;
- foreach (Int16DoubleWithValue item in maxPoints)
- {
- if (item.V < globalMin) globalMin = item.V;
- if (item.V > globalMax) globalMax = item.V;
- types.SetPixel(item.O, MAXIMUM);
- }
- int nMax = maxPoints.Count();
- int[] pList = new int[width * height]; //here we enter points starting from a maximum
- int[] dirOffset = new int[] { -width, -width + 1, +1, +width + 1, +width, +width - 1, -1, -width - 1 };
- float maxSortingError = (float)(1.1 * (Math.Sqrt(2) / 2));//sorted sequence may be inaccurate by this value
- float tolerance = (float)0.5;// 05;
- for (int iMax = nMax - 1; iMax >= 0; iMax--)
- { //process all maxima now, starting from the highest
- int offset0 = maxPoints[iMax].O;
- if (((byte)types.GetPixel(offset0) & PROCESSED) != 0) //this maximum has been reached from another one, skip it
- continue;
- float v0 = ip.GetPixel(offset0);
- Boolean sortingError = false;
- do
- {
- pList[0] = offset0;
- types.SetPixel(offset0, (byte)((byte)types.GetPixel(offset0) | LISTED)); //mark first point as equal height (to itself) and listed
- int listLen = 1; //number of elements in the list
- int listI = 0; //index of current element in the list
- sortingError = false;
- Boolean maxPossible = true; //it may be a true maximum
- do
- { //while neigbor list is not fully processed (to listLen)
- int offset = pList[listI];
- int x = offset % width;
- int y = offset / width;
- Boolean isInner = (y != 0 && y != height - 1) && (x != 0 && x != width - 1); //not necessary, but faster than isWithin
- for (int d = 0; d < 8; d++)
- { //analyze all neighbors (in 8 directions) at the same level
- int offset2 = offset + dirOffset[d];
- if ((isInner || isWithin(x, y, d, width, height)) && ((byte)types.GetPixel(offset2) & LISTED) == 0)
- {
- float v2 = ip.GetPixel(offset2);
- if (ip.GetPixel(offset2) <= 0)
- {
- continue; //ignore the background (non-particles)
- }
- if (((byte)types.GetPixel(offset2) & PROCESSED) != 0)
- {
- maxPossible = false; //we have reached a point processed previously, thus it is no maximum now
- break;
- }
- if (v2 > v0 + maxSortingError)
- {
- maxPossible = false; //we have reached a higher point, thus it is no maximum
- break;
- }
- else if (v2 >= v0 - tolerance)
- {
- if (v2 > v0)
- {
- sortingError = true;
- offset0 = offset2;
- v0 = v2;
- }
- pList[listLen] = offset2;
- listLen++; //we have found a new point within the tolerance
- types.SetPixel(offset2, (byte)((byte)types.GetPixel(offset2) | LISTED));
- }
- } // if isWithin & not LISTED
- } // for directions d
- listI++;
- } while (listI < listLen);
- if (sortingError)
- { //if x0,y0 was not the true maximum but we have reached a higher one
- for (listI = 0; listI < listLen; listI++)
- types.SetPixel(pList[listI], (byte)0); //reset all points encountered, then retry
- }
- else
- {
- //...............................................................................//
- int resetMask = ~LISTED;
- for (listI = 0; listI < listLen; listI++)
- {
- int offset = pList[listI];
- types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) & resetMask)); //reset attributes no longer needed
- types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | PROCESSED)); //mark as processed
- if (maxPossible)
- {
- types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | MAX_AREA)); //reset attributes no longer needed
- }
- } // for listI
- }
- }
- while (sortingError);
- }// for all maxima iMax
- //if (nMax == 0) //no initial maxima at all? then consider all as 'within tolerance'
- // Arrays.fill(types, (byte)(PROCESSED | MAX_AREA));
- //makeUEPs:::
- double threshold = 0.5;
- //make8bit............
- double offset01 = globalMin - (globalMax - globalMin) * (1.0 / 253 / 2 - 1e-6); //everything above minValue should become >(byte)0
- double factor = 253 / (globalMax - globalMin);
- BitMap2d pixels = new BitMap2d(width, height, 0);
- int dataLen = height * width;
- for (int offset = 0; offset < dataLen; offset++)
- {
- float rawValue = ip.GetPixel(offset);
- if (rawValue < threshold) { }
- else if (((byte)types.GetPixel(offset) & MAX_AREA) != 0)
- pixels.SetPixel(offset, (byte)255); //prepare watershed by setting "true" maxima+surroundings to 255
- else
- {
- long v = (long)(1 + Math.Round((rawValue - offset01) * factor));
- if (v < 1) pixels.SetPixel(offset, (byte)1);
- else if (v <= 254) pixels.SetPixel(offset, (byte)(v & 255));
- else pixels.SetPixel(offset, (byte)254);
- }
- }
- //cleanupMaxima............
- for (int iMax = nMax - 1; iMax >= 0; iMax--)
- {
- int offset0 = maxPoints[iMax].O; //type cast gets lower 32 bits where pixel offset is encoded
- if (((int)types.GetPixel(offset0) & (MAX_AREA | ELIMINATED)) != 0) continue;
- int level = (byte)pixels.GetPixel(offset0) & 255;
- int loLevel = level + 1;
- pList[0] = offset0; //we start the list at the current maximum
- types.SetPixel(offset0, (byte)((byte)types.GetPixel(offset0) | LISTED)); //mark first point as listed
- int listLen = 1; //number of elements in the list
- int lastLen = 1;
- int listI = 0; //index of current element in the list
- Boolean saddleFound = false;
- while (!saddleFound && loLevel > 0)
- {
- loLevel--;
- lastLen = listLen; //remember end of list for previous level
- listI = 0; //in each level, start analyzing the neighbors of all pixels
- do
- { //for all pixels listed so far
- int offset = pList[listI];
- int x = offset % width;
- int y = offset / width;
- Boolean isInner = (y != 0 && y != height - 1) && (x != 0 && x != width - 1); //not necessary, but faster than isWithin
- for (int d = 0; d < 8; d++)
- { //analyze all neighbors (in 8 directions) at the same level
- int offset2 = offset + dirOffset[d];
- if ((isInner || isWithin(x, y, d, width, height)) && ((byte)types.GetPixel(offset2) & LISTED) == 0)
- {
- if (((byte)types.GetPixel(offset2) & MAX_AREA) != 0 || ((((byte)types.GetPixel(offset2) & ELIMINATED) != 0) && ((byte)pixels.GetPixel(offset2) & 255) >= loLevel))
- {
- saddleFound = true; //we have reached a point touching a "true" maximum...
- break; //...or a level not lower, but touching a "true" maximum
- }
- else if (((byte)pixels.GetPixel(offset2) & 255) >= loLevel && ((byte)types.GetPixel(offset2) & ELIMINATED) == 0)
- {
- pList[listLen] = offset2;
- listLen++; //we have found a new point to be processed
- types.SetPixel(offset2, (byte)((byte)types.GetPixel(offset2) | LISTED));
- }
- } // if isWithin & not LISTED
- } // for directions d
- if (saddleFound) break; //no reason to search any further
- listI++;
- } while (listI < listLen);
- } // while !levelFound && loLevel>=0
- for (listI = 0; listI < listLen; listI++) //reset attribute since we may come to this place again
- types.SetPixel(pList[listI], (byte)((byte)types.GetPixel(pList[listI]) & ~LISTED));
- for (listI = 0; listI < lastLen; listI++)
- { //for all points higher than the level of the saddle point
- int offset = pList[listI];
- pixels.SetPixel(offset, (byte)loLevel); //set pixel value to the level of the saddle point
- types.SetPixel(offset, (byte)((byte)types.GetPixel(offset) | ELIMINATED)); //mark as processed: there can't be a local maximum in this area
- }
- } // for all maxima iMax
- //watershedSegment
- int[] histogram = new int[256];
- for (int v1 = 0; v1 < 255; v1++)
- {
- histogram[v1] = 0;
- }
- for (int offset = 0; offset < dataLen; offset++)
- {
- int v1 = (byte)pixels.GetPixel(offset) & 255;
- if (v1 > 0 && v1 < 255)
- {
- histogram[v1]++;
- }
- }
- int arraySize = width * height - histogram[0] - histogram[255];
- int[] coordinates = new int[arraySize]; //from pixel coordinates, low bits x, high bits y
- int highestValue = 0;
- int maxBinSize = 0;
- int offset02 = 0;
- int[] levelStart = new int[256];
- for (int v1 = 1; v1 < 255; v1++)
- {
- levelStart[v1] = offset02;
- offset02 += histogram[v1];
- if (histogram[v1] > 0) highestValue = v1;
- if (histogram[v1] > maxBinSize) maxBinSize = histogram[v1];
- }
- int[] levelOffset = new int[highestValue + 1];
- for (int y = 0, i = 0; y < height; y++)
- {
- for (int x = 0; x < width; x++, i++)
- {
- int v1 = (byte)pixels.GetPixel(i) & 255;
- if (v1 > 0 && v1 < 255)
- {
- offset02 = levelStart[v1] + levelOffset[v1];
- coordinates[offset02] = x + y * width;
- levelOffset[v1]++;
- }
- } //for x
- } //for y
- // Create an array of the points (pixel offsets) that we set to 255 in one pass.
- // If we remember this list we need not create a snapshot of the ImageProcessor.
- int[] setPointList = new int[Math.Min(maxBinSize, (width * height + 2) / 3)];
- // now do the segmentation, starting at the highest level and working down.
- // At each level, dilate the particle (set pixels to 255), constrained to pixels
- // whose values are at that level and also constrained (by the fateTable)
- // to prevent features from merging.
- int[] table = makeFateTable();
- //IJ.showStatus("Segmenting (Esc to cancel)");
- /*final */
- int[] directionSequence = new int[] { 7, 3, 1, 5, 0, 4, 2, 6 }; // diagonal directions first
- for (int level = highestValue; level >= 1; level--)
- {
- int remaining = histogram[level]; //number of points in the level that have not been processed
- int idle = 0;
- while (remaining > 0 && idle < 8)
- {
- int sumN = 0;
- int dIndex = 0;
- do
- { // expand each level in 8 directions
- int n = processLevel(directionSequence[dIndex % 8], pixels, table,
- levelStart[level], remaining, coordinates, setPointList, width, height);
- //IJ.log("level="+level+" direction="+directionSequence[dIndex%8]+" remain="+remaining+"-"+n);
- remaining -= n; // number of points processed
- sumN += n;
- if (n > 0) idle = 0; // nothing processed in this direction?
- dIndex++;
- } while (remaining > 0 && idle++ < 8);
- }
- if (remaining > 0 && level > 1)
- { // any pixels that we have not reached?
- int nextLevel = level; // find the next level to process
- do
- nextLevel--;
- while (nextLevel > 1 && histogram[nextLevel] == 0);
- // in principle we should add all unprocessed pixels of this level to the
- // tasklist of the next level. This would make it very slow for some images,
- // however. Thus we only add the pixels if they are at the border (of the
- // image or a thresholded area) and correct unprocessed pixels at the very
- // end by CleanupExtraLines
- if (nextLevel > 0)
- {
- int newNextLevelEnd = levelStart[nextLevel] + histogram[nextLevel];
- for (int i = 0, p = levelStart[level]; i < remaining; i++, p++)
- {
- int pOffset = coordinates[p];
- int x = pOffset % width;
- int y = pOffset / width;
- //if ((pixels[pOffset] & 255) == 255) IJ.log("ERROR");
- Boolean addToNext = false;
- if (x == 0 || y == 0 || x == width - 1 || y == height - 1)
- addToNext = true; //image border
- else for (int d = 0; d < 8; d++)
- if (isWithin(x, y, d, width, height) && pixels.GetPixel(pOffset + dirOffset[d]) == 0)
- {
- addToNext = true; //border of area below threshold
- break;
- }
- if (addToNext)
- coordinates[newNextLevelEnd++] = pOffset;
- }
- //tasklist for the next level to process becomes longer by this:
- histogram[nextLevel] = newNextLevelEnd - levelStart[nextLevel];
- }
- }
- }
- System.Drawing.Color color = System.Drawing.Color.FromArgb(phase.color);
- Mat matPixels = OpenCvSharp.Extensions.BitmapConverter.ToMat(pixels.MakeBmp());
- for (int h = 0; h < matPixels.Height; h++)
- {
- for (int w = 0; w < matPixels.Width; w++)
- {
- if (matPixels.At<byte>(h, w) == 0)
- matPixels.Set<Vec4b>(h, w, new Vec4b(color.B, color.G, color.R, 255));
- else
- matPixels.Set<Vec4b>(h, w, new Vec4b(0, 0, 0, 0));
- }
- }
- return matPixels;
- }
- /** returns whether the neighbor in a given direction is within the image
- * NOTE: it is assumed that the pixel x,y itself is within the image!
- * Uses class variables width, height: dimensions of the image
- * @param x x-coordinate of the pixel that has a neighbor in the given direction
- * @param y y-coordinate of the pixel that has a neighbor in the given direction
- * @param direction the direction from the pixel towards the neighbor (see makeDirectionOffsets)
- * @return true if the neighbor is within the image (provided that x, y is within)
- */
- public static Boolean isWithin(int x, int y, int direction, int width, int height)
- {
- int xmax = width - 1;
- int ymax = height - 1;
- switch (direction)
- {
- case 0:
- return (y > 0);
- case 1:
- return (x < xmax && y > 0);
- case 2:
- return (x < xmax);
- case 3:
- return (x < xmax && y < ymax);
- case 4:
- return (y < ymax);
- case 5:
- return (x > 0 && y < ymax);
- case 6:
- return (x > 0);
- case 7:
- return (x > 0 && y > 0);
- }
- return false; //to make the compiler happy :-)
- } // isWithin
- /** dilate the UEP on one level by one pixel in the direction specified by step, i.e., set pixels to 255
- * @param pass gives direction of dilation, see makeFateTable
- * @param ip the EDM with the segmeted blobs successively getting set to 255
- * @param table The fateTable
- * @param levelStart offsets of the level in pixelPointers[]
- * @param levelNPoints number of points in the current level
- * @param pixelPointers[] list of pixel coordinates (x+y*width) sorted by level (in sequence of y, x within each level)
- * @param xCoordinates list of x Coorinates for the current level only (no offset levelStart)
- * @return number of pixels that have been changed
- */
- public static int processLevel(int pass, BitMap2d pixels, int[] fateTable,
- int levelStart, int levelNPoints, int[] coordinates, int[] setPointList, int width, int height)
- {
- int xmax = width - 1;
- int ymax = height - 1;
- //byte[] pixels = (byte[])ip.getPixels();
- ////byte[] pixels2 = (byte[])ip2.getPixels();
- int nChanged = 0;
- int nUnchanged = 0;
- for (int i = 0, p = levelStart; i < levelNPoints; i++, p++)
- {
- int offset = coordinates[p];
- int x = offset % width;
- int y = offset / width;
- int index = 0; //neighborhood pixel ocupation: index in fateTable
- if (y > 0 && ((byte)pixels.GetPixel(offset - width) & 255) == 255)
- index ^= 1;
- if (x < xmax && y > 0 && ((byte)pixels.GetPixel(offset - width + 1) & 255) == 255)
- index ^= 2;
- if (x < xmax && ((byte)pixels.GetPixel(offset + 1) & 255) == 255)
- index ^= 4;
- if (x < xmax && y < ymax && ((byte)pixels.GetPixel(offset + width + 1) & 255) == 255)
- index ^= 8;
- if (y < ymax && ((byte)pixels.GetPixel(offset + width) & 255) == 255)
- index ^= 16;
- if (x > 0 && y < ymax && ((byte)pixels.GetPixel(offset + width - 1) & 255) == 255)
- index ^= 32;
- if (x > 0 && ((byte)pixels.GetPixel(offset - 1) & 255) == 255)
- index ^= 64;
- if (x > 0 && y > 0 && ((byte)pixels.GetPixel(offset - width - 1) & 255) == 255)
- index ^= 128;
- int mask = 1 << pass;
- if ((fateTable[index] & mask) == mask)
- setPointList[nChanged++] = offset; //remember to set pixel to 255
- else
- coordinates[levelStart + (nUnchanged++)] = offset; //keep this pixel for future passes
- } // for pixel i
- //IJ.log("pass="+pass+", changed="+nChanged+" unchanged="+nUnchanged);
- for (int i = 0; i < nChanged; i++)
- pixels.SetPixel(setPointList[i], (byte)255);
- return nChanged;
- } //processLevel
- static public int[] makeFateTable()
- {
- int[] table = new int[256];
- Boolean[] isSet = new Boolean[8];
- for (int item = 0; item < 256; item++)
- { //dissect into pixels
- for (int i = 0, mask = 1; i < 8; i++)
- {
- isSet[i] = (item & mask) == mask;
- mask *= 2;
- }
- for (int i = 0, mask = 1; i < 8; i++)
- { //we dilate in the direction opposite to the direction of the existing neighbors
- if (isSet[(i + 4) % 8]) table[item] |= mask;
- mask *= 2;
- }
- for (int i = 0; i < 8; i += 2) //if side pixels are set, for counting transitions it is as good as if the adjacent edges were also set
- if (isSet[i])
- {
- isSet[(i + 1) % 8] = true;
- isSet[(i + 7) % 8] = true;
- }
- int transitions = 0;
- for (int i = 0; i < 8; i++)
- {
- if (isSet[i] != isSet[(i + 1) % 8])
- transitions++;
- }
- if (transitions >= 4)
- { //if neighbors contain more than one region, dilation ito this pixel is forbidden
- table[item] = 0;
- }
- else
- {
- }
- }
- return table;
- } // int[] makeFateTable
- /// <summary>
- /// 分水岭分割
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat WatershedSegment(Mat mat, List<Args> lists)
- {
- //中间变量
- //Mat temp = new Mat();
- int paramCount = 0;
- //读取参数信息
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "Count":
- paramCount = int.Parse(args.Value.ToString());
- break;
- }
- }
- //灰度图
- Mat Inmat = mat.CvtColor(ColorConversionCodes.BGR2GRAY);
- //BGR
- Mat Src_3 = mat.CvtColor(ColorConversionCodes.BGRA2BGR);// .Clone();
- //二值图
- Mat mat_bw = GetBW(Inmat);
- //Cv2.ImShow("mat_bw00", mat_bw);
- Mat result = Oper_Deal(mat_bw, Src_3);
- //mat.CopyTo(temp);
- return result;// temp;
- }
- private static Mat Oper_Deal(Mat ImIn, Mat src_3)
- {
- #region 距离变换
- Mat Im1 = new Mat(ImIn.Size(), ImIn.Type());
- //归一化
- Cv2.Normalize(ImIn, Im1, 0, 1, NormTypes.MinMax);
- Mat Im_dis = new Mat(ImIn.Size(), MatType.CV_32FC1);
- Cv2.DistanceTransform(ImIn, Im_dis, DistanceTypes.L2, DistanceMaskSize.Precise);
- Cv2.Normalize(Im_dis, Im_dis, 0, 1, NormTypes.MinMax);
- Mat conv = new Mat(Im_dis.Size(), MatType.CV_8UC1);
- Im_dis.ConvertTo(conv, MatType.CV_8UC1);
- Cv2.Threshold(conv, conv, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
- #endregion
- #region 轮廓标记
- Mat dis_8U = conv;
- //提取标记
- Point[][] contours; HierarchyIndex[] hierarchy;
- Cv2.FindContours(dis_8U, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new Point());
- #endregion
- #region 将标记存入markers,作分水岭注水点用
- var markers = new Mat(ImIn.Size(), MatType.CV_32SC1, Scalar.All(0));
- for (int i = 0; i < contours.Length; i++)
- {
- Cv2.DrawContours(markers, contours, i, Scalar.All(i + 1), 10, LineTypes.Link8, hierarchy);
- }
- #endregion
- Cv2.Watershed(src_3, markers);
- #region 分水岭结果图处理
- //连通域为1,线条为0
- var markers_ind = markers.GetGenericIndexer<int>();
- for (int i = 0; i < markers.Rows; i++)
- {
- for (int j = 0; j < markers.Cols; j++)
- {
- if (markers_ind[i, j] != -1)
- {
- markers_ind[i, j] = int.MaxValue;
- }
- else if (markers_ind[i, j] == -1)
- {
- markers_ind[i, j] = 0;
- }
- }
- }
- //结合初始二值图背景为0
- var ImIn_ind = ImIn.GetGenericIndexer<byte>();
- for (int i = 0; i < markers.Rows; i++)
- {
- for (int j = 0; j < markers.Cols; j++)
- {
- if (ImIn_ind[i, j] == 0)
- {
- markers_ind[i, j] = 0;
- }
- }
- }
- #endregion
- #region 连通域信息
- Mat water = new Mat(markers.Size(), MatType.CV_8UC1);
- markers.ConvertTo(water, MatType.CV_8UC1);
- var water_ind = water.GetGenericIndexer<byte>();
- Mat water_bw = new Mat();
- Cv2.Threshold(water, water_bw, 0, 255, ThresholdTypes.Otsu);
- //连通图的信息获取
- Mat labels = new Mat(); Mat stats = new Mat(); Mat centroids = new Mat();
- int num = Cv2.ConnectedComponentsWithStats(water_bw, labels, stats, centroids);
- #endregion
- #region
- Vec3b[] color = new Vec3b[num + 1];
- color[0] = new Vec3b(0, 0, 0);
- var stats_ind = stats.GetGenericIndexer<int>();
- Random rand = new Random();
- byte ranB = (byte)rand.Next(100, 255); byte ranG = (byte)rand.Next(100, 255); byte ranR = (byte)rand.Next(100, 255);
- for (int i = 1; i < num; i++)
- {
- color[i] = new Vec3b(ranB, ranG, ranR);
- int S = stats_ind[i, 4];
- if (S < 200)
- {
- color[i] = new Vec3b(0, 0, 0);
- }
- }
- #endregion
- #region mat填色
- Mat final = new Mat(water.Size(), MatType.CV_8UC3);
- for (int i = 0; i < final.Rows; i++)
- {
- for (int j = 0; j < final.Cols; j++)
- {
- int label = labels.Get<int>(i, j);
- final.Set<Vec3b>(i, j, color[label]);
- }
- }
- #endregion
- return final;
- }
- private static Mat GetBW(Mat Src)
- {
- //(最大类间方差)二值化
- //Mat result = Src.Threshold(109.242, 255, ThresholdTypes.Otsu);
- Mat result = Src.AdaptiveThreshold(255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 35, 5);
- //Cv2.ImShow("test", result); Cv2.WaitKey();
- return result;
- }
- #endregion
- #region 去碎屑
- /// <summary>
- /// 去碎屑(功能实际是颗粒筛选的功能)
- /// 需要传进来二值的图
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat Debris(Mat mat, List<Args> lists, int color, double rule)
- {
- //相颜色
- System.Drawing.Color color1 = System.Drawing.Color.FromArgb(color);
- //原始轮廓信息
- OpenCvSharp.Point[][] contours;
- //轮廓的拓扑信息
- HierarchyIndex[] hierachy;
- //筛选参数
- FilterParameters filterParameters = FilterParameters.Area;
- //筛选范围
- double min = 0, max = 0;
- //筛选单位
- MeasurementUnit measurementUnit = MeasurementUnit.Pixel;
- //筛选单方式
- FunctionParameters functionParameters = FunctionParameters.Choise;
- //边界保留
- bool boundaryPreservation = false;
- //中间变量
- Mat temp = new Mat();
- //轮廓总面积
- //double areas = 0;
- //删除的边界
- List<int> deleteIndexs = new List<int>();
- //读取参数信息
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "FilterParameters":
- filterParameters = (FilterParameters)args.Value;
- break;
- case "Scope":
- min = ((List<double>)args.Value)[0];
- max = ((List<double>)args.Value)[1];
- break;
- case "UnitParameters":
- measurementUnit = (MeasurementUnit)args.Value;
- break;
- case "FunctionParameters":
- functionParameters = (FunctionParameters)args.Value;
- break;
- case "BoundaryPreservation":
- boundaryPreservation = (bool)args.Value;
- break;
- }
- }
- mat.CopyTo(temp);
- Cv2.FindContours(mat.CvtColor(ColorConversionCodes.BGR2GRAY), out contours, out hierachy, RetrievalModes.CComp, ContourApproximationModes.ApproxNone);
- //没有选中边界保留
- if (!boundaryPreservation)
- {
- if (contours.Length > 0)
- {
- for (int i = 0; i < contours.Length; i++)
- {
- for (int y = 0; y < contours[i].Length; y++)
- {
- if (contours[i][y].X == 0 || contours[i][y].X == temp.Width - 1 || contours[i][y].Y == 0 || contours[i][y].Y == temp.Height - 1)
- {
- deleteIndexs.Add(i);
- List<OpenCvSharp.Point[]> pointsTemp = new List<OpenCvSharp.Point[]>();
- RecursiveFindChildContours(contours.ToList(), hierachy, i, deleteIndexs);
- break;
- }
- }
- }
- }
- //用于绘制的轮廓
- List<OpenCvSharp.Point[]> drawContours = contours.ToList<OpenCvSharp.Point[]>();
- //循环处理轮廓,过滤到被删除的轮廓及其子轮廓
- if (deleteIndexs.Count > 0)
- {
- drawContours.Clear();
- for (int i = 0; i < contours.Length; i++)
- {
- if (!deleteIndexs.Exists(a => a == i))// && !deleteIndexs.Exists(a => a == hierachy[i].Parent)
- {
- drawContours.Add(contours[i]);
- }
- }
- }
- temp = new Mat(mat.Size(), mat.Type());
- Cv2.FillPoly(temp, drawContours, new Scalar(color1.B, color1.G, color1.R, 255), LineTypes.Link8);
- }
- /*//计算总面积
- foreach (Point[] points in contours)
- {
- areas += Math.Abs(Cv2.ContourArea(points));
- }
- if (measurementUnit == MeasurementUnit.Micron) areas = areas * rule;*/
- List<List<OpenCvSharp.Point>> ps = new List<List<OpenCvSharp.Point>>();
- for (int i = 0; i < hierachy.Length; i++)
- {
- if (deleteIndexs.Exists(a => a == i))
- continue;
- //计算面积
- if (filterParameters == FilterParameters.Area)
- {
- double area = Math.Abs(Cv2.ContourArea(contours[i]));
- if (measurementUnit == MeasurementUnit.Micron) area = area * rule * rule;
- if (functionParameters == FunctionParameters.Remove)
- {
- if (area >= min && area <= max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- else if (functionParameters == FunctionParameters.Choise)
- {
- if (area <= min || area >= max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- }
- //计算面积比
- else if (filterParameters == FilterParameters.AreaRatio)
- {
- double area = Math.Abs(Cv2.ContourArea(contours[i]));
- Point2f center;
- float radius;
- Cv2.MinEnclosingCircle(contours[i], out center, out radius);
- double areas = Math.PI * radius * radius;
- if (measurementUnit == MeasurementUnit.Micron)
- {
- area = area * rule * rule;
- areas = areas * rule * rule;
- }
- if (functionParameters == FunctionParameters.Remove)
- {
- if (area / areas > min && area / areas < max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- else if (functionParameters == FunctionParameters.Choise)
- {
- if (area / areas < min || area / areas > max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- }
- //计算宽高比
- else if (filterParameters == FilterParameters.AspectRatio)
- {
- double area = BasicCalculationHelper.CalcAspectRatio(contours[i]);
- if (functionParameters == FunctionParameters.Remove)
- {
- if (area > min && area < max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- else if (functionParameters == FunctionParameters.Choise)
- {
- if (area < min || area > max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- }
- //计算最大卡规直径(长径)
- else if (filterParameters == FilterParameters.LongTrail)
- {
- double area = BasicCalculationHelper.CalcLongTrail(contours[i]) * 2;
- if (measurementUnit == MeasurementUnit.Micron) area = area * rule;
- if (functionParameters == FunctionParameters.Remove)
- {
- if (area > min && area < max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- else if (functionParameters == FunctionParameters.Choise)
- {
- if (area < min || area > max && hierachy[i].Parent == -1)
- {
- ps.Add(contours[i].ToList());
- }
- }
- }
- }
- if (functionParameters == FunctionParameters.Choise)
- Cv2.FillPoly(temp, ps, Scalar.Red);
- else if (functionParameters == FunctionParameters.Remove)
- Cv2.FillPoly(temp, ps, new Scalar(0, 0, 0, 0));
- return temp;
- }
- private static void RecursiveFindChildContours(
- List<OpenCvSharp.Point[]> drawContours,
- HierarchyIndex[] hierachy,
- int position,
- List<int> points
- )
- {
- int m = 0;
- foreach (HierarchyIndex index in hierachy)
- {
- if (index.Parent == position)
- {
- points.Add(m);
- RecursiveFindChildContours(drawContours, hierachy, m, points);
- }
- m++;
- }
- }
- #endregion
- #region 孔洞删除
- /// <summary>
- /// 孔洞删除,用其它颜色进行填充
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public static Mat HoleRemoval(Mat mat, List<Args> lists, int pColor, double rule, out double outmin, out double outmax)
- {
- //原始轮廓信息
- OpenCvSharp.Point[][] contours;
- //轮廓的拓扑信息
- HierarchyIndex[] hierachy;
- //筛选参数
- FilterParameters filterParameters = FilterParameters.Area;
- //筛选范围
- double min = 0, max = 0;
- //输出的值
- outmin = -1;
- outmax = -1;
- //筛选单位
- MeasurementUnit measurementUnit = MeasurementUnit.Pixel;
- //孔洞颜色
- int color = 0;
- //面积合计大小
- //double areas = 0;
- //读取参数信息
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "FilterParameters":
- filterParameters = (FilterParameters)args.Value;
- break;
- case "Scope":
- min = ((List<double>)args.Value)[0];
- max = ((List<double>)args.Value)[1];
- break;
- case "UnitParameters":
- measurementUnit = (MeasurementUnit)args.Value;
- break;
- case "HoleColor":
- color = (int)args.Value;
- break;
- }
- }
- System.Drawing.Color color1 = System.Drawing.Color.FromArgb(color);
- System.Drawing.Color color2 = System.Drawing.Color.FromArgb(pColor);
- Mat dst = new Mat();
- mat.CopyTo(dst);
- Cv2.FindContours(dst.CvtColor(ColorConversionCodes.BGR2GRAY), out contours, out hierachy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone);
- /*//计算总面积
- foreach (Point[] points in contours)
- {
- areas += Math.Abs(Cv2.ContourArea(points));
- }
- if (measurementUnit == MeasurementUnit.Micron) areas = areas * rule * rule;*/
- List<int> ints = new List<int>();
- List<List<OpenCvSharp.Point>> ps = new List<List<OpenCvSharp.Point>>();
- List<List<OpenCvSharp.Point>> ps1 = new List<List<OpenCvSharp.Point>>();
- for (int i = 0; i < hierachy.Length; i++)
- {
- if (hierachy[i].Parent > -1)
- {
- ps1.Add(contours[i].ToList());
- //计算面积
- if (filterParameters == FilterParameters.Area)
- {
- double area = Math.Abs(Cv2.ContourArea(contours[i]));
- //double area = BasicCalculationHelper.DecimalCeiling(Math.Abs(Cv2.ContourArea(contours[i])));
- if (measurementUnit == MeasurementUnit.Micron) area = area * rule * rule;
- if (outmin == -1)
- {
- outmin = area;
- outmax = area;
- }
- else
- {
- if (outmin > area) outmin = BasicCalculationHelper.DecimalFloor(area);
- if (outmax < area) outmax = BasicCalculationHelper.DecimalCeiling(area);
- }
- if (area >= min && area <= max)
- {
- ints.Add(i);
- //ps.Add(contours[i].ToList());
- }
- }
- //计算面积比
- else if (filterParameters == FilterParameters.AreaRatio)
- {
- double area = Math.Abs(Cv2.ContourArea(contours[i]));
- Point2f point;
- float radius;
- Cv2.MinEnclosingCircle(contours[i], out point, out radius);
- double areas = Math.PI * radius * radius;
- if (outmin == -1)
- {
- outmin = area / areas;
- outmax = Math.Round(area / areas, 2);
- }
- else
- {
- if (outmin > area / areas) outmin = area / areas;
- if (outmax < area / areas) outmax = Math.Round(area / areas, 2);
- }
- if (area / areas >= min && Math.Round(area / areas, 2) <= max)
- {
- ints.Add(i);
- //ps.Add(contours[i].ToList());
- }
- }
- //计算宽高比
- else if (filterParameters == FilterParameters.AspectRatio)
- {
- double area = Math.Round(BasicCalculationHelper.CalcAspectRatio(contours[i]), 2);
- if (outmin == -1)
- {
- outmin = area;
- outmax = area;
- }
- else
- {
- if (outmin > area) outmin = area;
- if (outmax < area) outmax = area;
- }
- if (area >= min && area <= max)
- {
- ints.Add(i);
- //ps.Add(contours[i].ToList());
- }
- }
- //计算最大卡规直径(长径)
- else if (filterParameters == FilterParameters.LongTrail)
- {
- double area = BasicCalculationHelper.CalcLongTrail(contours[i]) * 2;
- if (measurementUnit == MeasurementUnit.Micron) area = area * rule;
- if (outmin == -1)
- {
- outmin = area;
- outmax = area;
- }
- else
- {
- if (outmin > area) outmin = BasicCalculationHelper.DecimalFloor(area);
- if (outmax < area) outmax = BasicCalculationHelper.DecimalCeiling(area);
- }
- if (area >= min && area <= max)
- {
- ints.Add(i);
- //his.Add(hierachy[i]);
- //ps.Add(contours[i].ToList());
- }
- }
- }
- }
- Cv2.FillPoly(mat, ps1, new Scalar(color1.B, color1.G, color1.R, color1.A));
- for (int k = 0; k < ints.Count(); k++)
- {
- Cv2.DrawContours(mat, contours, ints[k], new Scalar(color2.B, color2.G, color2.R, 255), -1, LineTypes.Link8, hierachy, 0);
- }
- //foreach (List<Point> points in ps)
- //{
- //Cv2.FillPoly(mat, InputArray.Create(ps[0]), new Scalar(color2.B, color2.G, color2.R, 255));
- //}
- //Cv2.DrawContours(mat, ps, -1, new Scalar(color2.B, color2.G, color2.R, 255), -1, LineTypes.Link8, his, 1);
- //Cv2.FillPoly(mat, ps, new Scalar(color2.B, color2.G, color2.R, 255));
- return mat;
- }
- #endregion
- #region 抽骨架
- unsafe byte* pixels;
- int foreground;
- int width, height;
- int xMin, xMax, yMin, yMax;
- Mat dst;
- /// <summary>
- /// 抽骨架
- /// 使用demo里面的form26里面的ImageJ查表法
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="lists"></param>
- /// <returns></returns>
- public unsafe Mat ImageSkeleton(Mat mat, List<Args> lists, int color)
- {
- //如果不是单通道,转单通道
- if (mat.Type() != MatType.CV_8UC1)
- {
- Cv2.CvtColor(mat, mat, ColorConversionCodes.BGR2GRAY);
- }
- //判断是否二值化图像
- if (!BaseTools.DetermineBinaryImageByHist(mat))
- {
- MessageBox.Show("Please enter abinarization image");
- return mat;
- }
- //判断是否黑白的二值图
- if (!BaseTools.DetermineBinaryImage(mat))
- {
- //处理为黑/白二值化的图像
- for (int o = 0; o < mat.Height; o++)
- {
- for (int p = 0; p < mat.Width; p++)
- {
- byte v = mat.At<byte>(o, p);
- if (v > 0)
- {
- mat.Set<byte>(o, p, 255);
- }
- }
- }
- }
- //背景颜色
- int fg = 0;
- //前景颜色
- foreground = 255 - fg;
- int pass = 0;
- int pixelsRemoved;
- dst = new Mat();
- bool edgePixels = hasEdgePixels(mat);
- if (edgePixels)
- {
- dst = new Mat(new OpenCvSharp.Size(mat.Width + 2, mat.Height + 2), MatType.CV_8UC1, Scalar.All(0));
- Cv2.CopyMakeBorder(mat, dst, 1, 1, 1, 1, BorderTypes.Constant, Scalar.All(0));
- }
- else
- {
- mat.CopyTo(dst);
- }
- width = dst.Width;
- height = dst.Height;
- xMin = 1;
- xMax = width - 2;
- yMin = 1;
- yMax = height - 2;
- pixels = (byte*)dst.Data;
- do
- {
- pixelsRemoved = thin(pass++, BaseTools.table);
- pixelsRemoved += thin(pass++, BaseTools.table);
- } while (pixelsRemoved > 0);
- do
- {
- pixelsRemoved = thin(pass++, BaseTools.table2);
- pixelsRemoved += thin(pass++, BaseTools.table2);
- } while (pixelsRemoved > 0);
- BaseTools.shrink(mat, dst, edgePixels);
- System.Drawing.Color color1 = System.Drawing.Color.FromArgb(color);
- Mat temp1 = new Mat(mat.Size(), OpenCvSharp.MatType.CV_8UC4);
- for (int o = 0; o < mat.Height; o++)
- {
- for (int p = 0; p < mat.Width; p++)
- {
- byte v = dst.At<byte>(o, p);
- if (v > 0)
- {
- temp1.Set<Vec4b>(o, p, new Vec4b(color1.B, color1.G, color1.R, 255));
- }
- else
- {
- temp1.Set<Vec4b>(o, p, new Vec4b(0, 0, 0, 0));
- }
- }
- }
- temp1.CopyTo(mat);
- return mat;
- }
- bool hasEdgePixels(Mat ip)
- {
- int width = ip.Width;
- int height = ip.Height;
- bool edgePixels = false;
- for (int x = 0; x < width; x++)
- { // top edge
- if (ip.At<byte>(0, x) == foreground)
- edgePixels = true;
- }
- for (int x = 0; x < width; x++)
- { // bottom edge
- if (ip.At<byte>(height - 1, x) == foreground)
- edgePixels = true;
- }
- for (int y = 0; y < height; y++)
- { // left edge
- if (ip.At<byte>(y, 0) == foreground)
- edgePixels = true;
- }
- for (int y = 0; y < height; y++)
- { // right edge
- if (ip.At<byte>(y, width - 1) == foreground)
- edgePixels = true;
- }
- return edgePixels;
- }
- unsafe int thin(int pass, int[] table)
- {
- int p1, p2, p3, p4, p5, p6, p7, p8, p9;
- int bgColor = 0; //255
- //if (parent.isInvertedLut())
- // bgColor = 0;
- Mat temp = new Mat();
- dst.CopyTo(temp);
- byte* pixels2 = (byte*)temp.Data;
- int v, index, code;
- int offset, rowOffset = temp.Width;
- int pixelsRemoved = 0;
- for (int y = yMin; y <= yMax; y++)
- {
- offset = xMin + y * temp.Width;
- for (int x = xMin; x <= xMax; x++)
- {
- p5 = pixels2[offset];
- v = p5;
- if (v != bgColor)
- {
- p1 = pixels2[offset - rowOffset - 1];
- p2 = pixels2[offset - rowOffset];
- p3 = pixels2[offset - rowOffset + 1];
- p4 = pixels2[offset - 1];
- p6 = pixels2[offset + 1];
- p7 = pixels2[offset + rowOffset - 1];
- p8 = pixels2[offset + rowOffset];
- p9 = pixels2[offset + rowOffset + 1];
- index = 0;
- if (p1 != bgColor) index |= 1;
- if (p2 != bgColor) index |= 2;
- if (p3 != bgColor) index |= 4;
- if (p6 != bgColor) index |= 8;
- if (p9 != bgColor) index |= 16;
- if (p8 != bgColor) index |= 32;
- if (p7 != bgColor) index |= 64;
- if (p4 != bgColor) index |= 128;
- code = table[index];
- if ((pass & 1) == 1)
- { //odd pass
- if (code == 2 || code == 3)
- {
- v = bgColor;
- pixelsRemoved++;
- }
- }
- else
- { //even pass
- if (code == 1 || code == 3)
- {
- v = bgColor;
- pixelsRemoved++;
- }
- }
- }
- pixels[offset++] = (byte)v;
- }
- }
- return pixelsRemoved;
- }
- #endregion
- #region 空洞填充
- /// <summary>
- /// 孔洞填充
- /// </summary>
- /// <param name="mat"></param>
- /// <param name="c"></param>
- /// <returns></returns>
- public static Mat HolesFill(Mat mat, int c)
- {
- Mat temp = null;
- try
- {
- //mat的颜色
- System.Drawing.Color color = System.Drawing.Color.FromArgb(c);
- //原始轮廓信息
- OpenCvSharp.Point[][] contours;
- //轮廓的拓扑信息
- HierarchyIndex[] hierachy;
- //中间变量
- temp = new Mat();
- mat.CopyTo(temp);
- Cv2.FindContours(temp.CvtColor(ColorConversionCodes.BGRA2GRAY), out contours, out hierachy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone);
- if (hierachy != null)
- {
- for (int i = 0; i < hierachy.Length; i++)
- {
- //如果需要还可以判断面积范围
- if (hierachy[i].Parent > -1)
- {
- Vec3b vec3B = mat.At<Vec3b>(contours[i][0].Y, contours[i][0].X);
- if ((vec3B.Item0 == (byte)color.B) && (vec3B.Item1 == (byte)color.G) && (vec3B.Item2 == (byte)(color.R)))
- {
- List<List<OpenCvSharp.Point>> ps = new List<List<OpenCvSharp.Point>>();
- ps.Add(contours[i].ToList());
- Cv2.FillPoly(mat, ps, new Scalar(color.B, color.G, color.R, 255));
- }
- }
- }
- }
- }
- catch (Exception)
- {
- System.Windows.Forms.MessageBox.Show("Abnormal program");
- }
- finally
- {
- if (temp != null && !temp.IsDisposed) temp.Dispose();
- }
- return mat;
- }
- #endregion
- #region 形态学分割
- public static Mat MorphologySegment(Mat mat, PhaseModel model, List<Args> lists)
- {
- //获取参数
- int paramCount = 0;
- //读取参数信息
- for (int i = 0; i < lists.Count; i++)
- {
- Args args = lists[i];
- switch (args.Key)
- {
- case "Count":
- paramCount = int.Parse(args.Value.ToString());
- break;
- }
- }
- //处理相
- for (int h = 0; h < model.mat.Height; h++)
- {
- for (int w = 0; w < model.mat.Width; w++)
- {
- Vec4b vec4B = model.mat.At<Vec4b>(h, w);
- if (vec4B.Item3 == 0)
- {
- model.mat.Set<Vec4b>(h, w, new Vec4b(255, 255, 255, 255));
- }
- else
- {
- model.mat.Set<Vec4b>(h, w, new Vec4b(0, 0, 0, 255));
- }
- }
- }
- //构造八边形的卷积核
- InputArray kernel = InputArray.Create<int>(new int[5, 5] {
- { 0, 1, 1, 1, 0 },
- { 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1 },
- { 1, 1, 1, 1, 1 },
- { 0, 1, 1, 1, 0 } });
- Mat element = kernel.GetMat();
- element.ConvertTo(element, MatType.CV_8UC1);
- Mat lab1Img = new Mat();
- model.mat.CopyTo(lab1Img);
- //原图灰度化
- Mat img = lab1Img.CvtColor(ColorConversionCodes.BGR2GRAY);
- //用来判断极限腐蚀是否完成的中间变量
- Mat erode = new Mat();
- img.CopyTo(erode);
- //用来观察腐蚀次数
- int h1 = 0;
- Mat temp = new Mat();
- //开始
- while (Cv2.CountNonZero(erode) > 0)
- {
- //寻找并标记区域个数
- Mat labelMat = new Mat();
- Mat stats = new Mat();
- Mat centroids = new Mat();
- int num = Cv2.ConnectedComponentsWithStats(erode, labelMat, stats, centroids, PixelConnectivity.Connectivity8);
- //进行腐蚀
- temp = erode.Erode(element, null, 1);
- //跳出循环的条件
- int count = Cv2.CountNonZero(temp);
- //循环质心,和腐蚀后的图片进行比较,如果腐蚀后的图片质心为黑色了,那说明被腐蚀掉了,则在下面需要被还原回来
- for (int h = 1; h < centroids.Height; h++)
- {
- double a = centroids.At<double>(h, 0);
- double b = centroids.At<double>(h, 1);
- OpenCvSharp.Point point = new OpenCvSharp.Point(a, b);
- //计算每个stats范围内的像素和是否为0
- int x = stats.At<int>(h, 0);
- int y = stats.At<int>(h, 1);
- int width = stats.At<int>(h, 2);
- int height = stats.At<int>(h, 3);
- System.Console.WriteLine("x:" + x + " y:" + y);
- Rect roi1 = new Rect(x, y, width, height);
- Mat ImageROI1 = new Mat(temp, roi1);
- int cc1 = Cv2.CountNonZero(ImageROI1);
- //代表区域已经消失了,需要还原回来
- if (cc1 == 0)
- {
- Rect roi = new Rect(x, y, width, height);
- Mat ImageROI = new Mat(erode, roi);
- Rect rect = new Rect(x, y, width, height);
- Mat pos = new Mat(temp, rect);
- ImageROI.CopyTo(pos);
- }
- }
- if (h1 == paramCount && paramCount > 0) break;
- temp.CopyTo(erode);
- h1++;
- if (count == 0)
- {
- break;
- }
- }
- Mat fffff = new Mat();
- Mat labels = new Mat();
- Cv2.DistanceTransformWithLabels(~temp, fffff, labels, DistanceTypes.L1, DistanceMaskSize.Precise);
- //labels.ConvertTo(labels, MatType.CV_8UC3);
- //找到轮廓
- OpenCvSharp.Point[][] contours;
- HierarchyIndex[] hierachy;
- Cv2.FindContours(labels, out contours, out hierachy, RetrievalModes.CComp, ContourApproximationModes.ApproxNone);
- Mat lk = new Mat(labels.Size(), MatType.CV_8UC1, Scalar.All(255));
- Cv2.DrawContours(lk, contours, -1, Scalar.All(0), 1, LineTypes.Link8, hierachy);
- //Cv2.MorphologyEx(img, img, MorphTypes.Open, element, null, 1);
- //Cv2.Dilate(img, img, element, null, 1);
- System.Drawing.Color color = System.Drawing.Color.FromArgb(model.color);
- for (int h = 0; h < lab1Img.Height; h++)
- {
- for (int w = 0; w < lab1Img.Width; w++)
- {
- if (lab1Img.At<byte>(h, w) == 0)
- lab1Img.Set<Vec3b>(h, w, new Vec3b(color.B, color.G, color.R));
- /*if (lab1Img.At<byte>(h, w) == 0 || lk.At<byte>(h, w) == 0)
- lab1Img.Set<Vec4b>(h, w, new Vec4b(color.B, color.G, color.R, 255));
- else
- lab1Img.Set<Vec4b>(h, w, new Vec4b(0, 0, 0, 0));*/
- }
- }
- for (int h = 0; h < lk.Height; h++)
- {
- for (int w = 0; w < lk.Width; w++)
- {
- if (lk.At<byte>(h, w) == 0)
- lab1Img.Set<Vec3b>(h, w, new Vec3b(color.B, color.G, color.R));
- }
- }
- Cv2.Erode(lab1Img, lab1Img, null, null, 1);
- Cv2.Dilate(lab1Img, lab1Img, null, null, 1);
- //Cv2.ImShow("dddd", lk);
- //Cv2.ImShow("粗化操作1", lab1Img);
- return lab1Img;
- }
- #endregion
- }
- public struct Int16DoubleWithValue : IComparable<Int16DoubleWithValue>
- {
- public int O;
- public float V;
- public Int16DoubleWithValue(int offset, float value)
- {
- O = offset;
- V = value;
- }
- public int CompareTo(Int16DoubleWithValue other)
- {
- return this.V.CompareTo(other.V);
- }
- }
- public class BitMap2d
- {
- public float[] data;
- public int width;
- public int height;
- /// <summary>
- /// 初始化操作对象
- /// </summary>
- /// <param name="width"></param>
- /// <param name="height"></param>
- /// <param name="v">初始值</param>
- public BitMap2d(int width, int height, float v)
- {
- this.width = width;
- this.height = height;
- data = new float[width * height];
- for (int i = 0; i < width * height; i++)
- data[i] = v;
- }
- /// <summary>
- /// 根据mat初始化
- /// </summary>
- /// <param name="mat">初始EDM对象</param>
- public unsafe BitMap2d(Mat mat)
- {
- this.width = mat.Width;
- this.height = mat.Height;
- data = new float[width * height];
- mat.ForEachAsFloat(FunctionForEachAsFloat);
- }
- private unsafe void FunctionForEachAsFloat(float* value, int* position)
- {
- data[position[0] * width + position[1]] = *value;
- }
- public void SetPixel(int x, int y, byte v)
- {
- data[x + y * width] = v;
- }
- public float GetPixel(int x, int y)
- {
- return data[x + y * width];
- }
- public void SetPixel(int offset, byte v)
- {
- data[offset] = v;
- }
- public float GetPixel(int offset)
- {
- return data[offset];
- }
- public System.Drawing.Bitmap MakeBmp()
- {
- float min = float.MaxValue;
- float max = float.MinValue;
- for (int i = 0; i < width; i++)
- {
- for (int j = 0; j < height; j++)
- {
- float r = this.GetPixel(i, j);
- if (r > max)
- max = r;
- if (r < min)
- min = r;
- }
- }
- float delta = max - min;
- System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(this.width, this.height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- for (int i = 0; i < width; i++)
- {
- for (int j = 0; j < height; j++)
- {
- float r = this.GetPixel(i, j);
- int b = 255 - (int)(255 * (r - min) / delta);
- System.Drawing.Color c = System.Drawing.Color.FromArgb((byte)b, (byte)b, (byte)b);
- bmp.SetPixel(i, j, c);
- }
- }
- return bmp;
- }
- }
- public class MaximunFinder
- {
- BitMap2d bmp;
- int width;
- int height;
- public MaximunFinder(BitMap2d bmp)
- {
- this.bmp = bmp;
- this.width = bmp.width;
- this.height = bmp.height;
- }
- public List<Int16DoubleWithValue> FindMaxima()
- {
- List<Int16DoubleWithValue> list = new List<Int16DoubleWithValue>();
- int offset = 0;
- for (int j = 0; j < height; j++)
- {
- for (int i = 0; i < width; i++, offset++)
- {
- if (IsMaxima(i, j, offset))
- {
- list.Add(new Int16DoubleWithValue(offset, bmp.GetPixel(offset)));
- }
- }
- }
- list.Sort();
- return list;
- }
- private bool IsMaxima(int i, int j, int offset)
- {
- float v = bmp.GetPixel(offset);
- if (v == 0) return false;
- bool b1 = v >= bmp.GetPixel(Math.Max(0, i - 1), Math.Max(0, j - 1));
- bool b2 = v >= bmp.GetPixel(i, Math.Max(0, j - 1));
- bool b3 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), Math.Max(0, j - 1));
- bool b4 = v >= bmp.GetPixel(Math.Max(0, i - 1), j);
- bool b5 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), j);
- bool b6 = v >= bmp.GetPixel(Math.Max(0, i - 1), Math.Min(height - 1, j + 1));
- bool b7 = v >= bmp.GetPixel(i, Math.Min(height - 1, j + 1));
- bool b8 = v >= bmp.GetPixel(Math.Min(width - 1, i + 1), Math.Min(height - 1, j + 1));
- return b1 && b2 && b3 && b4 && b5 && b6 && b7 && b8 && (v > 0);
- }
- }
- }
|