AdjustIntent.cs 256 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206
  1. using OpenCvSharp;
  2. using OpenCvSharp.Extensions;
  3. using PaintDotNet.Adjust.BaseImage;
  4. using PaintDotNet.Base;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Drawing;
  8. using System.Drawing.Imaging;
  9. using System.Linq;
  10. using System.Runtime.InteropServices;
  11. using System.Windows.Forms;
  12. namespace PaintDotNet.Adjust
  13. {
  14. public struct UVT
  15. {
  16. //[FieldOffset(0)]
  17. public double u;
  18. //[FieldOffset(1)]
  19. public double v;
  20. //[FieldOffset(2)]
  21. public double t;
  22. }
  23. /// <summary>
  24. /// 图像调节
  25. /// </summary>
  26. public unsafe class AdjustIntent
  27. {
  28. /// <summary>
  29. /// 全局的mat,用来做中间变量,但是需要注意销毁
  30. /// </summary>
  31. private static Mat phaseTemp1;
  32. private static Mat phaseTempMax;
  33. private static Mat phaseTempMin;
  34. private static Mat localMeansMatrix;// = new Mat(src.Rows, src.Cols, MatType.CV_32FC1);
  35. private static Mat localVarianceMatrix;// = new Mat(src.Rows, src.Cols, MatType.CV_32FC1);
  36. private static double contrast = 1.5; //对比度 contrast Enter the alpha value [1.0-3.0]:
  37. private static double brightness = 50; //亮度 brightness Enter the beta value [0-100]
  38. private static int localThreshold; //阈值
  39. private static int dstWidth; //图像的宽度
  40. private static int dstChannel; //图像的通道数
  41. //(三通道)图像拷贝
  42. private static Mat calMats;
  43. //白平衡C-翻译
  44. private static double localTemp = -1.0, localGreen = -1.0, localEqual = 1.0, INITIALBLACKBODY = 4000.0;
  45. private static string localMethod = "Custom";
  46. private static int settings_CRI_color = 4; // Number for display Lab value; 0 = disabled
  47. private static bool settings_verbose = false;
  48. private static double[][] cie_colour_match_jd = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer.
  49. new double[]{0.000000000000, 0.000000000000, 0.000000000000},
  50. new double[]{0.000000000000, 0.000000000000, 0.000000000000},
  51. new double[]{0.000000122200, 0.000000013398, 0.000000535027},
  52. new double[]{0.000000919270, 0.000000100650, 0.000004028300},
  53. new double[]{0.000005958600, 0.000000651100, 0.000026143700},
  54. new double[]{0.000033266000, 0.000003625000, 0.000146220000},
  55. new double[]{0.000159952000, 0.000017364000, 0.000704776000},
  56. new double[]{0.000662440000, 0.000071560000, 0.002927800000},
  57. new double[]{0.002361600000, 0.000253400000, 0.010482200000},
  58. new double[]{0.007242300000, 0.000768500000, 0.032344000000},
  59. new double[]{0.019109700000, 0.002004400000, 0.086010900000},
  60. new double[]{0.043400000000, 0.004509000000, 0.197120000000},
  61. new double[]{0.084736000000, 0.008756000000, 0.389366000000},
  62. new double[]{0.140638000000, 0.014456000000, 0.656760000000},
  63. new double[]{0.204492000000, 0.021391000000, 0.972542000000},
  64. new double[]{0.264737000000, 0.029497000000, 1.282500000000},
  65. new double[]{0.314679000000, 0.038676000000, 1.553480000000},
  66. new double[]{0.357719000000, 0.049602000000, 1.798500000000},
  67. new double[]{0.383734000000, 0.062077000000, 1.967280000000},
  68. new double[]{0.386726000000, 0.074704000000, 2.027300000000},
  69. new double[]{0.370702000000, 0.089456000000, 1.994800000000},
  70. new double[]{0.342957000000, 0.106256000000, 1.900700000000},
  71. new double[]{0.302273000000, 0.128201000000, 1.745370000000},
  72. new double[]{0.254085000000, 0.152761000000, 1.554900000000},
  73. new double[]{0.195618000000, 0.185190000000, 1.317560000000},
  74. new double[]{0.132349000000, 0.219940000000, 1.030200000000},
  75. new double[]{0.080507000000, 0.253589000000, 0.772125000000},
  76. new double[]{0.041072000000, 0.297665000000, 0.570060000000},
  77. new double[]{0.016172000000, 0.339133000000, 0.415254000000},
  78. new double[]{0.005132000000, 0.395379000000, 0.302356000000},
  79. new double[]{0.003816000000, 0.460777000000, 0.218502000000},
  80. new double[]{0.015444000000, 0.531360000000, 0.159249000000},
  81. new double[]{0.037465000000, 0.606741000000, 0.112044000000},
  82. new double[]{0.071358000000, 0.685660000000, 0.082248000000},
  83. new double[]{0.117749000000, 0.761757000000, 0.060709000000},
  84. new double[]{0.172953000000, 0.823330000000, 0.043050000000},
  85. new double[]{0.236491000000, 0.875211000000, 0.030451000000},
  86. new double[]{0.304213000000, 0.923810000000, 0.020584000000},
  87. new double[]{0.376772000000, 0.961988000000, 0.013676000000},
  88. new double[]{0.451584000000, 0.982200000000, 0.007918000000},
  89. new double[]{0.529826000000, 0.991761000000, 0.003988000000},
  90. new double[]{0.616053000000, 0.999110000000, 0.001091000000},
  91. new double[]{0.793832000000, 0.982380000000, 0.000000000000},
  92. new double[]{0.878655000000, 0.955552000000, 0.000000000000},
  93. new double[]{0.951162000000, 0.915175000000, 0.000000000000},
  94. new double[]{1.014160000000, 0.868934000000, 0.000000000000},
  95. new double[]{1.074300000000, 0.825623000000, 0.000000000000},
  96. new double[]{1.118520000000, 0.777405000000, 0.000000000000},
  97. new double[]{1.134300000000, 0.720353000000, 0.000000000000},
  98. new double[]{1.123990000000, 0.658341000000, 0.000000000000},
  99. new double[]{1.089100000000, 0.593878000000, 0.000000000000},
  100. new double[]{1.030480000000, 0.527963000000, 0.000000000000},
  101. new double[]{0.950740000000, 0.461834000000, 0.000000000000},
  102. new double[]{0.856297000000, 0.398057000000, 0.000000000000},
  103. new double[]{0.754930000000, 0.339554000000, 0.000000000000},
  104. new double[]{0.647467000000, 0.283493000000, 0.000000000000},
  105. new double[]{0.535110000000, 0.228254000000, 0.000000000000},
  106. new double[]{0.431567000000, 0.179828000000, 0.000000000000},
  107. new double[]{0.343690000000, 0.140211000000, 0.000000000000},
  108. new double[]{0.268329000000, 0.107633000000, 0.000000000000},
  109. new double[]{0.204300000000, 0.081187000000, 0.000000000000},
  110. new double[]{0.152568000000, 0.060281000000, 0.000000000000},
  111. new double[]{0.112210000000, 0.044096000000, 0.000000000000},
  112. new double[]{0.081260600000, 0.031800400000, 0.000000000000},
  113. new double[]{0.057930000000, 0.022601700000, 0.000000000000},
  114. new double[]{0.040850800000, 0.015905100000, 0.000000000000},
  115. new double[]{0.028623000000, 0.011130300000, 0.000000000000},
  116. new double[]{0.019941300000, 0.007748800000, 0.000000000000},
  117. new double[]{0.013842000000, 0.005375100000, 0.000000000000},
  118. new double[]{0.009576880000, 0.003717740000, 0.000000000000},
  119. new double[]{0.006605200000, 0.002564560000, 0.000000000000},
  120. new double[]{0.004552630000, 0.001768470000, 0.000000000000},
  121. new double[]{0.003144700000, 0.001222390000, 0.000000000000},
  122. new double[]{0.002174960000, 0.000846190000, 0.000000000000},
  123. new double[]{0.001505700000, 0.000586440000, 0.000000000000},
  124. new double[]{0.001044760000, 0.000407410000, 0.000000000000},
  125. new double[]{0.000727450000, 0.000284041000, 0.000000000000},
  126. new double[]{0.000508258000, 0.000198730000, 0.000000000000},
  127. new double[]{0.000356380000, 0.000139550000, 0.000000000000},
  128. new double[]{0.000250969000, 0.000098428000, 0.000000000000},
  129. new double[]{0.000177730000, 0.000069819000, 0.000000000000},
  130. new double[]{0.000126390000, 0.000049737000, 0.000000000000},
  131. new double[]{0.000090151000, 0.000035540500, 0.000000000000},
  132. new double[]{0.000064525800, 0.000025486000, 0.000000000000},
  133. new double[]{0.000046339000, 0.000018338400, 0.000000000000},
  134. new double[]{0.000033411700, 0.000013249000, 0.000000000000},
  135. new double[]{0.000024209000, 0.000009619600, 0.000000000000},
  136. new double[]{0.000017611500, 0.000007012800, 0.000000000000},
  137. new double[]{0.000012855000, 0.000005129800, 0.000000000000},
  138. new double[]{0.000009413630, 0.000003764730, 0.000000000000},
  139. new double[]{0.000006913000, 0.000002770810, 0.000000000000},
  140. new double[]{0.000005093470, 0.000002046130, 0.000000000000},
  141. new double[]{0.000003767100, 0.000001516770, 0.000000000000},
  142. new double[]{0.000002795310, 0.000001128090, 0.000000000000},
  143. new double[]{0.000002082000, 0.000000842160, 0.000000000000},
  144. new double[]{0.000001553140, 0.000000629700, 0.000000000000},
  145. new double[]{0.000000000000, 0.000000000000, 0.000000000000}//手动加0
  146. };
  147. // spectral data for Daylight direct Sun: I have choose 5300K because Nikon=5200K, Olympus=5300K, Panasonic=5500K, Leica=5400K, Minolta=5100K
  148. private static double[] Daylight5300_spect = {
  149. 24.82, 26.27, 27.72, 28.97, 30.22, 29.71, 29.19, 31.95, 34.71, 45.49, 56.26, 59.97, 63.68, 65.30, 66.92, 65.39, 63.86, 72.59, 81.32, 87.53, 93.73, 95.15, 96.56, 96.55, 96.54, 98.13, 99.73, 97.70, 95.66, 97.19, 98.72,
  150. 98.90, 99.08, 98.98, 98.87, 101.13, 103.39, 102.48, 101.57, 102.14, 102.71, 101.36, 100.00, 98.71, 97.42, 97.81, 98.21, 95.20, 92.20, 93.92, 95.63, 96.15, 96.67, 96.34, 96.01, 94.21, 92.41, 93.58, 94.74, 93.05, 91.36, 92.29,
  151. 93.21, 95.25, 97.28, 95.30, 93.32, 87.92, 82.51, 84.29, 86.06, 86.94, 87.81, 80.24, 72.68, 77.32, 81.96, 84.88, 87.79, 81.01, 74.22, 64.41, 54.60, 66.55, 78.51, 76.35, 74.20, 74.79, 75.38, 72.48, 69.58, 65.11, 60.64,
  152. 63.88, 67.13, 68.85, 70.57
  153. };
  154. //spectral data for Daylight Cloudy: I have choose 6200K because Nikon=6000K, Olympus=6000K, Panasonic=6200K, Leica=6400K, Minolta=6500K
  155. private static double[] Cloudy6200_spect = {
  156. 39.50, 40.57, 41.63, 43.85, 46.08, 45.38, 44.69, 47.20, 49.71, 63.06, 76.41, 80.59, 84.77, 85.91, 87.05, 84.14, 81.23, 90.29, 99.35, 105.47, 111.58, 112.23, 112.87, 111.74, 110.62, 111.41, 112.20, 108.98, 105.76, 106.32,
  157. 106.89, 106.34, 105.79, 104.62, 103.45, 105.09, 106.72, 105.24, 103.76, 103.75, 103.75, 101.87, 100.00, 98.29, 96.58, 96.46, 96.34, 92.85, 89.37, 90.25, 91.12, 91.06, 90.99, 90.17, 89.35, 87.22, 85.10, 85.48, 85.85,
  158. 84.03, 82.20, 82.45, 82.69, 83.92, 85.15, 83.14, 81.13, 76.65, 72.17, 73.27, 74.36, 75.65, 76.95, 70.34, 63.74, 67.98, 72.22, 74.88, 77.54, 71.59, 65.65, 56.82, 47.99, 58.53, 69.06, 67.27, 65.47, 65.96, 66.44, 63.92, 61.41, 57.52,
  159. 53.63, 56.47, 59.31, 60.80, 62.29
  160. };
  161. //spectral data for Daylight Shade: I have choose 7600K because Nikon=8000K, Olympus=7500K, Panasonic=7500K, Leica=7500K, Minolta=7500K
  162. private static double[] Shade7600_spect = {
  163. 64.42, 64.46, 64.51, 68.35, 72.20, 70.22, 68.24, 69.79, 71.35, 87.49, 103.64, 108.68, 113.72, 114.12, 114.53, 109.54, 104.55, 113.59, 122.63, 128.52, 134.41, 134.02, 133.63, 131.02, 128.41, 128.08, 127.75, 123.16,
  164. 118.57, 117.89, 117.22, 115.72, 114.22, 111.60, 108.99, 109.84, 110.68, 108.57, 106.45, 105.71, 104.98, 102.49, 100.00, 97.78, 95.55, 94.82, 94.08, 90.47, 86.87, 86.94, 87.01, 86.45, 85.88, 84.57, 83.27, 80.83, 78.40, 78.21,
  165. 78.03, 76.22, 74.42, 74.15, 73.89, 74.41, 74.92, 73.01, 71.09, 67.26, 63.42, 64.01, 64.60, 66.10, 67.60, 61.83, 56.06, 59.94, 63.82, 66.27, 68.71, 63.49, 58.26, 50.30, 42.34, 51.64, 60.95, 59.45, 57.95, 58.35, 58.76, 56.57,
  166. 54.38, 51.00, 47.62, 50.10, 52.58, 53.88, 55.19
  167. };
  168. //spectral data for tungsten - incandescent 2856K
  169. private static double[] A2856_spect = {
  170. 4.75, 5.42, 6.15, 6.95, 7.83, 8.78, 9.80, 10.91, 12.09, 13.36, 14.72, 16.16, 17.69, 19.30, 21.01, 22.80, 24.68, 26.65, 28.71, 30.86, 33.10, 35.42, 37.82, 40.31, 42.88, 45.53, 48.25, 51.05, 53.92, 56.87, 59.87, 62.94, 66.07, 69.26, 72.50,
  171. 75.80, 79.14, 82.53, 85.95, 89.42, 92.91, 96.44, 100.00, 103.58, 107.18, 110.80, 114.43, 118.07, 121.72, 125.38, 129.03, 132.68, 136.33, 139.97, 143.60, 147.21, 150.81, 154.39, 157.95, 161.48, 164.99, 168.47, 171.92, 175.34,
  172. 178.72, 182.07, 185.38, 188.65, 191.88, 195.06, 198.20, 201.30, 204.34, 207.34, 210.29, 213.19, 216.04, 218.84, 221.58, 224.28, 226.91, 229.49, 232.02, 234.49, 236.91, 239.27, 241.57, 243.82, 246.01, 248.14, 250.21, 252.23, 254.19,
  173. 256.10, 257.95, 259.74, 261.47
  174. };
  175. //spectral data for fluo F1 Daylight 6430K
  176. private static double[] FluoF1_spect = {
  177. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.87, 2.36, 2.94, 3.47, 5.17, 19.49, 6.13, 6.24, 7.01, 7.79, 8.56, 43.67, 16.94, 10.72, 11.35, 11.89, 12.37, 12.75, 13.00, 13.15, 13.23, 13.17, 13.13, 12.85, 12.52,
  178. 12.20, 11.83, 11.50, 11.22, 11.05, 11.03, 11.18, 11.53, 27.74, 17.05, 13.55, 14.33, 15.01, 15.52, 18.29, 19.55, 15.48, 14.91, 14.15, 13.22, 12.19, 11.12, 10.03, 8.95, 7.96, 7.02, 6.20, 5.42, 4.73, 4.15, 3.64, 3.20, 2.81,
  179. 2.47, 2.18, 1.93, 1.72, 1.67, 1.43, 1.29, 1.19, 1.08, 0.96, 0.88, 0.81, 0.77, 0.75, 0.73, 0.68, 0.69, 0.64, 0.68, 0.69, 0.61, 0.52, 0.43, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  180. };
  181. //spectral data for fluo F2 Cool white 4230K
  182. private static double[] FluoF2_spect = {
  183. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.18, 1.48, 1.84, 2.15, 3.44, 15.69, 3.85, 3.74, 4.19, 4.62, 5.06, 34.98, 11.81, 6.27, 6.63, 6.93, 7.19, 7.40, 7.54, 7.62, 7.65, 7.62, 7.62, 7.45, 7.28, 7.15, 7.05, 7.04, 7.16, 7.47, 8.04, 8.88, 10.01, 24.88, 16.64, 14.59, 16.16, 17.60, 18.62, 21.47, 22.79, 19.29, 18.66, 17.73, 16.54, 15.21, 13.80, 12.36, 10.95, 9.65, 8.40, 7.32, 6.31, 5.43, 4.68, 4.02, 3.45,
  184. 2.96, 2.55, 2.19, 1.89, 1.64, 1.53, 1.27, 1.10, 0.99, 0.88, 0.76, 0.68, 0.61, 0.56, 0.54, 0.51, 0.47, 0.47, 0.43, 0.46, 0.47, 0.40, 0.33, 0.27, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  185. };
  186. //spectral data for fluo F3 White 3450K
  187. private static double[] FluoF3_spect = {
  188. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.82, 1.02, 1.26, 1.44, 2.57, 14.36, 2.70, 2.45, 2.73, 3.00, 3.28, 31.85, 9.47, 4.02, 4.25, 4.44, 4.59, 4.72, 4.80, 4.86, 4.87, 4.85, 4.88, 4.77, 4.67, 4.62, 4.62, 4.73, 4.99, 5.48, 6.25,
  189. 7.34, 8.78, 23.82, 16.14, 14.59, 16.63, 18.49, 19.95, 23.11, 24.69, 21.41, 20.85, 19.93, 18.67, 17.22, 15.65, 14.04, 12.45, 10.95, 9.51, 8.27, 7.11, 6.09, 5.22, 4.45, 3.80, 3.23, 2.75, 2.33, 1.99, 1.70, 1.55,
  190. 1.27, 1.09, 0.96, 0.83, 0.71, 0.62, 0.54, 0.49, 0.46, 0.43, 0.39, 0.39, 0.35, 0.38, 0.39, 0.33, 0.28, 0.21, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  191. };
  192. //spectral data for fluo F4 Warm white 2940K
  193. private static double[] FluoF4_spect = {
  194. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.57, 0.70, 0.87, 0.98, 2.01, 13.75, 1.95, 1.59, 1.76, 1.93, 2.10, 30.28, 8.03, 2.55, 2.70, 2.82, 2.91, 2.99, 3.04, 3.08, 3.09, 3.09, 3.14, 3.06, 3.00, 2.98, 3.01,
  195. 3.14, 3.41, 3.90, 4.69, 5.81, 7.32, 22.59, 15.11, 13.88, 16.33, 18.68, 20.64, 24.28, 26.26, 23.28, 22.94, 22.14, 20.91, 19.43, 17.74, 16.00, 14.42, 12.56, 10.93, 9.52, 8.18, 7.01, 6.00, 5.11, 4.36, 3.69, 3.13, 2.64,
  196. 2.24, 1.91, 1.70, 1.39, 1.18, 1.03, 0.88, 0.74, 0.64, 0.54, 0.49, 0.46, 0.42, 0.37, 0.37, 0.33, 0.35, 0.36, 0.31, 0.26, 0.19, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  197. };
  198. //spectral data for fluo F5 Daylight 6350K
  199. private static double[] FluoF5_spect = {
  200. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.87, 2.35, 2.92, 3.45, 5.10, 18.91, 6.00, 6.11, 6.85, 7.58, 8.31, 40.76, 16.06, 10.32, 10.91, 11.40, 11.83, 12.17, 12.40, 12.54, 12.58, 12.52, 12.47, 12.20, 11.89,
  201. 11.61, 11.33, 11.10, 10.96, 10.97, 11.16, 11.54, 12.12, 27.78, 17.73, 14.47, 15.20, 15.77, 16.10, 18.54, 19.50, 15.39, 14.64, 13.72, 12.69, 11.57, 10.45, 9.35, 8.29, 7.32, 6.41, 5.63, 4.90, 4.26,
  202. 3.72, 3.25, 2.83, 2.49, 2.19, 1.93, 1.71, 1.52, 1.43, 1.26, 1.13, 1.05, 0.96, 0.85, 0.78, 0.72, 0.68, 0.67, 0.65, 0.61, 0.62, 0.59, 0.62, 0.64, 0.55, 0.47, 0.40, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  203. };
  204. //spectral data for fluo F6 Lite white 4150K
  205. private static double[] FluoF6_spect = {
  206. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.05, 1.31, 1.63, 1.90, 3.11, 14.8, 3.43, 3.30, 3.68, 4.07, 4.45, 32.61, 10.74, 5.48, 5.78, 6.03, 6.25, 6.41, 6.52, 6.58, 6.59, 6.56, 6.56, 6.42, 6.28, 6.20, 6.19, 6.30, 6.60, 7.12, 7.94, 9.07, 10.49, 25.22, 17.46, 15.63, 17.22, 18.53,
  207. 19.43, 21.97, 23.01, 19.41, 18.56, 17.42, 16.09, 14.64, 13.15, 11.68, 10.25, 8.96, 7.74, 6.69, 5.71, 4.87, 4.16, 3.55, 3.02, 2.57, 2.20, 1.87, 1.60, 1.37, 1.29, 1.05, 0.91, 0.81, 0.71, 0.61, 0.54, 0.48, 0.44,
  208. 0.43, 0.40, 0.37, 0.38, 0.35, 0.39, 0.41, 0.33, 0.26, 0.21, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  209. };
  210. //spectral data for fluo F7 D65 Daylight simulator 6500K
  211. private static double[] FluoF7_spect = {
  212. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.56, 3.18, 3.84, 4.53, 6.15, 19.37, 7.37, 7.05, 7.71, 8.41, 9.15, 44.14, 17.52, 11.35, 12.00, 12.58, 13.08, 13.45, 13.71, 13.88, 13.95, 13.93, 13.82, 13.64, 13.43, 13.25, 13.08, 12.93, 12.78, 12.60,
  213. 12.44, 12.33, 12.26, 29.52, 17.05, 12.44, 12.58, 12.72, 12.83, 15.46, 16.75, 12.83, 12.67, 12.43, 12.19, 11.89, 11.60, 11.35, 11.12, 10.95, 10.76, 10.42, 10.11, 10.04, 10.02, 10.11, 9.87, 8.65, 7.27, 6.44, 5.83, 5.41,
  214. 5.04, 4.57, 4.12, 3.77, 3.46, 3.08, 2.73, 2.47, 2.25, 2.06, 1.90, 1.75, 1.62, 1.54, 1.45, 1.32, 1.17, 0.99, 0.81, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  215. };
  216. //spectral data for fluo F8 D50 simulator Sylvania F40 Design 5000K
  217. private static double[] FluoF8_spect = {
  218. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.21, 1.5, 1.81, 2.13, 3.17, 13.08, 3.83, 3.45, 3.86, 4.42, 5.09, 34.1, 12.42, 7.68, 8.60, 9.46, 10.24, 10.84, 11.33, 11.71, 11.98, 12.17, 12.28, 12.32, 12.35, 12.44, 12.55, 12.68, 12.77, 12.72,
  219. 12.60, 12.43, 12.22, 28.96, 16.51, 11.79, 11.76, 11.77, 11.84, 14.61, 16.11, 12.34, 13.61, 13.87, 14.07, 14.20, 14.16, 14.13, 14.34, 14.50, 14.46, 14.00, 12.58, 10.99, 9.98, 9.22, 8.62, 8.07, 7.39, 6.71, 6.16, 5.63, 5.03, 4.46, 4.02, 3.66,
  220. 3.36, 3.09, 2.85, 2.65, 2.51, 2.37, 2.15, 1.89, 1.61, 1.32, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  221. };
  222. //spectral data for fluo F9 Cool white deluxe 4150K
  223. private static double[] FluoF9_spect = {
  224. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.9, 1.12, 1.36, 1.60, 2.59, 12.8, 3.05, 2.56, 2.86, 3.30, 3.82, 32.62, 10.77, 5.84, 6.57, 7.25, 7.86, 8.35, 8.75, 9.06, 9.31, 9.48, 9.61, 9.68, 10.04, 10.26, 10.48, 10.63, 10.76, 10.96,
  225. 11.18, 27.71, 16.29, 12.28, 12.74, 13.21, 13.65, 16.57, 18.14, 14.55, 14.65, 14.66, 14.61, 14.50, 14.39, 14.40, 14.47, 14.62, 14.72, 14.55, 14.4, 14.58, 14.88, 15.51, 15.47, 13.20, 10.57, 9.18, 8.25, 7.57, 7.03,
  226. 6.35, 5.72, 5.25, 4.80, 4.29, 3.80, 3.43, 3.12, 2.86, 2.64, 2.43, 2.26, 2.14, 2.02, 1.83, 1.61, 1.38, 1.12, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  227. };
  228. //spectral data for fluo F10 Philips TL85 - 5000K
  229. private static double[] FluoF10_spect = {
  230. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.11, 0.63, 0.62, 0.57, 1.48, 12.16, 2.12, 2.70, 3.74, 5.14, 6.75, 34.39, 14.86, 10.4, 10.76, 10.11, 9.27, 8.29, 7.29, 7.91, 16.64, 16.73, 10.44, 5.94, 3.34, 2.35, 1.88, 1.59, 1.47,
  231. 1.80, 5.71, 40.98, 73.69, 33.61, 8.24, 3.38, 2.47, 4.86, 11.45, 14.79, 12.16, 8.97, 6.52, 8.81, 44.12, 34.55, 12.09, 12.15, 10.52, 4.43, 1.95, 2.19, 3.19, 2.77, 2.29, 2.00, 1.52, 1.35, 1.47, 1.79, 1.74, 1.02, 1.14,
  232. 3.32, 4.49, 2.05, 0.49, 0.24, 0.21, 0.21, 0.24, 0.24, 0.21, 0.17, 0.21, 0.22, 0.17, 0.12, 0.09, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  233. };
  234. //spectral data for fluo F11 Philips TL84 4150K
  235. private static double[] FluoF11_spect = {
  236. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.91, 0.63, 0.46, 0.37, 1.29, 12.68, 1.59, 1.79, 2.46, 3.38, 4.49, 33.94, 12.13, 6.95, 7.19, 7.12, 6.72, 6.13, 5.46, 4.79, 5.66, 14.29, 14.96, 8.97, 4.72, 2.33, 1.47, 1.10, 0.89, 0.83, 1.18, 4.90, 39.59,
  237. 72.84, 32.61, 7.52, 2.83, 1.96, 1.67, 4.43, 11.28, 14.76, 12.73, 9.74, 7.33, 9.72, 55.27, 42.58, 13.18, 13.16, 12.26, 5.11, 2.07, 2.34, 3.58, 3.01, 2.48, 2.14, 1.54, 1.33, 1.46, 1.94, 2.00, 1.20, 1.35, 4.10, 5.58,
  238. 2.51, 0.57, 0.27, 0.23, 0.21, 0.24, 0.24, 0.20, 0.24, 0.32, 0.26, 0.16, 0.12, 0.09, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  239. };
  240. //spectral data for fluo F12 Philips TL83 3000K
  241. private static double[] FluoF12_spect = {
  242. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.96, 0.64, 0.45, 0.33, 1.19, 12.48, 1.12, 0.94, 1.08, 1.37, 1.78, 29.05, 7.90, 2.65, 2.71, 2.65, 2.49, 2.33, 2.10, 1.91, 3.01, 10.83, 11.88, 6.88, 3.43, 1.49, 0.92, 0.71, 0.60, 0.63, 1.10, 4.56, 34.4, 65.40, 29.48,
  243. 7.16, 3.08, 2.47, 2.27, 5.09, 11.96, 15.32, 14.27, 11.86, 9.28, 12.31, 68.53, 53.02, 14.67, 14.38, 14.71, 6.46, 2.57, 2.75, 4.18, 3.44, 2.81, 2.42, 1.64, 1.36, 1.49, 2.14, 2.34, 1.42, 1.61, 5.04, 6.98, 3.19, 0.71, 0.30, 0.26, 0.23, 0.28, 0.28, 0.21,
  244. 0.17, 0.21, 0.19, 0.15, 0.10, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  245. };
  246. //spectral data for HMI lamp studio "Osram" 4800K (for film, spectacle, studio...)
  247. private static double[] HMI_spect = {
  248. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 9.66, 11.45, 13.24, 14.93, 16.63, 17.90, 19.20, 20.12, 21.03, 23.84, 26.65, 26.38, 26.12, 26.52, 27.92, 31.15, 34.37, 34.98, 35.61, 35.71, 35.81, 34.90, 34.02, 34.06, 34.08, 34.68, 35.28, 34.72, 34.20, 33.63,
  249. 33.05, 34.70, 36.35, 38.01, 39.48, 37.29, 35.10, 36.22, 37.28, 38.76, 40.24, 39.56, 38.90, 39.35, 39.79, 38.90, 38.01, 38.05, 38.10, 37.45, 36.64, 35.82, 35.00, 35.06, 33.13, 33.85, 34.55, 35.26, 35.77, 34.92,
  250. 34.09, 33.40, 32.72, 32.08, 31.45, 26.83, 22.23, 21.50, 20.79, 21.41, 22.03, 11.01, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  251. };
  252. //spectral data for GTI lamp : Graphiclite & ColorMatch for Photography 5000K
  253. private static double[] GTI_spect = {
  254. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.26, 4.71, 6.17, 12.71, 19.27, 20.53, 21.80, 19.15, 16.53, 28.25, 39.97, 48.52, 57.06, 43.66, 30.27, 30.22, 30.16, 31.48, 32.98, 34.01, 35.04, 35.83, 36.62, 37.12, 37.62, 37.99, 38.19, 38.29, 38.48,
  255. 38.82, 39.16, 45.40, 51.63, 51.83, 62.04, 52.41, 42.80, 42.95, 43.09, 45.64, 48.20, 46.23, 44.27, 43.74, 43.22, 43.30, 43.41, 43.10, 42.78, 42.03, 41.29, 40.29, 39.29, 37.89, 36.58, 34.92, 33.27, 31.47, 29.68, 27.90,
  256. 26.13, 24.55, 22.98, 21.42, 19.86, 18.40, 16.92, 14.46, 13.99, 12.36, 11.73, 5.86, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  257. };
  258. //spectral data for JudgeIII Lamp D50
  259. private static double[] JudgeIII_spect = {
  260. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.08, 4.25, 4.43, 6.90, 9.40, 9.75, 10.11, 9.30, 8.54, 14.90, 21.16, 26.01, 30.83, 24.90, 19.00, 19.00, 19.00, 19.56, 20.13, 20.28, 20.44, 20.64, 20.85, 21.05, 21.24, 21.65, 22.11, 22.85, 23.58, 24.00, 24.43,
  261. 27.75, 31.27, 33.90, 36.59, 30.90, 25.32, 25.05, 24.76, 26.03, 27.31, 25.90, 24.48, 23.85, 23.29, 23.10, 22.94, 23.24, 23.53, 24.02, 24.52, 23.80, 23.13, 24.51, 25.76, 27.90, 29.15, 24.70, 20.25, 16.60, 12.98, 11.63, 10.27, 9.30, 8.34,
  262. 7.60, 6.91, 6.25, 5.67, 5.15, 4.68, 2.34, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  263. };
  264. //spectral data for Solux lamp : 3500K
  265. private static double[] Solux3500_spect = {
  266. 0.5268, 0.93, 1.3278, 1.51, 1.6987, 2.65, 3.6100, 3.80, 3.9927, 6.08, 8.1680, 11.02, 13.863, 15.66, 17.4600, 18.78, 20.130, 21.43, 22.749, 24.02, 25.290, 27.40, 29.504, 31.77, 34.031, 36.35, 38.672, 40.55, 42.426, 44.15, 45.865, 47.37, 48.879,
  267. 49.71, 50.531, 51.2, 51.872, 51.9, 51.928, 52.97, 54.015, 55.93, 57.846, 60.25, 62.650, 64.36, 66.065, 66.72, 67.369, 68.81, 70.260, 71.37, 72.487, 72.53, 72.578, 72.51, 72.447, 72.46, 72.471,
  268. 72.76, 73.047, 74.25, 75.449, 76.5, 77.543, 78.79, 80.040, 80.72, 81.394, 82.12, 82.840, 83.23, 83.614, 83.36, 83.100, 82.36, 81.615, 80.11, 78.606, 75.91, 73.221, 69.61, 66.006, 62.43, 58.844, 56.07, 53.292,
  269. 51.07, 48.839, 46.93, 45.013, 43.54, 42.070, 40.61, 39.150, 37.79, 36.425
  270. };
  271. //spectral data for Solux lamp : 4100K
  272. private static double[] Solux4100_spect = {
  273. 0.5717, 0.70, 0.8286, 1.16, 1.522, 2.01, 2.384, 3.45, 4.57, 6.46, 8.4548, 11.31, 14.205, 16.10, 17.949, 19.51, 21.068, 22.60, 24.197, 25.37, 26.566, 28.15, 29.742, 30.90, 32.060, 33.26, 34.481, 34.80, 35.130, 35.42, 35.697, 36.20, 36.763,
  274. 37.90, 39.004, 40.26, 41.494, 43.10, 44.690, 45.80, 46.900, 47.45, 47.885, 47.75, 47.635, 47.00, 46.410, 46.22, 46.058, 46.70, 47.344, 48.65, 50.005, 51.02, 52.045, 53.55, 55.075, 55.98, 56.823,
  275. 56.85, 56.884, 56.15, 55.523, 54.60, 53.732, 52.55, 51.425, 50.30, 49.1830, 48.76, 48.273, 48.22, 48.169, 49.92, 49.915, 51.90, 53.099, 54.95, 56.852, 58.45, 60.090, 61.67, 63.2530, 63.55, 63.834, 63.55, 63.468,
  276. 62.40, 61.373, 59.75, 58.1810, 56.25, 54.395, 51.90, 49.496, 47.05, 44.620
  277. };
  278. //spectral data for Solux lamp : near Daylight (for example "Musée d'Orsay") - 4700K
  279. private static double[] Solux4700_spect = {
  280. 0.4590, 0.83, 1.2011, 1.53, 1.8647, 2.15, 2.5338, 3.06, 3.5809, 3.99, 4.4137, 4.82, 5.2228, 5.63, 6.0387, 6.53, 6.9944, 7.55, 8.0266, 8.475, 8.9276, 8.90, 9.7840, 10.20, 10.6390, 11.00, 11.3600, 11.75, 12.1340, 12.36, 12.5880, 12.74, 12.8790,
  281. 13.07, 13.2560, 13.38, 13.5220, 13.41, 13.3070, 13.35, 13.3990, 13.37, 13.3420, 13.39, 13.4220, 13.65, 13.2710, 13.25, 13.2330, 13.12, 13.0110, 12.93, 12.8470, 12.805, 12.7630, 12.66, 12.5760, 12.563, 12.5490,
  282. 12.59, 12.6330, 12.617, 12.6010, 12.616, 12.6310, 12.6275, 12.6240, 12.70, 12.7710, 12.776, 12.7810, 12.786, 12.7950, 12.74, 12.6850, 12.64, 12.5950, 12.55, 12.5420, 12.43, 12.3180, 12.07, 11.8340, 11.72, 11.6190, 11.55, 11.5020,
  283. 11.32, 11.1510, 11.05, 10.9530, 10.80, 10.6550, 10.495, 10.4390, 10.31, 10.1790
  284. };
  285. //spectral data for Solux lamp : near Daylight 4400K - test National Gallery
  286. private static double[] NG_Solux4700_spect = {
  287. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 139, 152, 170, 185, 202, 223, 240, 257, 270, 282, 293, 305, 317, 329, 342, 355, 367, 378, 387, 395, 401, 405, 408, 411, 414, 415, 416, 415, 414, 414, 416, 419, 423, 427, 432, 437, 442, 447, 452,
  288. 456, 461, 467, 475, 483, 488, 490, 491, 490, 487, 485, 481, 477, 472, 466, 461, 455, 449, 442, 434, 427, 419, 411, 403, 395, 386, 377, 367, 359, 351, 343, 335, 327, 322, 316, 312, 306, 305, 301, 299, 299, 298,
  289. 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0
  290. };
  291. //spectral data for LED LSI Lumelex 2040 - test National Gallery
  292. private static double[] NG_LEDLSI2040_spect = {
  293. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.2, 0.5, 0.7, 0.6, 1.6, 1.7, 7.0, 16.6, 35.5, 64, 106, 162.5, 230.5, 272.2, 249, 213.4, 214, 227.6, 231.9, 233, 235.2, 241.4, 253.7, 270.3, 288.5, 306.2, 322.3, 337.6, 352.5, 367.2, 381.7, 395.9, 409.6, 416.2, 423.2, 429.7, 435.8, 442.8,
  294. 451.7, 464.2, 480.3, 501, 526.3, 555.9, 587.5, 625.4, 655.1, 681.7, 705.3, 721.5, 728.5, 729, 719.8, 702.5, 676.7, 646.2, 611.5, 571.7, 530.3, 488.3, 445.9, 404, 365.2, 326.8, 290.8, 257.6, 226.9, 199.8, 175.2, 154.2, 133.8, 116.4, 101.5, 88.5, 76.6, 67.3, 57.9, 50.7, 44.2, 38.2,
  295. 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0
  296. };
  297. //spectral data for LED CRS SP12 WWMR16 - test National Gallery
  298. private static double[] NG_CRSSP12WWMR16_spect = {
  299. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.14, 0.33, 1.31, 3.34, 7.9, 17.4, 36.5, 72.6, 145.4, 260.5, 359.2, 365.3, 303.1, 256.1, 221.7, 193.6, 185.8, 191.4, 207.3, 232.8, 257.5, 285.1, 310.5, 333.4, 351.5, 368.8, 383.7, 398.8, 411.6, 424.7, 435.6, 447.9, 459.7, 471.7,
  300. 484.6, 497.9, 512.3, 531.1, 548.9, 567.9, 587.5, 608.6, 625.3, 640.1, 648.6, 654.0, 654.3, 647.2, 633.9, 616.1, 590.5, 561.5, 526.5, 494.8, 457.9, 420.8, 382.4, 347.3, 309.9, 280.5, 249.2, 220.0, 194.9, 170.8, 149.1, 130.0, 112.3, 97.5, 84.9, 73.2, 63.1, 54.1, 45.6, 39.0, 32.6, 27.4,
  301. 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.0
  302. };
  303. //Data for flash :
  304. // in theory, should be the spectral data of each owner flash (Nikon, Canon, Sony ...) or studio flash (Profoto. ..)
  305. // but: 1) I did not, 2) the data vary depending on the power used ... so by default, although this is not true, I chose the values "Daylight" for temp...
  306. // CRI for flash near of 95 - 97 !!
  307. //spectral data for Flash daylight 5500K (Leica...)
  308. private static double[] Flash5500_spect = {
  309. 27.77, 29.17, 30.58, 32.02, 33.47, 33.00, 32.53, 35.28, 38.04, 49.46, 60.88, 64.68, 68.48, 69.99, 71.51, 69.68, 67.85, 76.70, 85.54, 91.74, 97.93, 99.17, 100.41, 100.14, 99.86, 101.28, 102.70, 100.37, 98.04, 99.35, 100.65,
  310. 100.66, 100.67, 100.32, 99.97, 102.08, 104.20, 103.15, 102.09, 102.53, 102.96, 101.48, 100.00, 98.61, 97.22, 97.49, 97.76, 94.60, 91.44, 92.94, 94.44, 94.80, 95.16, 94.70, 94.25, 92.36, 90.48, 91.42, 92.36, 90.63,
  311. 88.89, 89.62, 90.36, 92.18, 94.00, 92.00, 90.00, 84.86, 79.72, 81.30, 82.88, 83.88, 84.89, 77.58, 70.27, 74.80, 82.19, 85.03, 78.47, 71.91, 62.37, 52.82, 64.39, 75.96, 73.91, 71.85, 72.41, 72.97, 70.17, 67.38, 63.07,
  312. 58.75, 61.89, 65.02, 66.68, 68.34
  313. };
  314. //spectral data for Flash daylight 6000K (Canon, Pentax, Olympus,...Standard)
  315. private static double[] Flash6000_spect = {
  316. 36.00, 37.18, 38.36, 40.36, 42.35, 41.77, 41.19, 43.79, 46.40, 59.24, 72.09, 76.15, 80.22, 81.47, 82.71, 80.12, 77.52, 86.54, 95.56, 101.70, 107.85, 108.66, 109.46, 108.57, 107.68, 108.65, 109.61, 106.63, 103.65, 104.42,
  317. 105.19, 104.79, 104.39, 103.45, 102.51, 104.28, 106.05, 104.68, 103.31, 103.42, 103.54, 101.77, 100.00, 98.38, 96.75, 96.74, 96.72, 93.30, 89.89, 90.92, 91.95, 91.99, 92.03, 91.30, 90.57, 88.51, 86.45, 86.96,
  318. 87.47, 85.66, 83.85, 84.21, 84.57, 85.95, 87.32, 85.31, 83.30, 78.66, 74.03, 75.24, 76.45, 77.68, 78.91, 72.13, 65.35, 69.67, 73.98, 76.68, 79.39, 73.29, 67.19, 58.19, 49.19, 59.98, 70.77, 68.91, 67.05, 67.55, 68.05,
  319. 65.47, 62.88, 58.89, 54.90, 57.81, 60.72, 62.25, 63.78
  320. };
  321. //spectral data for Flash daylight 6500K (Nikon, Minolta, Panasonic, Sony...)
  322. private static double[] Flash6500_spect = {
  323. 44.86, 45.72, 46.59, 49.16, 51.74, 50.83, 49.92, 52.26, 54.60, 68.65, 82.69, 87.06, 91.42, 92.39, 93.37, 90.00, 86.63, 95.72, 104.81, 110.88, 116.96, 117.36, 117.76, 116.29, 114.82, 115.35, 115.89, 112.33, 108.78, 109.06,
  324. 109.33, 108.56, 107.78, 106.28, 104.78, 106.23, 107.68, 106.04, 104.40, 104.22, 104.04, 102.02, 100.00, 98.17, 96.34, 96.06, 95.79, 92.24, 88.69, 89.35, 90.02, 89.81, 89.61, 88.66, 87.71, 85.51, 83.30, 83.51, 83.72,
  325. 81.88, 80.05, 80.14, 80.24, 81.27, 82.30, 80.31, 78.31, 74.03, 69.74, 70.69, 71.63, 73.00, 74.37, 68.00, 61.62, 65.76, 69.91, 72.51, 75.11, 69.36, 63.61, 55.02, 46.43, 56.63, 66.83, 65.11, 63.40, 63.86, 64.32, 61.90, 59.47,
  326. 55.72, 51.97, 54.72, 57.46, 58.89, 60.33
  327. };
  328. //
  329. private static Dictionary<string, double[]> spectMap = new Dictionary<string, double[]>()
  330. {
  331. {"Daylight", Daylight5300_spect},
  332. {"Cloudy", Cloudy6200_spect},
  333. {"Shade", Shade7600_spect},
  334. {"Tungsten", A2856_spect},
  335. {"Fluo F1", FluoF1_spect},
  336. {"Fluo F2", FluoF2_spect},
  337. {"Fluo F3", FluoF3_spect},
  338. {"Fluo F4", FluoF4_spect},
  339. {"Fluo F5", FluoF5_spect},
  340. {"Fluo F6", FluoF6_spect},
  341. {"Fluo F7", FluoF7_spect},
  342. {"Fluo F8", FluoF8_spect},
  343. {"Fluo F9", FluoF9_spect},
  344. {"Fluo F10", FluoF10_spect},
  345. {"Fluo F11", FluoF11_spect},
  346. {"Fluo F12", FluoF12_spect},
  347. {"HMI Lamp", HMI_spect},
  348. {"GTI Lamp", GTI_spect},
  349. {"JudgeIII Lamp", JudgeIII_spect},
  350. {"Solux Lamp 3500K", Solux3500_spect},
  351. {"Solux Lamp 4100K", Solux4100_spect},
  352. {"Solux Lamp 4700K", Solux4700_spect},
  353. {"NG Solux Lamp 4700K", NG_Solux4700_spect},
  354. {"LED LSI Lumelex 2040", NG_LEDLSI2040_spect},
  355. {"LED CRS SP12 WWMR16", NG_CRSSP12WWMR16_spect},
  356. {"Flash 5500K", Flash5500_spect},
  357. {"Flash 6000K", Flash6000_spect},
  358. {"Flash 6500K", Flash6500_spect}
  359. };
  360. private static double[][] sRGBd65_xyz = {
  361. new double[]{ 3.2404542, -1.5371385, -0.4985314},
  362. new double[]{ -0.9692660, 1.8760108, 0.0415560},
  363. new double[]{0.0556434, -0.2040259, 1.0572252}
  364. };
  365. // Data for Color ==> CRI (Color Rendering Index and Palette
  366. // actually 20 color that must be good enough for CRI
  367. // I think 40 color for palette (Skin, Sky, gray)
  368. //spectral data Colorchecker24 : Red C3
  369. private static double[] ColorchechredC3_spect = {
  370. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  371. 0.0478, 0.0476, 0.0474, 0.0472, 0.0470, 0.0466, 0.0461, 0.0460, 0.0459, 0.0456, 0.0453, 0.0451, 0.0449, 0.0448, 0.0447, 0.0446, 0.0445, 0.0441, 0.0437, 0.0432, 0.0427, 0.0424, 0.0421, 0.0419,
  372. 0.0417, 0.0415, 0.0412, 0.0412, 0.0412, 0.0413, 0.0413, 0.0415, 0.0416, 0.0421, 0.0426, 0.0436, 0.0446, 0.0469, 0.0491, 0.0549, 0.0607, 0.0773, 0.0939, 0.1376, 0.1812, 0.2568, 0.3323, 0.4070, 0.4816, 0.5308,
  373. 0.5800, 0.6059, 0.6317, 0.6447, 0.6577, 0.6653, 0.6728, 0.6761, 0.6793, 0.6820, 0.6847, 0.6878, 0.6909, 0.6945, 0.6980, 0.7013, 0.7046, 0.7065, 0.7084, 0.7107, 0.7129, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  374. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  375. };
  376. //spectral data Colorchecker24 : Orange A2
  377. private static double[] ColorchechOraA2_spect = {
  378. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  379. 0.0520, 0.0530, 0.0540, 0.0535, 0.0530, 0.0532, 0.0534, 0.0532, 0.0529, 0.0529, 0.0528, 0.0530, 0.0532, 0.0537, 0.0542, 0.0550, 0.0557, 0.0565, 0.0573, 0.0585, 0.0597, 0.0613, 0.0628, 0.0656, 0.0683, 0.0793,
  380. 0.0902, 0.1085, 0.1268, 0.1414, 0.1559, 0.1645, 0.1730, 0.1837, 0.1944, 0.2184, 0.2424, 0.2877, 0.3329, 0.3923, 0.4517, 0.5021, 0.5525, 0.5739, 0.5952, 0.5967, 0.5982, 0.5962, 0.5942, 0.5932, 0.5922, 0.5927,
  381. 0.5932, 0.5938, 0.5944, 0.5988, 0.6032, 0.6105, 0.6178, 0.6284, 0.6389, 0.6498, 0.6607, 0.6699, 0.6791, 0.6839, 0.6886, 0.6879, 0.6871, 0.6886, 0.6901, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  382. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  383. };
  384. //spectral data Colorchecker24 :yellow D3
  385. private static double[] ColorchechYelD3_spect = {
  386. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  387. 0.0476, 0.0482, 0.0488, 0.0492, 0.0496, 0.0498, 0.0499, 0.0498, 0.0496, 0.0501, 0.0506, 0.0516, 0.0526, 0.0547, 0.0567, 0.0610, 0.0652, 0.0733, 0.0813, 0.0962, 0.1110, 0.1333, 0.1556, 0.1884, 0.2211,
  388. 0.2782, 0.3353, 0.4023, 0.4692, 0.5198, 0.5703, 0.5976, 0.6249, 0.6400, 0.6551, 0.6667, 0.6783, 0.6901, 0.7018, 0.7095, 0.7171, 0.7231, 0.7290, 0.7329, 0.7367, 0.7395, 0.7423, 0.7447, 0.7471, 0.7490, 0.7508,
  389. 0.7533, 0.7558, 0.7578, 0.7598, 0.7623, 0.7647, 0.7654, 0.7661, 0.7677, 0.7693, 0.7720, 0.7746, 0.7780, 0.7814, 0.7845, 0.7876, 0.7889, 0.7902, 0.7920, 0.7938,
  390. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  391. };
  392. //spectral data Colorchecker24 : Green E2
  393. private static double[] ColorchechGreE2_spect = {
  394. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  395. 0.0560, 0.0583, 0.0605, 0.0626, 0.0646, 0.0650, 0.0653, 0.0657, 0.0661, 0.0669, 0.0676, 0.0692, 0.0708, 0.0737, 0.0765, 0.0816, 0.0867, 0.0956, 0.1044, 0.1194, 0.1344, 0.1581, 0.1818, 0.2196, 0.2574, 0.3166, 0.3757,
  396. 0.4297, 0.4837, 0.5142, 0.5446, 0.5541, 0.5636, 0.5608, 0.5579, 0.5480, 0.5381, 0.5258, 0.5135, 0.4959, 0.4783, 0.4570, 0.4356, 0.4124, 0.3891, 0.3710, 0.3529, 0.3425, 0.3320, 0.3266, 0.3211, 0.3180, 0.3149,
  397. 0.3129, 0.3108, 0.3123, 0.3137, 0.3193, 0.3248, 0.3335, 0.3422, 0.3518, 0.3613, 0.3693, 0.3772, 0.3810, 0.3847, 0.3838, 0.3829, 0.3838, 0.3847, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  398. };
  399. //const double ColorTemp::ColorGreenM25_spect[97] = {
  400. // 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  401. // 0.0758, 0.0614, 0.0662, 0.0591, 0.0648, 0.0633, 0.0671, 0.0613, 0.0621, 0.0610, 0.0680, 0.0690, 0.0784, 0.0830, 0.0920, 0.1070, 0.1231, 0.1423, 0.1607, 0.1731, 0.1816, 0.1911, 0.1951, 0.1986, 0.1915, 0.1889,
  402. // 0.1758, 0.1673, 0.1606, 0.1505, 0.1384, 0.1317, 0.1230, 0.1149, 0.1081, 0.0992, 0.0882, 0.0785, 0.0709, 0.0629, 0.0550, 0.0502, 0.0486, 0.0474, 0.0445, 0.0434, 0.0429, 0.0423, 0.0411, 0.0405, 0.0397, 0.0387, 0.0399, 0.0398, 0.0398, 0.0407, 0.0408, 0.0426, 0.0445, 0.0443, 0.0468,
  403. // 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  404. //};
  405. ////0 658 45 0 0 131 98 84 123 104 131 112 121 121 139 128 148 199 296 389 476 689 945 1132 1326 1490 1674 1741 1775 1868 1914 1928 1961 1972 1992 2045 2064 2053 2048 2072 2086 2081 2069 2056 2073 2096 2114 2067 2089 2100 2061 2019 1983 1971 1961 2016 1956 1946 1922 1983 1991
  406. //const double ColorTemp::ColorYellowkeltano_spect[97] = {
  407. // 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  408. // 0.0, 0.0658, 0.0045, 0.0, 0.0, 0.0131, 0.0098, 0.0084, 0.0123, 0.0104, 0.0131, 0.0112, 0.0121, 0.0121, 0.0139,
  409. // 0.0128, 0.0148, 0.0199, 0.0296, 0.0389, 0.0476, 0.0689, 0.0945, 0.1132, 0.1326, 0.1490, 0.1674, 0.1741, 0.1775, 0.1868,
  410. // 0.1914, 0.1928, 0.1961, 0.1972, 0.1992, 0.2045, 0.2064, 0.2053, 0.2048, 0.2072, 0.2086, 0.2081, 0.2069, 0.2056, 0.2073,
  411. // 0.2096, 0.2114, 0.2067, 0.2089, 0.2100, 0.2061, 0.2019, 0.1983, 0.1971, 0.1961, 0.2016, 0.1956, 0.1946, 0.1922, 0.1983, 0.1991,
  412. // 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  413. //};
  414. //spectral data Colorchecker24 : Green B3
  415. private static double[] ColorchechGreB3_spect = {
  416. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  417. 0.0531, 0.0545, 0.0559, 0.0563, 0.0566, 0.0571, 0.0576, 0.0576, 0.0575, 0.0581, 0.0586, 0.0596, 0.0606, 0.0629, 0.0652, 0.0699, 0.0745, 0.0839, 0.0932, 0.1101, 0.1270, 0.1521, 0.1771, 0.2098, 0.2424,
  418. 0.2789, 0.3154, 0.3312, 0.3470, 0.3431, 0.3392, 0.3303, 0.3213, 0.3089, 0.2964, 0.2788, 0.2612, 0.2442, 0.2271, 0.2117, 0.1962, 0.1815, 0.1667, 0.1527, 0.1386, 0.1284, 0.1182, 0.1124, 0.1066, 0.1035, 0.1003,
  419. 0.0987, 0.0971, 0.0961, 0.0950, 0.0950, 0.0950, 0.0962, 0.0973, 0.0994, 0.1014, 0.1045, 0.1075, 0.1106, 0.1137, 0.1157, 0.1176, 0.1175, 0.1173, 0.1173, 0.1173,
  420. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  421. };
  422. //spectral data Colorchecker24 : Cyan F3
  423. private static double[] ColorchechCyaF3_spect = {
  424. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  425. 0.0813, 0.1048, 0.1282, 0.1611, 0.1940, 0.2198, 0.2456, 0.2575, 0.2693, 0.2807, 0.2921, 0.3079, 0.3237, 0.3424, 0.3611, 0.3820, 0.4029, 0.4234, 0.4439, 0.4547, 0.4654, 0.4638, 0.4621, 0.4482, 0.4342, 0.4119, 0.3895,
  426. 0.3656, 0.3417, 0.3160, 0.2903, 0.2654, 0.2404, 0.2167, 0.1929, 0.1720, 0.1510, 0.1368, 0.1226, 0.1138, 0.1049, 0.0993, 0.0936, 0.0890, 0.0844, 0.0810, 0.0776, 0.0759, 0.0742, 0.0733, 0.0724, 0.0723, 0.0722, 0.0727,
  427. 0.0732, 0.0745, 0.0757, 0.0763, 0.0768, 0.0764, 0.0759, 0.0748, 0.0736, 0.0723, 0.0710, 0.0703, 0.0696, 0.0707, 0.0718, 0.0756, 0.0793, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  428. };
  429. //spectral data Colorchecker24 : Purple D2
  430. private static double[] ColorchechPurD2_spect = {
  431. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  432. 0.0854, 0.1047, 0.1240, 0.1468, 0.1696, 0.1826, 0.1955, 0.1963, 0.1970, 0.1910, 0.1849, 0.1750, 0.1651, 0.1541, 0.1430, 0.1322, 0.1213, 0.1117, 0.1020, 0.0944, 0.0868, 0.0809, 0.0750, 0.0703, 0.0655,
  433. 0.0627, 0.0599, 0.0583, 0.0567, 0.0550, 0.0533, 0.0525, 0.0517, 0.0518, 0.0519, 0.0523, 0.0526, 0.0525, 0.0524, 0.0520, 0.0516, 0.0523, 0.0529, 0.0560, 0.0591, 0.0662, 0.0732, 0.0828, 0.0924, 0.1021,
  434. 0.1117, 0.1222, 0.1327, 0.1469, 0.1610, 0.1796, 0.1981, 0.2173, 0.2365, 0.2532, 0.2698, 0.2826, 0.2953, 0.3022, 0.3090, 0.3126, 0.3161, 0.3238, 0.3314, 0.3504, 0.3694, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  435. };
  436. //spectral data Colorchecker24 : Magenta E3
  437. private static double[] ColorchechMagE3_spect = {
  438. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  439. 0.1112, 0.1438, 0.1763, 0.2294, 0.2824, 0.3188, 0.3552, 0.3623, 0.3693, 0.3653, 0.3612, 0.3510, 0.3407, 0.3269, 0.3130, 0.2981, 0.2832, 0.2686, 0.2539, 0.2385, 0.2230, 0.2083, 0.1935, 0.1818, 0.1700, 0.1600, 0.1499,
  440. 0.1394, 0.1288, 0.1188, 0.1088, 0.1051, 0.1014, 0.1026, 0.1038, 0.1041, 0.1043, 0.1064, 0.1085, 0.1225, 0.1364, 0.1701, 0.2037, 0.2532, 0.3027, 0.3587, 0.4147, 0.4683, 0.5219, 0.5672, 0.6124, 0.6455, 0.6785, 0.7009,
  441. 0.7232, 0.7391, 0.7550, 0.7629, 0.7707, 0.7737, 0.7766, 0.7778, 0.7790, 0.7803, 0.7815, 0.7835, 0.7854, 0.7896, 0.7937, 0.8026, 0.8114, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  442. };
  443. //spectral data Colorchecker24 : Skin A1
  444. //use also for palette WB
  445. private static double[] ColorchechSkiA138_13_14_spect = {
  446. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  447. 0.0479, 0.051, 0.0553, 0.058, 0.0610, 0.062, 0.0626, 0.0622, 0.0619, 0.0617, 0.0616, 0.0615, 0.0614, 0.0614, 0.0615, 0.0617, 0.0618, 0.0618, 0.0619, 0.0618, 0.0618, 0.062, 0.0622, 0.063, 0.0638, 0.066, 0.0696,
  448. 0.073, 0.0767, 0.078, 0.0801, 0.0807, 0.0817, 0.0831, 0.0845, 0.0870, 0.0902, 0.0955, 0.1017, 0.1096, 0.1175, 0.1250, 0.1336, 0.1385, 0.1435, 0.1455, 0.1479, 0.1490, 0.1514, 0.1547, 0.1580, 0.1625, 0.1675,
  449. 0.173, 0.1772, 0.181, 0.1842, 0.1846, 0.1853, 0.1831, 0.1811, 0.1788, 0.1765, 0.1769, 0.1773, 0.181, 0.1834, 0.1874, 0.1914, 0.1965, 0.2018, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  450. };
  451. //spectral data Colorchecker24 : Gray C4 L=67
  452. //use also for palette WB
  453. private static double[] ColorchechGraC4_67_spect = {
  454. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  455. 0.1074, 0.1380, 0.1704, 0.22, 0.2705, 0.305, 0.3409, 0.35, 0.3601, 0.3628, 0.3655, 0.3675, 0.3698, 0.371, 0.3724, 0.373, 0.3733, 0.3725, 0.3715, 0.3705, 0.3692,
  456. 0.369, 0.3689, 0.368, 0.3673, 0.3678, 0.3684, 0.37, 0.3711, 0.3712, 0.3714, 0.3714, 0.3714, 0.371, 0.3707, 0.37, 0.3694, 0.3697, 0.3703, 0.3697, 0.3692, 0.3688, 0.3685, 0.3675, 0.3669, 0.3657, 0.3647, 0.3635, 0.3625, 0.361,
  457. 0.3596, 0.3585, 0.3579, 0.357, 0.3560, 0.3555, 0.3548, 0.3535, 0.3526, 0.3513, 0.3500, 0.349, 0.3475, 0.3467, 0.3460, 0.3452, 0.3444, 0.3431, 0.3421, 0.3411, 0.3403, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  458. };
  459. //spectral data Colorchecker24 : Skin B1
  460. //use also for palette WB
  461. private static double[] ColorchechSkiB166_18_18_spect = {
  462. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  463. 0.0962, 0.114, 0.1328, 0.152, 0.1706, 0.1755, 0.1877, 0.189, 0.1903, 0.1913, 0.1923, 0.1946, 0.1971, 0.2015, 0.2064, 0.215, 0.2245, 0.239, 0.2535, 0.273, 0.2922, 0.31, 0.3274, 0.337, 0.3473,
  464. 0.348, 0.3489, 0.335, 0.3224, 0.303, 0.2835, 0.275, 0.2671, 0.27, 0.2728, 0.2735, 0.2741, 0.279, 0.2836, 0.308, 0.3334, 0.375, 0.4183, 0.457, 0.4950, 0.516, 0.5409, 0.5515, 0.5625, 0.568, 0.5731, 0.5786,
  465. 0.5820, 0.586, 0.5902, 0.596, 0.6025, 0.611, 0.6174, 0.627, 0.6375, 0.65, 0.6626, 0.677, 0.6910, 0.704, 0.7171, 0.723, 0.7339, 0.741, 0.7475,
  466. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  467. };
  468. //spectral data Colorchecker24 : blue sky C1
  469. //use also for palette WB
  470. private static double[] ColorchechBluC150_m5_m22_spect = {
  471. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  472. 0.1053, 0.134, 0.1633, 0.2075, 0.2518, 0.283, 0.3163, 0.324, 0.3325, 0.334, 0.3355, 0.3352, 0.3349, 0.332, 0.3294, 0.325, 0.3199, 0.3127, 0.3055, 0.2955, 0.2863, 0.28, 0.2737, 0.267, 0.2612, 0.249, 0.2378, 0.228, 0.2199,
  473. 0.218, 0.2173, 0.2146, 0.2118, 0.20, 0.1884, 0.178, 0.1682, 0.166, 0.1639, 0.162, 0.1613, 0.158, 0.1550, 0.1504, 0.1458, 0.1415, 0.1375, 0.135, 0.1327, 0.1316, 0.1305, 0.1304, 0.1302, 0.131, 0.1322, 0.1342, 0.1362,
  474. 0.1367, 0.1372, 0.1356, 0.1340, 0.1311, 0.1288, 0.1253, 0.1227, 0.1205, 0.1187, 0.1195, 0.1205, 0.1255, 0.1303, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  475. };
  476. //spectral data ColorcheckerDC : blue sky N8
  477. //use also for palette WB
  478. private static double[] ColorchechDCBluN881_m7_m14_spect = {
  479. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  480. 0.1371, 0.17, 0.2029, 0.291, 0.3790, 0.495, 0.6100, 0.67, 0.7249, 0.737, 0.7501, 0.7545, 0.7597, 0.764, 0.7677, 0.7685, 0.7693, 0.7677, 0.7662, 0.763, 0.7593, 0.753, 0.7471, 0.737, 0.7289, 0.718, 0.7077, 0.705, 0.6819, 0.666, 0.6515, 0.636, 0.6244,
  481. 0.61, 0.5948, 0.577, 0.5581, 0.544, 0.5293, 0.522, 0.5147, 0.512, 0.5091, 0.506, 0.5029, 0.499, 0.4950, 0.494, 0.4931, 0.497, 0.5007, 0.508, 0.5176, 0.527, 0.5359, 0.542, 0.5487, 0.549, 0.5494, 0.544,
  482. 0.5375, 0.531, 0.5244, 0.522, 0.5207, 0.524, 0.5264, 0.532, 0.5369, 0.542, 0.5505, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  483. };
  484. //spectral data ColorcheckerSG : Skin F7
  485. //use also for palette WB
  486. private static double[] ColorchechSGSkiF763_14_26_spect = {
  487. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0508, 0.064, 0.0776, 0.903, 0.1099, 0.1128, 0.1256, 0.128, 0.1307, 0.133, 0.1357, 0.139, 0.1425, 0.148, 0.1523, 0.159, 0.1669, 0.177, 0.1871, 0.20, 0.2118, 0.2235, 0.2355, 0.2445, 0.2537, 0.259, 0.2655, 0.268,
  488. 0.2700, 0.2708, 0.2716, 0.2743, 0.2770, 0.2803, 0.2827, 0.283, 0.2832, 0.283, 0.2828, 0.295, 0.3079, 0.344, 0.3803, 0.4105, 0.4409, 0.455, 0.4694, 0.477, 0.4851, 0.4896, 0.4962, 0.501, 0.5066, 0.511, 0.5160, 0.521,
  489. 0.5256, 0.529, 0.5318, 0.535, 0.5383, 0.541, 0.5451, 0.549, 0.5524, 0.556, 0.5597, 0.562, 0.5650, 0.568, 0.5709, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  490. };
  491. //spectral data ColorcheckerSG : Skin K2 85 11 17
  492. //use also for palette WB
  493. private static double[] ColorchechSGSkiK285_11_17_spect = {
  494. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  495. 0.1122, 0.149, 0.1866, 0.259, 0.3318, 0.393, 0.4547, 0.469, 0.4846, 0.4845, 0.4844, 0.4838, 0.4834, 0.4837, 0.4840, 0.4847, 0.4854, 0.4852, 0.4849, 0.4842, 0.4835, 0.4832, 0.4828, 0.485,
  496. 0.4874, 0.501, 0.5150, 0.536, 0.5572, 0.5685, 0.5798, 0.586, 0.5932, 0.5987, 0.6142, 0.6342, 0.6541, 0.683, 0.7119, 0.734, 0.7571, 0.769, 0.7829, 0.788, 0.7932, 0.795, 0.7968, 0.7973,
  497. 0.7977, 0.7974, 0.7969, 0.797, 0.7972, 0.7973, 0.7975, 0.7983, 0.7990, 0.7978, 0.7965, 0.7957, 0.7949, 0.7944, 0.7940, 0.794, 0.7941, 0.7943, 0.7946, 0.7938, 0.7930, 0.7929, 0.7928,
  498. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  499. };
  500. //spectral data Colorcheck24 : White A4 L=96
  501. //use also for palette WB
  502. private static double[] ColorchechWhiA496_spect = {
  503. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  504. 0.1267, 0.172, 0.2179, 0.317, 0.4164, 0.505, 0.6780, 0.758, 0.8397, 0.865, 0.8911, 0.897, 0.9035, 0.9062, 0.9092, 0.9124, 0.9154, 0.9167, 0.9180, 0.9187, 0.9194, 0.92, 0.9225, 0.9217, 0.9209, 0.921,
  505. 0.9212, 0.9227, 0.9242, 0.9235, 0.9227, 0.9232, 0.9238, 0.9243, 0.9248, 0.9237, 0.9227, 0.9239, 0.9252, 0.924, 0.9233, 0.9238, 0.9242, 0.924, 0.9239, 0.9239, 0.9239, 0.924, 0.9242, 0.9239,
  506. 0.9237, 0.925, 0.9264, 0.9276, 0.9288, 0.9298, 0.9308, 0.9296, 0.9284, 0.928, 0.9276, 0.928, 0.9284, 0.9294, 0.9304, 0.9316, 0.9328, 0.9328, 0.9328, 0.9337, 0.9345,
  507. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  508. };
  509. //spectral data Colorcheck24 : foliage Green D1
  510. private static double[] ColorchechGreD1_spect = {
  511. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  512. 0.0477, 0.0492, 0.0507, 0.0517, 0.0527, 0.0532, 0.0537, 0.054, 0.0544, 0.0554, 0.0563, 0.0573, 0.0584, 0.0592, 0.0601, 0.0607, 0.0611, 0.0613, 0.0619, 0.626, 0.0634, 0.0646, 0.0659, 0.069,
  513. 0.0721, 0.0837, 0.0958, 0.117, 0.1386, 0.156, 0.1748, 0.1802, 0.1855, 0.1795, 0.1742, 0.1636, 0.1529, 0.144, 0.1351, 0.13, 0.1239, 0.1202, 0.1171, 0.1138, 0.1106, 0.108, 0.1048, 0.1035,
  514. 0.1022, 0.1025, 0.1030, 0.1041, 0.1052, 0.106, 0.1068, 0.107, 0.1073, 0.1066, 0.1060, 0.1047, 0.1035, 0.1028, 0.1021, 0.1029, 0.1034, 0.105, 0.1069, 0.1086, 0.1104, 0.1127, 0.1150,
  515. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  516. };
  517. //spectral data ColorchecSG : black N3 L=6
  518. //use also for palette WB
  519. private static double[] ColorchechSGBlaN3_6_spect = {
  520. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  521. 0.0066, 0.0069, 0.0071, 0.0072, 0.0074, 0.0073, 0.0072, 0.0073, 0.0074, 0.0074, 0.0074, 0.0074, 0.0074, 0.0073, 0.0073, 0.0073, 0.0073, 0.0072, 0.0072, 0.0072, 0.0072, 0.0071, 0.0071, 0.0071,
  522. 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0070, 0.0070, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0071, 0.0070,
  523. 0.0070, 0.0070, 0.0070, 0.0069, 0.0069, 0.0069, 0.0068, 0.0068, 0.0068, 0.0068, 0.0068, 0.0068, 0.0067, 0.0067, 0.0067, 0.0067, 0.0066, 0.0066, 0.0066, 0.0066, 0.0066, 0.0066, 0.0066, 0.0067,
  524. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  525. };
  526. //spectral data 468 color : gray K14 L=44
  527. //use also for palette WB
  528. private static double[] JDC468_GraK14_44_spect = {
  529. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  530. 0.04240, 0.0485, 0.05500, 0.0624, 0.06930, 0.084, 0.09820, 0.109, 0.12160, 0.127, 0.13300, 0.13490, 0.13690, 0.1379, 0.13890, 0.1396, 0.14060, 0.1407, 0.14080, 0.1423, 0.14380, 0.1488, 0.15370, 0.157, 0.16040,
  531. 0.157, 0.15360, 0.1482, 0.14290, 0.1436, 0.14470, 0.1454, 0.14620, 0.137, 0.12870, 0.1205, 0.11250, 0.116, 0.11930, 0.1261, 0.13350, 0.1367, 0.13990, 0.139, 0.13810, 0.1371, 0.13610, 0.1372, 0.13820,
  532. 0.1408, 0.14330, 0.1475, 0.15170, 0.1583, 0.16500, 0.172, 0.17940, 0.1836, 0.18780, 0.188, 0.18820, 0.186, 0.18430, 0.1801, 0.17620, 0.1741, 0.17210, 0.179, 0.18420, 0.1991, 0.21430,
  533. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  534. };
  535. //spectral data 468 color : Blue H10 - Gamut > WidegamutRGB
  536. private static double[] JDC468_BluH10_spect = {
  537. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
  538. 0.01590, 0.028, 0.03970, 0.0697, 0.09970, 0.1526, 0.20550, 0.253, 0.30110, 0.3412, 0.38180, 0.423, 0.46610, 0.4683, 0.51030, 0.5005, 0.49950, 0.4785, 0.45810, 0.429, 0.39950, 0.374, 0.35010, 0.3135, 0.29630,
  539. 0.2587, 0.22070, 0.182, 0.14450, 0.1125, 0.09060, 0.072, 0.04810, 0.033, 0.01740, 0.0113, 0.00520, 0.004, 0.00290, 0.0028, 0.00270, 0.0027, 0.00270, 0.0027, 0.00280, 0.0027, 0.00270, 0.0028, 0.00280,
  540. 0.0029, 0.00300, 0.0029, 0.00290, 0.0029, 0.0029, 0.00290, 0.0029, 0.00290, 0.0029, 0.00290, 0.0029, 0.00290, 0.0029, 0.00290, 0.0029, 0.0031, 0.00320, 0.0035, 0.00380, 0.0047, 0.00560,
  541. 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  542. };
  543. /// <summary>
  544. /// 反色
  545. /// </summary>
  546. /// <param name="src"></param>
  547. /// <returns></returns>
  548. public static Mat ReverseColorFunction(Mat src)
  549. {
  550. return (~src.CvtColor(ColorConversionCodes.BGRA2BGR)).ToMat().CvtColor(ColorConversionCodes.BGR2BGRA);
  551. }
  552. #region 直方图方法
  553. /// <summary>
  554. /// 相机调用方法
  555. /// </summary>
  556. /// <param name="src"> 待处理的图像 </param>
  557. /// <param name="methodType"> 0 原图, 1 最佳, 2 最大最小</param>
  558. /// <param name="gamma45"> 是否计算伽马0.45 </param>
  559. /// <returns></returns>
  560. public static Mat CalHistMethod(Mat src, int methodType, bool gamma45)
  561. {
  562. Mat[] mats = Cv2.Split(src);//一张图片,将panda拆分成3个图片装进mat
  563. bool isGray = true;
  564. /// <summary>
  565. /// 一个矩阵数组,用来接收直方图,记得全部初始化
  566. /// </summary>
  567. Mat[] oldHists = new Mat[] { new Mat(), new Mat(), new Mat() };
  568. Mat[] mats0 = new Mat[] { mats[0] };//panda的第一个通道,也就是B
  569. Mat[] mats1 = new Mat[] { mats[1] };//panda的第二个通道,也就是G
  570. Mat[] mats2 = new Mat[] { mats[2] };//panda的第三个通道,也就是R
  571. int[] channels0 = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置一个就行
  572. int[] channels1 = new int[] { 0 };
  573. int[] channels2 = new int[] { 0 };
  574. int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子
  575. Rangef[] range = new Rangef[1];//一个通道,范围
  576. range[0] = new Rangef(0.0F, 256.0F);
  577. Mat mask = new Mat();//不做掩码
  578. Cv2.CalcHist(mats0, channels0, mask, oldHists[0], 1, histsize, range);//对被拆分的图片单独进行计算
  579. Cv2.CalcHist(mats1, channels1, mask, oldHists[1], 1, histsize, range);//对被拆分的图片单独进行计算
  580. Cv2.CalcHist(mats2, channels2, mask, oldHists[2], 1, histsize, range);//对被拆分的图片单独进行计算
  581. for (int h = 0; h < oldHists[0].Rows; h++)
  582. {
  583. for (int j = oldHists.Length - 1; j >= 1; j--)
  584. {
  585. if (oldHists[j].At<float>(h) != oldHists[0].At<float>(h))
  586. {
  587. isGray = false;
  588. break;
  589. }
  590. }
  591. if (!isGray)
  592. break;
  593. }
  594. //if (methodType == 0)
  595. //{
  596. //计算对比度
  597. string label6_Text = "1.00";// (256.0 / (startIndex.Y - startIndex.X)).ToString("f2");
  598. //计算亮度
  599. string label5_Text = "-0.50";// ((0 - startIndex.X - startIndex.Y) / 510.0).ToString("f2");
  600. //}
  601. if (methodType == 1)
  602. {
  603. //100 为千分比输入值,需要确认
  604. OpenCvSharp.Point startIndex = getStartIndex(src, oldHists, 100/*50*//*(float)numericUpDown1.Value*/, isGray);
  605. //计算对比度
  606. label6_Text = (256.0 / (startIndex.Y - startIndex.X)).ToString("f2");
  607. //计算亮度
  608. label5_Text = ((0 - startIndex.X - startIndex.Y) / 510.0).ToString("f2");
  609. }
  610. else if (methodType == 2)
  611. {
  612. //100 为千分比输入值,需要确认
  613. OpenCvSharp.Point startIndex = getStartIndex(src, oldHists, 0/*50*//*(float)numericUpDown1.Value*/, isGray);
  614. //计算对比度
  615. label6_Text = (256.0 / (startIndex.Y - startIndex.X)).ToString("f2");
  616. //计算亮度
  617. label5_Text = ((0 - startIndex.X - startIndex.Y) / 510.0).ToString("f2");
  618. }
  619. return scrollMethod(src, label5_Text, label6_Text, gamma45 ? "0.45" : "1.00", isGray, oldHists);
  620. ////updateHistogramRect(true);
  621. //return null;
  622. }
  623. /// <summary>
  624. /// 伽马0.45
  625. /// </summary>
  626. public static Mat Gamma45ButtonMethod(Mat src)
  627. {
  628. Mat[] mats = Cv2.Split(src);//一张图片,将panda拆分成3个图片装进mat
  629. bool isGray = true;
  630. /// <summary>
  631. /// 一个矩阵数组,用来接收直方图,记得全部初始化
  632. /// </summary>
  633. Mat[] oldHists = new Mat[] { new Mat(), new Mat(), new Mat() };
  634. Mat[] mats0 = new Mat[] { mats[0] };//panda的第一个通道,也就是B
  635. Mat[] mats1 = new Mat[] { mats[1] };//panda的第二个通道,也就是G
  636. Mat[] mats2 = new Mat[] { mats[2] };//panda的第三个通道,也就是R
  637. int[] channels0 = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置一个就行
  638. int[] channels1 = new int[] { 0 };
  639. int[] channels2 = new int[] { 0 };
  640. int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子
  641. Rangef[] range = new Rangef[1];//一个通道,范围
  642. range[0] = new Rangef(0.0F, 256.0F);
  643. Mat mask = new Mat();//不做掩码
  644. Cv2.CalcHist(mats0, channels0, mask, oldHists[0], 1, histsize, range);//对被拆分的图片单独进行计算
  645. Cv2.CalcHist(mats1, channels1, mask, oldHists[1], 1, histsize, range);//对被拆分的图片单独进行计算
  646. Cv2.CalcHist(mats2, channels2, mask, oldHists[2], 1, histsize, range);//对被拆分的图片单独进行计算
  647. for (int h = 0; h < oldHists[0].Rows; h++)
  648. {
  649. for (int j = oldHists.Length - 1; j >= 1; j--)
  650. {
  651. if (oldHists[j].At<float>(h) != oldHists[0].At<float>(h))
  652. {
  653. isGray = false;
  654. break;
  655. }
  656. }
  657. if (!isGray)
  658. break;
  659. }
  660. //500 为千分比输入值,需要确认
  661. OpenCvSharp.Point startIndex = getStartIndex(src, oldHists, 0/*(float)numericUpDown1.Value*/, isGray);
  662. //计算对比度
  663. string label6_Text = "1.00";// (256.0 / (startIndex.Y - startIndex.X)).ToString("f2");
  664. int trackBar2_Value = Math.Min(999/*trackBar2.Maximum*/, (int)(double.Parse(label6_Text) * 100));
  665. //计算亮度
  666. string label5_Text = "-0.50";// ((0 - startIndex.X - startIndex.Y) / 510.0).ToString("f2");
  667. int trackBar1_Value = (int)(double.Parse(label5_Text) * 100);
  668. return scrollMethod(src, label5_Text, label6_Text, "0.45", isGray, oldHists);
  669. }
  670. /// <summary>
  671. /// 最大最小
  672. /// </summary>
  673. public static Mat MaxMinButtonMethod(Mat src)
  674. {
  675. Mat[] mats = Cv2.Split(src);//一张图片,将panda拆分成3个图片装进mat
  676. bool isGray = true;
  677. /// <summary>
  678. /// 一个矩阵数组,用来接收直方图,记得全部初始化
  679. /// </summary>
  680. Mat[] oldHists = new Mat[] { new Mat(), new Mat(), new Mat() };
  681. Mat[] mats0 = new Mat[] { mats[0] };//panda的第一个通道,也就是B
  682. Mat[] mats1 = new Mat[] { mats[1] };//panda的第二个通道,也就是G
  683. Mat[] mats2 = new Mat[] { mats[2] };//panda的第三个通道,也就是R
  684. int[] channels0 = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置一个就行
  685. int[] channels1 = new int[] { 0 };
  686. int[] channels2 = new int[] { 0 };
  687. int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子
  688. Rangef[] range = new Rangef[1];//一个通道,范围
  689. range[0] = new Rangef(0.0F, 256.0F);
  690. Mat mask = new Mat();//不做掩码
  691. Cv2.CalcHist(mats0, channels0, mask, oldHists[0], 1, histsize, range);//对被拆分的图片单独进行计算
  692. Cv2.CalcHist(mats1, channels1, mask, oldHists[1], 1, histsize, range);//对被拆分的图片单独进行计算
  693. Cv2.CalcHist(mats2, channels2, mask, oldHists[2], 1, histsize, range);//对被拆分的图片单独进行计算
  694. for (int h = 0; h < oldHists[0].Rows; h++)
  695. {
  696. for (int j = oldHists.Length - 1; j >= 1; j--)
  697. {
  698. if (oldHists[j].At<float>(h) != oldHists[0].At<float>(h))
  699. {
  700. isGray = false;
  701. break;
  702. }
  703. }
  704. if (!isGray)
  705. break;
  706. }
  707. //500 为千分比输入值,需要确认
  708. OpenCvSharp.Point startIndex = getStartIndex(src, oldHists, 0/*(float)numericUpDown1.Value*/, isGray);
  709. //计算对比度
  710. string label6_Text = (256.0 / (startIndex.Y - startIndex.X)).ToString("f2");
  711. int trackBar2_Value = Math.Min(999/*trackBar2.Maximum*/, (int)(double.Parse(label6_Text) * 100));
  712. //计算亮度
  713. string label5_Text = ((0 - startIndex.X - startIndex.Y) / 510.0).ToString("f2");
  714. int trackBar1_Value = (int)(double.Parse(label5_Text) * 100);
  715. return scrollMethod(src, label5_Text, label6_Text, "1.00"/*"0.45"*/, isGray, oldHists);
  716. }
  717. /// <summary>
  718. /// 最佳
  719. /// </summary>
  720. public static Mat BestButtonMethod(Mat src)
  721. {
  722. Mat[] mats = Cv2.Split(src);//一张图片,将panda拆分成3个图片装进mat
  723. bool isGray = true;
  724. /// <summary>
  725. /// 一个矩阵数组,用来接收直方图,记得全部初始化
  726. /// </summary>
  727. Mat[] oldHists = new Mat[] { new Mat(), new Mat(), new Mat() };
  728. Mat[] mats0 = new Mat[] { mats[0] };//panda的第一个通道,也就是B
  729. Mat[] mats1 = new Mat[] { mats[1] };//panda的第二个通道,也就是G
  730. Mat[] mats2 = new Mat[] { mats[2] };//panda的第三个通道,也就是R
  731. int[] channels0 = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置一个就行
  732. int[] channels1 = new int[] { 0 };
  733. int[] channels2 = new int[] { 0 };
  734. int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子
  735. Rangef[] range = new Rangef[1];//一个通道,范围
  736. range[0] = new Rangef(0.0F, 256.0F);
  737. Mat mask = new Mat();//不做掩码
  738. Cv2.CalcHist(mats0, channels0, mask, oldHists[0], 1, histsize, range);//对被拆分的图片单独进行计算
  739. Cv2.CalcHist(mats1, channels1, mask, oldHists[1], 1, histsize, range);//对被拆分的图片单独进行计算
  740. Cv2.CalcHist(mats2, channels2, mask, oldHists[2], 1, histsize, range);//对被拆分的图片单独进行计算
  741. for (int h = 0; h < oldHists[0].Rows; h++)
  742. {
  743. for (int j = oldHists.Length - 1; j >= 1; j--)
  744. {
  745. if (oldHists[j].At<float>(h) != oldHists[0].At<float>(h))
  746. {
  747. isGray = false;
  748. break;
  749. }
  750. }
  751. if (!isGray)
  752. break;
  753. }
  754. //500 为千分比输入值,需要确认
  755. OpenCvSharp.Point startIndex = getStartIndex(src, oldHists, 100/*50*//*(float)numericUpDown1.Value*/, isGray);
  756. //计算对比度
  757. string label6_Text = (256.0 / (startIndex.Y - startIndex.X)).ToString("f2");
  758. int trackBar2_Value = Math.Min(999/*trackBar2.Maximum*/, (int)(double.Parse(label6_Text) * 100));
  759. //计算亮度
  760. string label5_Text = ((0 - startIndex.X - startIndex.Y) / 510.0).ToString("f2");
  761. int trackBar1_Value = (int)(double.Parse(label5_Text) * 100);
  762. return scrollMethod(src, label5_Text, label6_Text, "1.00"/*"0.45"*/, isGray, oldHists);
  763. ////updateHistogramRect(true);
  764. //return null;
  765. }
  766. /// <summary>
  767. /// 根据亮度、对比度、gamma对图片进行处理
  768. /// </summary>
  769. private static Mat scrollMethod(Mat src, string label5_Text, string label6_Text, string label7_Text, bool isGray, Mat[] oldHists)
  770. {
  771. Mat[] mats = Cv2.Split(src);//一张图片,将panda拆分成3个图片装进mat
  772. //根据亮度和对比度计算左右阈值
  773. int grayMin = (int)(0 - (256.0 / (double.Parse(label6_Text) == 0 ? 0.01 : double.Parse(label6_Text)) + double.Parse(label5_Text) * 510.0) / 2.0);
  774. int grayMax = (int)((256.0 / (double.Parse(label6_Text) == 0 ? 0.01 : double.Parse(label6_Text)) - double.Parse(label5_Text) * 510.0) / 2.0);
  775. if (grayMin >= grayMax)
  776. {
  777. return src;
  778. }
  779. Mat dst = new Mat();
  780. //如果是灰度化图片,则只需计算一个通道。对灰度值进行映射,BGR根据左右阈值做缩放操作
  781. if (isGray)
  782. {
  783. Cv2.Min(mats[0], new Mat(mats[0].Rows, mats[0].Cols, MatType.CV_8UC1, new Scalar(grayMax)), dst);
  784. Cv2.Max(dst, new Mat(mats[0].Rows, mats[0].Cols, MatType.CV_8UC1, new Scalar(grayMin)), dst);
  785. Cv2.Normalize(dst, dst, 0, 255, NormTypes.MinMax);
  786. }
  787. else
  788. {
  789. for (int j = 0; j < oldHists.Length; j++)
  790. {
  791. Cv2.Min(mats[j], new Mat(mats[j].Rows, mats[j].Cols, MatType.CV_8UC1, new Scalar(grayMax)), mats[j]);
  792. Cv2.Max(mats[j], new Mat(mats[j].Rows, mats[j].Cols, MatType.CV_8UC1, new Scalar(grayMin)), mats[j]);
  793. Cv2.Normalize(mats[j], mats[j], 0, 255, NormTypes.MinMax);
  794. }
  795. Cv2.Merge(mats, dst);
  796. }
  797. //灰度归一化
  798. dst.ConvertTo(dst, MatType.CV_64F, 1.0 / 255, 0);
  799. //gamma运算,gamma值根据AxioVision对比 取最小值0.01进行计算
  800. Cv2.Pow(dst, Math.Max(0.01, double.Parse(label7_Text)), dst);
  801. dst.ConvertTo(dst, MatType.CV_8U, 255, 0);
  802. return dst;
  803. //Document document = Document.FromImage(OpenCvSharp.Extensions.BitmapConverter.ToBitmap(dst));
  804. //this.AppWorkspace.ActiveDocumentWorkspace.Document = document;
  805. //this.AppWorkspace.ActiveDocumentWorkspace.Refresh();
  806. }
  807. /// <summary>
  808. /// 通过颜色通道去除像素点的千分比计算有效阈值
  809. /// </summary>
  810. /// <param name="hists"></param>
  811. /// <param name="percentValue"></param>
  812. /// <returns></returns>
  813. private static OpenCvSharp.Point getStartIndex(Mat mat, Mat[] hists, float percentValue, bool isGray)
  814. {
  815. //灰度化图片取第一通道
  816. Mat histGray = hists[0];
  817. //彩色图片取灰度化后的通道
  818. if (!isGray)
  819. {
  820. OpenCvSharp.Point startIndex = new OpenCvSharp.Point(0, histGray.Rows);
  821. //计算三次
  822. OpenCvSharp.Point startIndex0 = getStartRange(mat, hists[0], percentValue);
  823. OpenCvSharp.Point startIndex1 = getStartRange(mat, hists[1], percentValue);
  824. OpenCvSharp.Point startIndex2 = getStartRange(mat, hists[2], percentValue);
  825. startIndex.X = Math.Min(startIndex0.X, Math.Min(startIndex1.X, startIndex2.X));
  826. startIndex.Y = Math.Max(startIndex0.Y, Math.Max(startIndex1.Y, startIndex2.Y));
  827. startIndex.Y = Math.Min(255 - 1, startIndex.Y);
  828. startIndex.X = Math.Max(startIndex.X, 1);
  829. startIndex.Y = Math.Max(startIndex.X + 1, startIndex.Y);
  830. return startIndex;
  831. }
  832. return getStartRange(mat, histGray, percentValue);
  833. }
  834. private static OpenCvSharp.Point getStartRange(Mat mat, Mat histGray, float percentValue)
  835. {
  836. //if (this.AppWorkspace.ActiveDocumentWorkspace == null)
  837. //{
  838. // return new OpenCvSharp.Point(1, 254); ;
  839. //}
  840. //计算灰度分布密度
  841. float totalPoints = mat.Cols * mat.Rows;
  842. OpenCvSharp.Point startIndex = new OpenCvSharp.Point(0, histGray.Rows);
  843. bool foundStartTag = false;
  844. bool foundEndTag = false;
  845. //根据累计直方图分布计算左右阈值
  846. float equalizeHists = 0;
  847. for (int i = 0; i < histGray.Rows; ++i)
  848. {
  849. equalizeHists += ((float)(histGray.At<float>(i) / (totalPoints * 1.0))) * 1000;
  850. if (!foundStartTag && equalizeHists > percentValue)
  851. {
  852. foundStartTag = true;
  853. startIndex.X = i;
  854. }
  855. else if (equalizeHists >= 1000 - percentValue)
  856. {
  857. foundEndTag = true;
  858. startIndex.Y = i;
  859. }
  860. if (foundStartTag && foundEndTag)
  861. break;
  862. }
  863. startIndex.Y = Math.Min(255 - 1, startIndex.Y);
  864. startIndex.X = Math.Max(startIndex.X, 1);
  865. startIndex.Y = Math.Max(startIndex.X + 1, startIndex.Y);
  866. return startIndex;
  867. }
  868. #endregion
  869. /// <summary>
  870. /// 灰度化
  871. /// </summary>
  872. /// <param name="src"></param>
  873. /// <returns></returns>
  874. public static Mat Bgr2GrayFunction(Mat src)
  875. {
  876. return src.CvtColor(ColorConversionCodes.BGR2GRAY);
  877. }
  878. /// <summary>
  879. /// 白平衡C-限制最大最小值
  880. /// </summary>
  881. /// <param name="temp"></param>
  882. /// <param name="green"></param>
  883. /// <param name="equal"></param>
  884. public static void clip(double temp1, double green1, double equal1, out double temp, out double green, out double equal)
  885. {
  886. temp = Math.Max(1500.0/*min*/, Math.Min(temp1, 60000.0/*max*/));
  887. green = Math.Max(0.02, Math.Min(green1, 10.0));
  888. equal = Math.Max(0.8, Math.Min(equal1, 1.5));
  889. }
  890. /// <summary>
  891. /// calculate XYZ from spectrum data (color) and illuminant : J.Desmis December 2011
  892. /// </summary>
  893. /// <param name="spec_color"></param>
  894. /// <param name="spec_intens"></param>
  895. /// <param name="xx"></param>
  896. /// <param name="yy"></param>
  897. /// <param name="zz"></param>
  898. public static void spectrum_to_color_xyz_preset(double[] spec_color, double[] spec_intens, out double xx, out double yy, out double zz)
  899. {
  900. int i;
  901. double lambda, X = 0, Y = 0, Z = 0, Yo = 0;
  902. for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5)
  903. {
  904. double Me;
  905. double Mc;
  906. Me = get_spectral_color(lambda, spec_color);
  907. Mc = get_spectral_color(lambda, spec_intens);
  908. X += Mc * cie_colour_match_jd[i][0] * Me;
  909. Y += Mc * cie_colour_match_jd[i][1] * Me;
  910. Z += Mc * cie_colour_match_jd[i][2] * Me;
  911. }
  912. for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5)
  913. {
  914. double Ms;
  915. Ms = get_spectral_color(lambda, spec_intens);
  916. Yo += cie_colour_match_jd[i][1] * Ms;
  917. }
  918. xx = X / Yo;
  919. yy = Y / Yo;
  920. zz = Z / Yo;
  921. }
  922. /*
  923. Calculate Planck's radiation
  924. */
  925. //calculate spectral data for blackbody at temp!
  926. public static double blackbody_spect(double wavelength, double temperature)
  927. {
  928. double wlm = wavelength * 1e-9; /* Wavelength in meters */
  929. return (3.7417715247e-16 / Math.Pow(wlm, 5)) / //3.7417..= c1 = 2*Pi*h*c2 where h=Planck constant, c=velocity of light
  930. (Math.Exp(1.438786e-2 / (wlm * temperature)) - 1.0); //1.4387..= c2 = h*c/k where k=Boltzmann constant
  931. }
  932. /// <summary>
  933. /// calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011
  934. /// </summary>
  935. /// <param name="spec_color"></param>
  936. /// <param name="_temp"></param>
  937. /// <param name="xx"></param>
  938. /// <param name="yy"></param>
  939. /// <param name="zz"></param>
  940. public static void spectrum_to_color_xyz_blackbody(double[] spec_color, double _temp, out double xx, out double yy, out double zz)
  941. {
  942. int i;
  943. double lambda, X = 0, Y = 0, Z = 0;
  944. for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5)
  945. {
  946. double Me = spec_color[i];
  947. double Mc = blackbody_spect(lambda, _temp);
  948. X += Mc * cie_colour_match_jd[i][0] * Me;
  949. Y += Mc * cie_colour_match_jd[i][1] * Me;
  950. Z += Mc * cie_colour_match_jd[i][2] * Me;
  951. }
  952. xx = X / Y;
  953. yy = 1.0;
  954. zz = Z / Y;
  955. }
  956. /// <summary>
  957. /// spectrum_to_xyz_blackbody
  958. /// </summary>
  959. /// <param name="_temp"></param>
  960. /// <param name="x"></param>
  961. /// <param name="y"></param>
  962. /// <param name="z"></param>
  963. public static void spectrum_to_xyz_blackbody(double _temp, out double x, out double y, out double z)
  964. {
  965. int i;
  966. double lambda, X = 0, Y = 0, Z = 0, XYZ;
  967. for (i = 0, lambda = 350.0; lambda < 830.1; i++, lambda += 5.0)
  968. {
  969. double Me = blackbody_spect(lambda, _temp);
  970. X += Me * cie_colour_match_jd[i][0];
  971. Y += Me * cie_colour_match_jd[i][1];
  972. Z += Me * cie_colour_match_jd[i][2];
  973. }
  974. XYZ = (X + Y + Z);
  975. x = X / XYZ;
  976. y = Y / XYZ;
  977. z = Z / XYZ;
  978. }
  979. /// <summary>
  980. /// calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011
  981. /// </summary>
  982. /// <param name="spec_color"></param>
  983. /// <param name="_m1"></param>
  984. /// <param name="_m2"></param>
  985. /// <param name="xx"></param>
  986. /// <param name="yy"></param>
  987. /// <param name="zz"></param>
  988. public static void spectrum_to_color_xyz_daylight(double[] spec_color, double _m1, double _m2, out double xx, out double yy, out double zz)
  989. {
  990. int i;
  991. double lambda, X = 0, Y = 0, Z = 0;
  992. for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5)
  993. {
  994. double Me = spec_color[i];
  995. double Mc = daylight_spect(lambda, _m1, _m2);
  996. X += Mc * cie_colour_match_jd[i][0] * Me;
  997. Y += Mc * cie_colour_match_jd[i][1] * Me;
  998. Z += Mc * cie_colour_match_jd[i][2] * Me;
  999. }
  1000. xx = X / Y;
  1001. yy = 1.0;
  1002. zz = Z / Y;
  1003. }
  1004. /// <summary>
  1005. /// 白平衡C-翻译-色度toRGB
  1006. /// </summary>
  1007. /// <param name="wavelength"></param>
  1008. /// <param name="array"></param>
  1009. /// <returns></returns>
  1010. public static double get_spectral_color(double wavelength, double[] array)
  1011. {
  1012. int wlm = (int)((wavelength - 350.0) / 5.0);
  1013. return array[wlm];
  1014. }
  1015. /// <summary>
  1016. /// 白平衡C-翻译-色度toRGB
  1017. /// </summary>
  1018. /// <param name="spec_intens"></param>
  1019. /// <param name="x"></param>
  1020. /// <param name="y"></param>
  1021. /// <param name="z"></param>
  1022. public static void spectrum_to_xyz_preset(double[] spec_intens, out double x, out double y, out double z)
  1023. {
  1024. int i = 0;
  1025. double lambda = 350.0, X = 0, Y = 0, Z = 0, XYZ;
  1026. for (; lambda < 830.1; i++, lambda += 5.0)
  1027. {
  1028. double Me = get_spectral_color(lambda, spec_intens);
  1029. X += Me * cie_colour_match_jd[i][0];
  1030. Y += Me * cie_colour_match_jd[i][1];
  1031. Z += Me * cie_colour_match_jd[i][2];
  1032. }
  1033. XYZ = (X + Y + Z);
  1034. x = X / XYZ;
  1035. y = Y / XYZ;
  1036. z = Z / XYZ;
  1037. }
  1038. /// <summary>
  1039. /// 白平衡C-翻译-色度toRGB
  1040. /// </summary>
  1041. /// <param name="wavelength"></param>
  1042. /// <param name="m1"></param>
  1043. /// <param name="m2"></param>
  1044. /// <returns></returns>
  1045. public static double daylight_spect(double wavelength, double m1, double m2)
  1046. {
  1047. //Values for Daylight illuminant: s0 s1 s2
  1048. //s0
  1049. double[] s0 = {61.80, 61.65, 61.50, 65.15, 68.80, 66.10, 63.40, 64.60, 65.80, 80.30, 94.80, 99.80, 104.80, 105.35, 105.90, 101.35, 96.80, 105.35, 113.90, 119.75, 125.60, 125.55, 125.50, 123.40, 121.30, 121.30, 121.30, 117.40, 113.50, 113.30,
  1050. 113.10, 111.95, 110.80, 108.65, 106.50, 107.65, 108.80, 107.05, 105.30, 104.85, 104.40, 102.20, 100.00, 98.00, 96.00, 95.55, 95.10, 92.10, 89.10, 89.80, 90.50, 90.40, 90.30, 89.35, 88.40, 86.20, 84.00, 84.55, 85.10,
  1051. 83.50, 81.90, 82.25, 82.60, 83.75, 84.90, 83.10, 81.30, 76.60, 71.90, 73.10, 74.30, 75.35, 76.40, 69.85, 63.30, 67.50, 71.70, 74.35, 77.00, 71.10, 65.20, 56.45, 47.70, 58.15, 68.60, 66.80, 65.00, 65.50, 66.00, 63.50, 61.00, 57.15,
  1052. 53.30, 56.10, 58.90, 60.40, 61.90
  1053. };
  1054. //s1
  1055. double[] s1 = {41.60, 39.80, 38.00, 40.70, 43.40, 40.95, 38.50, 36.75, 35.00, 39.20, 43.40, 44.85, 46.30, 45.10, 43.90, 40.50, 37.10, 36.90, 36.70, 36.30, 35.90, 34.25, 32.60, 30.25, 27.90, 26.10, 24.30, 22.20, 20.10, 18.15, 16.20, 14.70,
  1056. 13.20, 10.90, 8.60, 7.35, 6.10, 5.15, 4.20, 3.05, 1.90, 0.95, 0.00, -0.80, -1.60, -2.55, -3.50, -3.50, -3.50, -4.65, -5.80, -6.50, -7.20, -7.90, -8.60, -9.05, -9.50, -10.20, -10.90, -10.80, -10.70, -11.35, -12.00, -13.00, -14.00,
  1057. -13.80, -13.60, -12.80, -12.00, -12.65, -13.30, -13.10, -12.90, -11.75, -10.60, -11.10, -11.60, -11.90, -12.20, -11.20, -10.20, -9.00, -7.80, -9.50, -11.20, -10.80, -10.50, -10.60, -10.15, -9.70, -9.00, -8.30,
  1058. -8.80, -9.30, -9.55, -9.80, 0.0
  1059. };//手动加0
  1060. //s2
  1061. double[] s2 = {6.70, 6.00, 5.30, 5.70, 6.10, 4.55, 3.00, 2.10, 1.20, 0.05, -1.10, -0.80, -0.50, -0.60, -0.70, -0.95, -1.20, -1.90, -2.60, -2.75, -2.90, -2.85, -2.80, -2.70, -2.60, -2.60, -2.60, -2.20, -1.80, -1.65, -1.50, -1.40, -1.30,
  1062. -1.25, -1.20, -1.10, -1.00, -0.75, -0.50, -0.40, -0.30, -0.15, 0.00, 0.10, 0.20, 0.35, 0.50, 1.30, 2.10, 2.65, 3.65, 4.10, 4.40, 4.70, 4.90, 5.10, 5.90, 6.70, 7.00, 7.30, 7.95, 8.60, 9.20, 9.80, 10.00, 10.20, 9.25, 8.30, 8.95,
  1063. 9.60, 9.05, 8.50, 7.75, 7.00, 7.30, 7.60, 7.80, 8.00, 7.35, 6.70, 5.95, 5.20, 6.30, 7.40, 7.10, 6.80, 6.90, 7.00, 6.70, 6.40, 5.95, 5.50, 5.80, 6.10, 6.30, 6.50, 0.0
  1064. };//手动加0
  1065. int wlm = (int)((wavelength - 350.0) / 5.0);
  1066. return (s0[wlm] + m1 * s1[wlm] + m2 * s2[wlm]);
  1067. }
  1068. /// <summary>
  1069. /// 白平衡C-翻译-色度toRGB
  1070. /// </summary>
  1071. /// <param name="_m1"></param>
  1072. /// <param name="_m2"></param>
  1073. /// <param name="x"></param>
  1074. /// <param name="y"></param>
  1075. /// <param name="z"></param>
  1076. public static void spectrum_to_xyz_daylight(double _m1, double _m2, out double x, out double y, out double z)
  1077. {
  1078. int i = 0;
  1079. double lambda = 350.0, X = 0, Y = 0, Z = 0, XYZ;
  1080. for (; lambda < 830.1; i++, lambda += 5.0)
  1081. {
  1082. double Me = daylight_spect(lambda, _m1, _m2);
  1083. X += Me * cie_colour_match_jd[i][0];
  1084. Y += Me * cie_colour_match_jd[i][1];
  1085. Z += Me * cie_colour_match_jd[i][2];
  1086. }
  1087. XYZ = (X + Y + Z);
  1088. x = X / XYZ;
  1089. y = Y / XYZ;
  1090. z = Z / XYZ;
  1091. }
  1092. /*
  1093. * Name: XYZtoCorColorTemp.c
  1094. *
  1095. * Author: Bruce Justin Lindbloom
  1096. *
  1097. * Copyright (c) 2003 Bruce Justin Lindbloom. All rights reserved.
  1098. *
  1099. *
  1100. * Description:
  1101. * This is an implementation of Robertson's method of computing the correlated color
  1102. * temperature of an XYZ color. It can compute correlated color temperatures in the
  1103. * range [1666.7K, infinity].
  1104. *
  1105. * Reference:
  1106. * "Color Science: Concepts and Methods, Quantitative Data and Formulae", Second Edition,
  1107. * Gunter Wyszecki and W. S. Stiles, John Wiley & Sons, 1982, pp. 227, 228.
  1108. */
  1109. public static UVT CreateUVT(double u, double v, double t)
  1110. {
  1111. UVT uVT = new UVT();
  1112. uVT.u = u;
  1113. uVT.v = v;
  1114. uVT.t = t;
  1115. return uVT;
  1116. }
  1117. /// <summary>
  1118. /// adaptation to RT by J.Desmis
  1119. /// </summary>
  1120. /// <param name="x0"></param>
  1121. /// <param name="y0"></param>
  1122. /// <param name="z0"></param>
  1123. /// <param name="temp"></param>
  1124. /// <returns></returns>
  1125. public static int XYZtoCorColorTemp(double x0, double y0, double z0, out double temp)
  1126. {
  1127. //// typedef enum information id
  1128. //public enum TUCAM_IDINFO
  1129. //{
  1130. // TUIDI_BUS = 0x01, // the bus type USB2.0/USB3.0
  1131. // TUIDI_VENDOR = 0x02, // the vendor id
  1132. // TUIDI_PRODUCT = 0x03, // the product id
  1133. // TUIDI_VERSION_API = 0x04, // the API version
  1134. // TUIDI_VERSION_FRMW = 0x05, // the firmware version
  1135. // TUIDI_VERSION_FPGA = 0x06, // the FPGA version
  1136. // TUIDI_VERSION_DRIVER = 0x07, // the driver version
  1137. // TUIDI_TRANSFER_RATE = 0x08, // the transfer rate
  1138. // TUIDI_CAMERA_MODEL = 0x09, // the camera model (string)
  1139. // TUIDI_CURRENT_WIDTH = 0x0A, // the camera image data current width(must use TUCAM_Dev_GetInfoEx and after calling TUCAM_Buf_Alloc)
  1140. // TUIDI_CURRENT_HEIGHT = 0x0B, // the camera image data current height(must use TUCAM_Dev_GetInfoEx and after calling TUCAM_Buf_Alloc)
  1141. // TUIDI_CAMERA_CHANNELS = 0x0C, // the camera image data channels
  1142. // TUIDI_BCDDEVICE = 0x0D, // the USB bcdDevice
  1143. // TUIDI_ENDINFO = 0x0E, // the string id end
  1144. //};
  1145. //public struct UVT
  1146. //{
  1147. // //[FieldOffset(0)]
  1148. // public double u;
  1149. // //[FieldOffset(1)]
  1150. // public double v;
  1151. // //[FieldOffset(2)]
  1152. // public double t;
  1153. //}
  1154. double[] rt = new double[31]{ /* reciprocal temperature (K) */
  1155. double.MinValue, 10.0e-6, 20.0e-6, 30.0e-6, 40.0e-6, 50.0e-6,
  1156. 60.0e-6, 70.0e-6, 80.0e-6, 90.0e-6, 100.0e-6, 125.0e-6,
  1157. 150.0e-6, 175.0e-6, 200.0e-6, 225.0e-6, 250.0e-6, 275.0e-6,
  1158. 300.0e-6, 325.0e-6, 350.0e-6, 375.0e-6, 400.0e-6, 425.0e-6,
  1159. 450.0e-6, 475.0e-6, 500.0e-6, 525.0e-6, 550.0e-6, 575.0e-6,
  1160. 600.0e-6
  1161. };
  1162. UVT[] uvt = new UVT[31]{
  1163. CreateUVT(0.18006, 0.26352, -0.24341),
  1164. CreateUVT(0.18066, 0.26589, -0.25479),
  1165. CreateUVT(0.18133, 0.26846, -0.26876),
  1166. CreateUVT(0.18208, 0.27119, -0.28539),
  1167. CreateUVT(0.18293, 0.27407, -0.30470),
  1168. CreateUVT(0.18388, 0.27709, -0.32675),
  1169. CreateUVT(0.18494, 0.28021, -0.35156),
  1170. CreateUVT(0.18611, 0.28342, -0.37915),
  1171. CreateUVT(0.18740, 0.28668, -0.40955),
  1172. CreateUVT(0.18880, 0.28997, -0.44278),
  1173. CreateUVT(0.19032, 0.29326, -0.47888),
  1174. CreateUVT(0.19462, 0.30141, -0.58204),
  1175. CreateUVT(0.19962, 0.30921, -0.70471),
  1176. CreateUVT(0.20525, 0.31647, -0.84901),
  1177. CreateUVT(0.21142, 0.32312, -1.0182),
  1178. CreateUVT(0.21807, 0.32909, -1.2168),
  1179. CreateUVT(0.22511, 0.33439, -1.4512),
  1180. CreateUVT(0.23247, 0.33904, -1.7298),
  1181. CreateUVT(0.24010, 0.34308, -2.0637),
  1182. CreateUVT(0.24792, 0.34655, -2.4681),
  1183. CreateUVT(0.25591, 0.34951, -2.9641),
  1184. CreateUVT(0.26400, 0.35200, -3.5814),
  1185. CreateUVT(0.27218, 0.35407, -4.3633),
  1186. CreateUVT(0.28039, 0.35577, -5.3762),
  1187. CreateUVT(0.28863, 0.35714, -6.7262),
  1188. CreateUVT(0.29685, 0.35823, -8.5955),
  1189. CreateUVT(0.30505, 0.35907, -11.324),
  1190. CreateUVT(0.31320, 0.35968, -15.628),
  1191. CreateUVT(0.32129, 0.36011, -23.325),
  1192. CreateUVT(0.32931, 0.36038, -40.770),
  1193. CreateUVT(0.33724, 0.36051, -116.45)
  1194. };
  1195. double us, vs, p, di = 0.0, dm;
  1196. int i;
  1197. if ((x0 < 1.0e-20) && (y0 < 1.0e-20) && (z0 < 1.0e-20))
  1198. {
  1199. temp = 0.0;
  1200. return -1; /* protect against possible divide-by-zero failure */
  1201. }
  1202. us = (4.0 * x0) / (x0 + 15.0 * y0 + 3.0 * z0);
  1203. vs = (6.0 * y0) / (x0 + 15.0 * y0 + 3.0 * z0);
  1204. dm = 0.0;
  1205. for (i = 0; i < 31; i++)
  1206. {
  1207. di = (vs - uvt[i].v) - uvt[i].t * (us - uvt[i].u);
  1208. if ((i > 0) && (((di < 0.0) && (dm >= 0.0)) || ((di >= 0.0) && (dm < 0.0))))
  1209. {
  1210. break; /* found lines bounding (us, vs) : i-1 and i */
  1211. }
  1212. dm = di;
  1213. }
  1214. if (i == 31)
  1215. {
  1216. temp = 0.0;
  1217. return -1; /* bad XYZ input, color temp would be less than minimum of 1666.7 degrees, or too far towards blue */
  1218. }
  1219. di = di / Math.Sqrt(1.0 + uvt[i].t * uvt[i].t);
  1220. dm = dm / Math.Sqrt(1.0 + uvt[i - 1].t * uvt[i - 1].t);
  1221. p = dm / (dm - di); /* p = interpolation parameter, 0.0 : i-1, 1.0 : i */
  1222. p = 1.0 / intp(p, rt[i], rt[i - 1]);
  1223. temp = p;
  1224. return 0; /* success */
  1225. }
  1226. /// <summary>
  1227. /// 白平衡C-翻译-色度toRGB
  1228. /// </summary>
  1229. /// <param name="temp"></param>
  1230. /// <param name="method"></param>
  1231. /// <param name="Xxyz"></param>
  1232. /// <param name="Zxyz"></param>
  1233. public static void temp2mulxyz(double temp, string method1/*, out string method*/, out double Xxyz, out double Zxyz)
  1234. {
  1235. double x, y, z;
  1236. if (spectMap.ContainsKey(method1))
  1237. {
  1238. spectrum_to_xyz_preset(spectMap[method1], out x, out y, out z);
  1239. }
  1240. else
  1241. {
  1242. // from 4000K up to 25000K: using the D illuminant (daylight) which is standard
  1243. double x_D, y_D;
  1244. if (temp <= 7000)
  1245. {
  1246. x_D = -4.6070e9 / (temp * temp * temp) + 2.9678e6 / (temp * temp) + 0.09911e3 / temp + 0.244063;
  1247. }
  1248. else if (temp <= 25000)
  1249. {
  1250. x_D = -2.0064e9 / (temp * temp * temp) + 1.9018e6 / (temp * temp) + 0.24748e3 / temp + 0.237040;
  1251. }
  1252. else /*if (temp > 25000)*/
  1253. {
  1254. x_D = -2.0064e9 / (temp * temp * temp) + 1.9018e6 / (temp * temp) + 0.24748e3 / temp + 0.237040 - ((temp - 25000) / 25000) * 0.025; //Jacques empirical adjustment for very high temp (underwater !)
  1255. }
  1256. y_D = -3.0 * x_D * x_D + 2.87 * x_D - 0.275; //modify blue / red action
  1257. //calculate D -daylight in function of s0, s1, s2 and temp ==> x_D y_D
  1258. //S(lamda)=So(lambda)+m1*s1(lambda)+m2*s2(lambda)
  1259. double interm = 0.0241 + 0.2562 * x_D - 0.734 * y_D;
  1260. double m1 = (-1.3515 - 1.7703 * x_D + 5.9114 * y_D) / interm;
  1261. double m2 = (0.03 - 31.4424 * x_D + 30.0717 * y_D) / interm;
  1262. spectrum_to_xyz_daylight(m1, m2, out x, out y, out z);
  1263. }
  1264. Xxyz = x / y;
  1265. Zxyz = (1.0 - x - y) / y;
  1266. }
  1267. public static double intp(double a, double b, double c)
  1268. {
  1269. // calculate a * b + (1 - a) * c
  1270. // following is valid:
  1271. // intp(a, b+x, c+x) = intp(a, b, c) + x
  1272. // intp(a, b*x, c*x) = intp(a, b, c) * x
  1273. return a * (b - c) + c;
  1274. }
  1275. public static void cieCAT02(double Xw, double Yw, double Zw, out double CAM02BB00, out double CAM02BB01, out double CAM02BB02, out double CAM02BB10, out double CAM02BB11, out double CAM02BB12, out double CAM02BB20, out double CAM02BB21, out double CAM02BB22, double adap)
  1276. {
  1277. // CIECAT02 - J.Desmis January 2012 review September 2012
  1278. double[] whiteD50p = new double[3] { 0.9646019585, 1.0, 0.8244507152 }; //calculate with these tool
  1279. double[] cam_dest = new double[3] { 0.0, 0.0, 0.0 };
  1280. double[] cam_orig = new double[3] { 0.0, 0.0, 0.0 };
  1281. double[][] CAT02 = new double[3][]{new double[3]{0.7328, 0.4296, -0.1624},//CAT02 2002
  1282. new double[3]{ -0.7036, 1.6975, 0.0061},
  1283. new double[3]{0.0030, 0.0136, 0.9834}
  1284. };
  1285. double[][] INVCAT02 = new double[3][]{new double[3]{1.09612382083551, -0.278869000218287, 0.182745179382773}, //Inverse CAT02
  1286. new double[3]{0.454369041975359, 0.4735331543070412, 0.0720978037172291},
  1287. new double[3]{ -0.009627608738442936, -0.00569803121611342, 1.01532563995454}
  1288. };
  1289. double[][] inv_white_orig = new double[3][]{new double[3]{0.0, 0.0, 0.0},
  1290. new double[3]{0.0, 0.0, 0.0},
  1291. new double[3]{0.0, 0.0, 0.0}
  1292. };
  1293. double[][] intermed = new double[3][]{new double[3]{0.0, 0.0, 0.0},
  1294. new double[3]{0.0, 0.0, 0.0},
  1295. new double[3]{0.0, 0.0, 0.0}
  1296. };
  1297. double[][] intermed_2 = new double[3][]{new double[3]{0.0, 0.0, 0.0},
  1298. new double[3]{0.0, 0.0, 0.0},
  1299. new double[3]{0.0, 0.0, 0.0}
  1300. };
  1301. double[][] CAM02 = new double[3][]{new double[3]{0.0, 0.0, 0.0},
  1302. new double[3]{0.0, 0.0, 0.0},
  1303. new double[3]{0.0, 0.0, 0.0}
  1304. };
  1305. double D = adap;
  1306. //white destination Wd : RT use always D50
  1307. cam_dest[0] = CAT02[0][0] * whiteD50p[0] + CAT02[0][1] * whiteD50p[1] + CAT02[0][2] * whiteD50p[2]; //Cone response RoD
  1308. cam_dest[1] = CAT02[1][0] * whiteD50p[0] + CAT02[1][1] * whiteD50p[1] + CAT02[1][2] * whiteD50p[2]; //GaD
  1309. cam_dest[2] = CAT02[2][0] * whiteD50p[0] + CAT02[2][1] * whiteD50p[1] + CAT02[2][2] * whiteD50p[2]; //BeD
  1310. //origin white Ws : A, D65, custom, etc.
  1311. cam_orig[0] = CAT02[0][0] * Xw + CAT02[0][1] * Yw + CAT02[0][2] * Zw; //Cone response RoS
  1312. cam_orig[1] = CAT02[1][0] * Xw + CAT02[1][1] * Yw + CAT02[1][2] * Zw;
  1313. cam_orig[2] = CAT02[2][0] * Xw + CAT02[2][1] * Yw + CAT02[2][2] * Zw;
  1314. //inverse white
  1315. inv_white_orig[0][0] = 1.0 / cam_orig[0]; // 1/RoS
  1316. inv_white_orig[1][1] = 1.0 / cam_orig[1]; // 1/GaS
  1317. inv_white_orig[2][2] = 1.0 / cam_orig[2]; // 1/BeS
  1318. //intermediates computation
  1319. for (int i = 0; i < 3; i++)
  1320. for (int j = 0; j < 3; j++)
  1321. {
  1322. intermed[i][j] = inv_white_orig[i][i] * CAT02[i][j];
  1323. }
  1324. for (int i = 0; i < 3; i++)
  1325. for (int j = 0; j < 3; j++)
  1326. {
  1327. intermed_2[i][j] = cam_dest[i] * intermed[i][j];
  1328. }
  1329. //and CAM02
  1330. for (int i = 0; i < 3; i++)
  1331. for (int j = 0; j < 3; j++)
  1332. for (int k = 0; k < 3; k++)
  1333. {
  1334. CAM02[i][j] += INVCAT02[i][k] * intermed_2[k][j];
  1335. }
  1336. //adaptation jdc : slightly different from CIECAM02 : Rc=(Yw(D/Rw)+(1-D))*R , but it's work ! true at 0 and 1
  1337. CAM02[1][1] = (CAM02[1][1] - 1.0) * D + 1.0;
  1338. CAM02[0][0] = (CAM02[0][0] - 1.0) * D + 1.0;
  1339. CAM02[2][2] = (CAM02[2][2] - 1.0) * D + 1.0;
  1340. CAM02[0][1] *= D;
  1341. CAM02[0][2] *= D;
  1342. CAM02[1][0] *= D;
  1343. CAM02[1][2] *= D;
  1344. CAM02[2][0] *= D;
  1345. CAM02[2][1] *= D;
  1346. //CAT02 matrix with D adaptation
  1347. CAM02BB00 = CAM02[0][0];
  1348. CAM02BB01 = CAM02[0][1];
  1349. CAM02BB02 = CAM02[0][2];
  1350. CAM02BB10 = CAM02[1][0];
  1351. CAM02BB11 = CAM02[1][1];
  1352. CAM02BB12 = CAM02[1][2];
  1353. CAM02BB20 = CAM02[2][0];
  1354. CAM02BB21 = CAM02[2][1];
  1355. CAM02BB22 = CAM02[2][2];
  1356. }
  1357. /// <summary>
  1358. /// 白平衡代码调用入口1-RGB转色度的方法
  1359. /// </summary>
  1360. /// <param name="mulr"></param>
  1361. /// <param name="mulg"></param>
  1362. /// <param name="mulb"></param>
  1363. /// <param name="e"></param>
  1364. public static void ColorTemp(double mulr, double mulg, double mulb, double e, out double temp, out double green)
  1365. {
  1366. localEqual = e;
  1367. mul2temp(mulr, mulg, mulb, localEqual, out temp, out green);
  1368. }
  1369. /// <summary>
  1370. /// 白平衡C代码翻译-RGB2色度的方法
  1371. /// </summary>
  1372. /// <param name="rmul"></param>
  1373. /// <param name="gmul"></param>
  1374. /// <param name="bmul"></param>
  1375. /// <param name="equal"></param>
  1376. /// <param name="temp"></param>
  1377. /// <param name="green"></param>
  1378. public static void mul2temp(double rmul, double gmul, double bmul, double equal, out double temp, out double green)
  1379. {
  1380. double maxtemp = 60000.0, mintemp = 1500.0;
  1381. double tmpr = 0.0, tmpg = 0.0, tmpb;
  1382. temp = (maxtemp + mintemp) / 2;
  1383. while (maxtemp - mintemp > 1)
  1384. {
  1385. temp2mul(temp, 1.0, equal, out tmpr, out tmpg, out tmpb);
  1386. if (tmpb / tmpr > bmul / rmul)
  1387. {
  1388. maxtemp = temp;
  1389. }
  1390. else
  1391. {
  1392. mintemp = temp;
  1393. }
  1394. temp = (maxtemp + mintemp) / 2;
  1395. }
  1396. green = (tmpg / tmpr) / (gmul / rmul);
  1397. temp = Math.Max(1500.0/*min*/, Math.Min(temp, 60000.0/*max*/));
  1398. green = Math.Max(0.02, Math.Min(green, 10.0));
  1399. }
  1400. /// <summary>
  1401. /// 白平衡C代码翻译-色度2RGB的方法
  1402. /// </summary>
  1403. /// <param name="temp"></param>
  1404. /// <param name="green"></param>
  1405. /// <param name="equal"></param>
  1406. /// <param name="rmul"></param>
  1407. /// <param name="gmul"></param>
  1408. /// <param name="bmul"></param>
  1409. public static void temp2mul(double temp, double green, double equal, out double rmul, out double gmul, out double bmul)
  1410. {
  1411. clip(temp, green, equal, out temp, out green, out equal);
  1412. double Xwb, Zwb;
  1413. temp2mulxyz(temp, localMethod, out Xwb, out Zwb);
  1414. double adj = 1.0;
  1415. if (equal < 0.9999 || equal > 1.0001)
  1416. {
  1417. adj = (100.0 + (1000.0 - (1000.0 * equal)) / 20.0) / 100.0;
  1418. }
  1419. /*if (isRaw) {
  1420. rmul = sRGB_xyz[0][0]*X + sRGB_xyz[0][1]*Y + sRGB_xyz[0][2]*Z;
  1421. gmul = sRGB_xyz[1][0]*X + sRGB_xyz[1][1]*Y + sRGB_xyz[1][2]*Z;
  1422. bmul = sRGB_xyz[2][0]*X + sRGB_xyz[2][1]*Y + sRGB_xyz[2][2]*Z;
  1423. } else {*/
  1424. //recalculate channels multipliers with new values of XYZ tue to whitebalance
  1425. rmul = sRGBd65_xyz[0][0] * Xwb * adj + sRGBd65_xyz[0][1] + sRGBd65_xyz[0][2] * Zwb / adj; // Jacques' empirical modification 5/2013
  1426. gmul = sRGBd65_xyz[1][0] * Xwb + sRGBd65_xyz[1][1] + sRGBd65_xyz[1][2] * Zwb;
  1427. bmul = sRGBd65_xyz[2][0] * Xwb * adj + sRGBd65_xyz[2][1] + sRGBd65_xyz[2][2] * Zwb / adj;
  1428. //};
  1429. gmul /= green;
  1430. //printf("rmul=%f gmul=%f bmul=%f\n",rmul, gmul, bmul);
  1431. double maxRGB = Math.Max(rmul, Math.Max(gmul, bmul));
  1432. rmul /= maxRGB;
  1433. gmul /= maxRGB;
  1434. bmul /= maxRGB;
  1435. if (settings_CRI_color != 0)
  1436. { //activate if CRi_color !=0
  1437. // begin CRI_RT : color rendering index RT - adaptation of CRI by J.Desmis
  1438. // CRI = 100 for Blackbody and Daylight
  1439. // calculate from spectral data values X, Y, Z , for color of colorchecker24 , SG, DC, JDC_468
  1440. // only for lamp different of tungstene
  1441. // first calcul with illuminant (choice)
  1442. // and calcul with : blackbody at equivalent temp of lamp
  1443. // CRI_color-1 = display Lab values of color CRI_color -1
  1444. double[] whiteD50 = { 0.9646019585, 1.0, 0.8244507152 }; //calculate with this tool : spect 5nm
  1445. double[] Xchk = new double[50], Ychk = new double[50], Zchk = new double[50]; //50 : I think it's a good limit for number of color : for CRI and Palette
  1446. double[] Xcam02 = new double[50], Ycam02 = new double[50], Zcam02 = new double[50];
  1447. double[] XchkLamp = new double[50], YchkLamp = new double[50], ZchkLamp = new double[50];
  1448. double[] Xcam02Lamp = new double[50], Ycam02Lamp = new double[50], Zcam02Lamp = new double[50];
  1449. double epsilon = 0.008856; //Lab
  1450. double[] xr = new double[50], yr = new double[50], zr = new double[50];
  1451. int illum = 0;
  1452. int numero_color = settings_CRI_color - 1;
  1453. //spectral data illuminant (actually 21): only those necessary (lamp, fluorescent, LED) others CRI=100 (not Flash...)
  1454. double[][] spec_color = {
  1455. ColorchechredC3_spect, ColorchechOraA2_spect, ColorchechYelD3_spect, ColorchechGreE2_spect, ColorchechGreB3_spect,
  1456. ColorchechCyaF3_spect, ColorchechPurD2_spect, ColorchechMagE3_spect, ColorchechSkiA138_13_14_spect, ColorchechGraC4_67_spect,
  1457. ColorchechSkiB166_18_18_spect, ColorchechBluC150_m5_m22_spect, ColorchechDCBluN881_m7_m14_spect, ColorchechSGSkiF763_14_26_spect,
  1458. ColorchechSGSkiK285_11_17_spect, ColorchechWhiA496_spect, ColorchechGreD1_spect, ColorchechSGBlaN3_6_spect,
  1459. JDC468_GraK14_44_spect, JDC468_BluH10_spect
  1460. };
  1461. int N_c = spec_color.Length;// sizeof(spec_color) / sizeof(spec_color[0]); //number of color
  1462. bool CRI_type = false;
  1463. double tempw = 0;
  1464. if (localMethod == "Fluo F1")
  1465. {
  1466. CRI_type = true;
  1467. tempw = 6430;
  1468. illum = 1;
  1469. }
  1470. else if (localMethod == "Fluo F2")
  1471. {
  1472. CRI_type = true;
  1473. tempw = 4230;
  1474. illum = 2;
  1475. }
  1476. else if (localMethod == "Fluo F3")
  1477. {
  1478. CRI_type = true;
  1479. tempw = 3450;
  1480. illum = 3;
  1481. }
  1482. else if (localMethod == "Fluo F4")
  1483. {
  1484. CRI_type = true;
  1485. tempw = 2940;
  1486. illum = 4;
  1487. }
  1488. else if (localMethod == "Fluo F5")
  1489. {
  1490. CRI_type = true;
  1491. tempw = 6350;
  1492. illum = 5;
  1493. }
  1494. else if (localMethod == "Fluo F6")
  1495. {
  1496. CRI_type = true;
  1497. tempw = 4150;
  1498. illum = 6;
  1499. }
  1500. else if (localMethod == "Fluo F7")
  1501. {
  1502. CRI_type = true;
  1503. tempw = 6500;
  1504. illum = 7;
  1505. }
  1506. else if (localMethod == "Fluo F8")
  1507. {
  1508. CRI_type = true;
  1509. tempw = 5020;
  1510. illum = 8;
  1511. }
  1512. else if (localMethod == "Fluo F9")
  1513. {
  1514. CRI_type = true;
  1515. tempw = 4330;
  1516. illum = 9;
  1517. }
  1518. else if (localMethod == "Fluo F10")
  1519. {
  1520. CRI_type = true;
  1521. tempw = 5300;
  1522. illum = 10;
  1523. }
  1524. else if (localMethod == "Fluo F11")
  1525. {
  1526. CRI_type = true;
  1527. tempw = 4000;
  1528. illum = 11;
  1529. }
  1530. else if (localMethod == "Fluo F12")
  1531. {
  1532. CRI_type = true;
  1533. tempw = 3000;
  1534. illum = 12;
  1535. }
  1536. else if (localMethod == "HMI Lamp")
  1537. {
  1538. CRI_type = true;
  1539. tempw = 4760;
  1540. illum = 13;
  1541. }
  1542. else if (localMethod == "GTI Lamp")
  1543. {
  1544. CRI_type = true;
  1545. tempw = 5000;
  1546. illum = 14;
  1547. }
  1548. else if (localMethod == "JudgeIII Lamp")
  1549. {
  1550. CRI_type = true;
  1551. tempw = 5100;
  1552. illum = 15;
  1553. }
  1554. else if (localMethod == "Solux Lamp 3500K")
  1555. {
  1556. CRI_type = true;
  1557. tempw = 3480;
  1558. illum = 16;
  1559. }
  1560. else if (localMethod == "Solux Lamp 4100K")
  1561. {
  1562. CRI_type = true;
  1563. tempw = 3930;
  1564. illum = 17;
  1565. }
  1566. else if (localMethod == "Solux Lamp 4700K")
  1567. {
  1568. CRI_type = true;
  1569. tempw = 4700;
  1570. illum = 18;
  1571. }
  1572. else if (localMethod == "NG Solux Lamp 4700K")
  1573. {
  1574. CRI_type = true;
  1575. tempw = 4480;
  1576. illum = 19;
  1577. }
  1578. else if (localMethod == "LED LSI Lumelex 2040")
  1579. {
  1580. CRI_type = true;
  1581. tempw = 2970;
  1582. illum = 20;
  1583. }
  1584. else if (localMethod == "LED CRS SP12 WWMR16")
  1585. {
  1586. CRI_type = true;
  1587. tempw = 3050;
  1588. illum = 21;
  1589. }
  1590. else
  1591. {
  1592. CRI_type = false;
  1593. }
  1594. if (CRI_type)
  1595. {
  1596. double x, y, z;
  1597. double Ywb = 1.0;
  1598. double[][] spect_illum = {
  1599. Daylight5300_spect, Cloudy6200_spect, Shade7600_spect, A2856_spect, FluoF1_spect, FluoF2_spect, FluoF3_spect,
  1600. FluoF4_spect, FluoF5_spect, FluoF6_spect, FluoF7_spect, FluoF8_spect, FluoF9_spect, FluoF10_spect, FluoF11_spect,
  1601. FluoF12_spect, HMI_spect, GTI_spect, JudgeIII_spect, Solux3500_spect, Solux4100_spect, Solux4700_spect,
  1602. NG_Solux4700_spect, NG_CRSSP12WWMR16_spect, NG_CRSSP12WWMR16_spect
  1603. };
  1604. float[] DeltaE = new float[50], DeltaEs = new float[8];
  1605. float quadCRI = 0.0f, quadCRIs = 0.0f;
  1606. float CRI_RT = (float)0.0;
  1607. float[] CRI = new float[50];
  1608. float CRI_RTs = (float)0.0;
  1609. float[] CRIs = new float[8];
  1610. for (int i = 0; i < N_c; i++)
  1611. {
  1612. spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], out XchkLamp[i], out YchkLamp[i], out ZchkLamp[i]);
  1613. }
  1614. //calculate XYZ for each color : for Blackbody and Daylight at tempw
  1615. if (tempw <= INITIALBLACKBODY)
  1616. {
  1617. for (int i = 0; i < N_c; i++)
  1618. {
  1619. spectrum_to_color_xyz_blackbody(spec_color[i], tempw, out Xchk[i], out Ychk[i], out Zchk[i]);
  1620. }
  1621. spectrum_to_xyz_blackbody(tempw, out x, out y, out z);//for white point
  1622. }
  1623. else
  1624. { // after 6600K (arbitrary) I use daylight...because ...but there is no lamp...
  1625. double m11, m22, x_DD, y_DD, interm2;
  1626. if (tempw <= 7000)
  1627. {
  1628. x_DD = -4.6070e9 / (tempw * tempw * tempw) + 2.9678e6 / (tempw * tempw) + 0.09911e3 / tempw + 0.244063;
  1629. }
  1630. else
  1631. {
  1632. x_DD = -2.0064e9 / (tempw * tempw * tempw) + 1.9018e6 / (tempw * tempw) + 0.24748e3 / tempw + 0.237040;
  1633. }
  1634. y_DD = -3.0 * x_DD * x_DD + 2.87 * x_DD - 0.275;
  1635. //calculate D -daylight in function of s0, s1, s2 and temp ==> x_D y_D
  1636. //S(lamda)=So(lambda)+m1*s1(lambda)+m2*s2(lambda)
  1637. interm2 = (0.0241 + 0.2562 * x_DD - 0.734 * y_DD);
  1638. m11 = (-1.3515 - 1.7703 * x_DD + 5.9114 * y_DD) / interm2;
  1639. m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2;
  1640. for (int i = 0; i < N_c; i++)
  1641. {
  1642. spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, out Xchk[i], out Ychk[i], out Zchk[i]);
  1643. }
  1644. spectrum_to_xyz_daylight(m11, m22, out x, out y, out z);
  1645. }
  1646. if (settings_verbose)
  1647. {
  1648. double correl_temp = 0.0;
  1649. XYZtoCorColorTemp(Xwb, Ywb, Zwb, out correl_temp);
  1650. //printf("Correlated temperature (lamp)=%i\n", (int)correl_temp); //use only for lamp...otherwise It give an information!!
  1651. }
  1652. double Xwb_bb = x / y; //white balance for blackbody
  1653. double Ywb_bb = 1.0;
  1654. double Zwb_bb = (1.0 - x - y) / y;
  1655. //calculate Matrix CAM02 : better than Von Kries and Bradford==> for Lamp
  1656. double adap = 1.0;
  1657. double CAM02BB00, CAM02BB01, CAM02BB02, CAM02BB10, CAM02BB11, CAM02BB12, CAM02BB20, CAM02BB21, CAM02BB22; //for CIECAT02
  1658. cieCAT02(Xwb, Ywb, Zwb, out CAM02BB00, out CAM02BB01, out CAM02BB02, out CAM02BB10, out CAM02BB11, out CAM02BB12, out CAM02BB20, out CAM02BB21, out CAM02BB22, adap);
  1659. //here new value of X,Y,Z for lamp with chromatic CAM02 adaptation
  1660. for (int i = 0; i < N_c; i++)
  1661. {
  1662. Xcam02Lamp[i] = CAM02BB00 * XchkLamp[i] + CAM02BB01 * YchkLamp[i] + CAM02BB02 * ZchkLamp[i];
  1663. Ycam02Lamp[i] = CAM02BB10 * XchkLamp[i] + CAM02BB11 * YchkLamp[i] + CAM02BB12 * ZchkLamp[i];
  1664. Zcam02Lamp[i] = CAM02BB20 * XchkLamp[i] + CAM02BB21 * YchkLamp[i] + CAM02BB22 * ZchkLamp[i];
  1665. }
  1666. //now calculate CAM02 for Blackbody (or Daylight) at tempx
  1667. cieCAT02(Xwb_bb, Ywb_bb, Zwb_bb, out CAM02BB00, out CAM02BB01, out CAM02BB02, out CAM02BB10, out CAM02BB11, out CAM02BB12, out CAM02BB20, out CAM02BB21, out CAM02BB22, adap);
  1668. //here new value of X,Y,Z for blackbody with chromatic CAM02 adaptation
  1669. for (int i = 0; i < N_c; i++)
  1670. {
  1671. Xcam02[i] = CAM02BB00 * Xchk[i] + CAM02BB01 * Ychk[i] + CAM02BB02 * Zchk[i];
  1672. Ycam02[i] = CAM02BB10 * Xchk[i] + CAM02BB11 * Ychk[i] + CAM02BB12 * Zchk[i];
  1673. Zcam02[i] = CAM02BB20 * Xchk[i] + CAM02BB21 * Ychk[i] + CAM02BB22 * Zchk[i];
  1674. // printf("CoulXYZ %i X %f Y %f Z %f\n", i, Xchk[i],Ychk[i],Zchk[i]);
  1675. // printf("CoulCAM %i X %f Y %f Z %f\n", i, Xcam02[i],Ycam02[i],Zcam02[i]);
  1676. }
  1677. //now conversion to Lab
  1678. // Lamp
  1679. double[] fx = new double[50], fy = new double[50], fz = new double[50];
  1680. for (int i = 0; i < N_c; i++)
  1681. {
  1682. xr[i] = Xcam02Lamp[i] / whiteD50[0];
  1683. yr[i] = Ycam02Lamp[i] / whiteD50[1];
  1684. zr[i] = Zcam02Lamp[i] / whiteD50[2];
  1685. // xr, yr , zr > epsilon
  1686. if (xr[i] > epsilon)
  1687. {
  1688. fx[i] = Math.Pow/*std::cbrt*/(xr[i], 1.0 / 3);
  1689. }
  1690. else
  1691. {
  1692. fx[i] = (903.3 * xr[i] + 16.0) / 116.0;
  1693. }
  1694. if (yr[i] > epsilon)
  1695. {
  1696. fy[i] = Math.Pow(yr[i], 1.0 / 3);
  1697. }
  1698. else
  1699. {
  1700. fy[i] = (903.3 * yr[i] + 16.0) / 116.0;
  1701. }
  1702. if (zr[i] > epsilon)
  1703. {
  1704. fz[i] = Math.Pow(zr[i], 1.0 / 3);
  1705. }
  1706. else
  1707. {
  1708. fz[i] = (903.3 * zr[i] + 16.0) / 116.0;
  1709. }
  1710. }
  1711. double[] Llamp = new double[50], alamp = new double[50], blamp = new double[50];
  1712. for (int i = 0; i < N_c; i++)
  1713. {
  1714. Llamp[i] = 116.0 * fy[i] - 16.0;
  1715. alamp[i] = 500.0 * (fx[i] - fy[i]);
  1716. blamp[i] = 200.0 * (fy[i] - fz[i]);
  1717. }
  1718. //blackbody at tempx
  1719. for (int i = 0; i < N_c; i++)
  1720. {
  1721. xr[i] = Xcam02[i] / whiteD50[0];
  1722. yr[i] = Ycam02[i] / whiteD50[1];
  1723. zr[i] = Zcam02[i] / whiteD50[2];
  1724. //
  1725. if (xr[i] > epsilon)
  1726. {
  1727. fx[i] = Math.Pow(xr[i], 1.0 / 3);
  1728. }
  1729. else
  1730. {
  1731. fx[i] = (903.3 * xr[i] + 16.0) / 116.0;
  1732. }
  1733. if (yr[i] > epsilon)
  1734. {
  1735. fy[i] = Math.Pow(yr[i], 1.0 / 3);
  1736. }
  1737. else
  1738. {
  1739. fy[i] = (903.3 * yr[i] + 16.0) / 116.0;
  1740. }
  1741. if (zr[i] > epsilon)
  1742. {
  1743. fz[i] = Math.Pow(zr[i], 1.0 / 3);
  1744. }
  1745. else
  1746. {
  1747. fz[i] = (903.3 * zr[i] + 16.0) / 116.0;
  1748. }
  1749. }
  1750. double[] Lbb = new double[50], abb = new double[50], bbb = new double[50];
  1751. for (int i = 0; i < N_c; i++)
  1752. {
  1753. Lbb[i] = 116.0 * fy[i] - 16.0;
  1754. abb[i] = 500.0 * (fx[i] - fy[i]);
  1755. bbb[i] = 200.0 * (fy[i] - fz[i]);
  1756. }
  1757. ////display value to verify calculus
  1758. //if (settings_CRI_color != 0)
  1759. //{
  1760. // //printf("Color Number %i\n", numero_color);
  1761. // //printf("L_refer=%2.2f a=%2.2f b=%2.2f\n", Lbb[numero_color], abb[numero_color], bbb[numero_color]);
  1762. // //printf("L_lamp=%2.2f al=%2.2f bl=%2.2f\n", Llamp[numero_color], alamp[numero_color], blamp[numero_color]);
  1763. //}
  1764. //then calculate DeltaE CIE 1976
  1765. for (int i = 0; i < 8; i++)
  1766. {
  1767. DeltaEs[i] = (float)Math.Sqrt((Lbb[i] - Llamp[i]) * (Lbb[i] - Llamp[i]) + (abb[i] - alamp[i]) * (abb[i] - alamp[i]) + (bbb[i] - blamp[i]) * (bbb[i] - blamp[i]));
  1768. }
  1769. for (int i = 0; i < 8; i++)
  1770. {
  1771. CRIs[i] = 100 - 3.0f * DeltaEs[i]; //3.0 coef to adapt ==> same results than CRI "official"
  1772. }
  1773. for (int i = 0; i < 8; i++)
  1774. {
  1775. CRI_RTs += CRIs[i];
  1776. }
  1777. CRI_RTs /= 8;
  1778. for (int i = 0; i < 8; i++)
  1779. {
  1780. quadCRIs += (CRIs[i] - CRI_RTs) * (CRIs[i] - CRI_RTs);
  1781. }
  1782. quadCRIs /= 8;
  1783. for (int i = 0; i < N_c; i++)
  1784. {
  1785. DeltaE[i] = (float)Math.Sqrt((Lbb[i] - Llamp[i]) * (Lbb[i] - Llamp[i]) + (abb[i] - alamp[i]) * (abb[i] - alamp[i]) + (bbb[i] - blamp[i]) * (bbb[i] - blamp[i]));
  1786. }
  1787. for (int i = 0; i < N_c; i++)
  1788. {
  1789. CRI[i] = 100 - 3.0f * DeltaE[i]; //3.0 coef to adapt ==> same results than CRI "official"
  1790. }
  1791. for (int i = 0; i < N_c; i++)
  1792. {
  1793. CRI_RT += CRI[i];
  1794. }
  1795. CRI_RT /= N_c;
  1796. for (int i = 0; i < N_c; i++)
  1797. {
  1798. quadCRI += (CRI[i] - CRI_RT) * (CRI[i] - CRI_RT);
  1799. }
  1800. quadCRI /= N_c;
  1801. //if (settings_CRI_color != 0)
  1802. //{
  1803. // //printf("CRI_standard=%i CRI:1->8=%i %i %i %i %i %i %i %i Sigma=%2.1f\n", (int)CRI_RTs, (int)CRIs[0], (int)CRIs[1], (int)CRIs[2], (int)CRIs[3], (int)CRIs[4], (int)CRIs[5], (int)CRIs[6], (int)CRIs[7], sqrt(static_cast<double>(quadCRIs)));
  1804. // //printf("CRI_RT_exten=%i CRI:9->20=%i %i %i %i %i %i %i %i %i %i %i %i Sigma=%2.1f\n", (int)CRI_RT, (int)CRI[8], (int)CRI[9], (int)CRI[10], (int)CRI[11], (int)CRI[12], (int)CRI[13], (int)CRI[14], (int)CRI[15], (int)CRI[16], (int)CRI[17], (int)CRI[18], (int)CRI[19], static_cast<double>(sqrt(quadCRI)));
  1805. //}
  1806. }
  1807. }
  1808. }
  1809. ///// <summary>
  1810. ///// 白平衡-图像转换方法(Image8.cc)
  1811. ///// </summary>
  1812. ///// <param name="src"></param>
  1813. //public static void/*Mat*/ imgGetStdImage(Mat src)
  1814. //{
  1815. // Mat dst = src.Clone();
  1816. // // compute channel multipliers
  1817. // double/*float*/ rm = 1.0f, gm = 1.0f, bm = 1.0f;
  1818. // if (localTemp/*ctemp.getTemp()*/ >= 0)
  1819. // {
  1820. // double drm, dgm, dbm;
  1821. // temp2mul(localTemp, localGreen, localEqual, out drm, out dgm, out dbm);
  1822. // //ctemp.getMultipliers(drm, dgm, dbm);
  1823. // rm = drm;
  1824. // gm = dgm;
  1825. // bm = dbm;
  1826. // rm = 1.0f / rm;
  1827. // gm = 1.0f / gm;
  1828. // bm = 1.0f / bm;
  1829. // double/*float*/ mul_lum = 0.299f * rm + 0.587f * gm + 0.114f * bm;
  1830. // rm /= mul_lum;
  1831. // gm /= mul_lum;
  1832. // bm /= mul_lum;
  1833. // }
  1834. // int imwidth = src.Width;// image->getWidth(); // Destination image
  1835. // int imheight = src.Height;// image->getHeight(); // Destination image
  1836. // int maxx = imwidth - 1;// width; // Source image
  1837. // int maxy = imheight - 1;// height; // Source image
  1838. // int sx1 = 0, sy1 = 0;
  1839. // double/*float*/ rm2 = rm;
  1840. // double/*float*/ gm2 = gm;
  1841. // double/*float*/ bm2 = bm;
  1842. // // Iterating all the rows of the destination image
  1843. // for (int iy = 0; iy < imheight; iy++)
  1844. // {
  1845. // // special case (speedup for 1:1 scale)
  1846. // // i: source image, first line of the current destination row
  1847. // int src_y = sy1 + iy;
  1848. // // overflow security check, not sure that it's necessary
  1849. // if (src_y >= maxy)
  1850. // {
  1851. // continue;
  1852. // }
  1853. // for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x++)
  1854. // {
  1855. // double/*float*/ r_, g_, b_;
  1856. // // overflow security check, not sure that it's necessary
  1857. // if (src_x >= maxx)
  1858. // {
  1859. // continue;
  1860. // }
  1861. // Vec3b rgb123 = dst.At<Vec3b>(src_y, src_x);
  1862. // r_ = rgb123.Item2;
  1863. // g_ = rgb123.Item1;
  1864. // b_ = rgb123.Item0;
  1865. // Vec3b rgb = new Vec3b();
  1866. // rgb[0] = (byte)Math.Max(0, Math.Min(255, bm2 * b_)); //m_pLookupB[rgb123[0]];
  1867. // rgb[1] = (byte)Math.Max(0, Math.Min(255, gm2 * g_)); //m_pLookupG[rgb123[1]];
  1868. // rgb[2] = (byte)Math.Max(0, Math.Min(255, rm2 * r_));
  1869. // dst.Set<Vec3b>(src_y, src_x, rgb);
  1870. // }
  1871. // }
  1872. // Cv2.ImShow("dst", dst);
  1873. //}
  1874. ///// <summary>
  1875. ///// 白平衡-图像转换方法(rawimagesource.cc)
  1876. ///// </summary>
  1877. ///// <param name="src"></param>
  1878. //public static void RawImageSource_getImage(Mat src)
  1879. //{
  1880. //}
  1881. ///// <summary>
  1882. ///// 白平衡-图像转换方法
  1883. ///// </summary>
  1884. ///// <param name="value"></param>
  1885. ///// <param name="position"></param>
  1886. //private static void ForeachFunctionVeb3ForWhiteBalance(Vec3b* value, int* position)
  1887. //{
  1888. // //对每个像素点的操作
  1889. // Vec3b rgb = new Vec3b();
  1890. // rgb[0] = (byte)Math.Max(0, Math.Min(255, bm2 * value->Item0));
  1891. // rgb[1] = (byte)Math.Max(0, Math.Min(255, gm2 * value->Item1));
  1892. // rgb[2] = (byte)Math.Max(0, Math.Min(255, rm2 * value->Item2));
  1893. // phaseTemp1.Set(position[0], position[1], rgb);
  1894. //}
  1895. /// <summary>
  1896. /// 白平衡【完美反射算法<--灰度世界算法】、手动模式
  1897. /// 灰度世界算法以灰度世界假设为基础,假设为:对于一幅有着大量色彩变化的图像,RGB三个分量的平均值趋于同一个灰度值(https://mp.weixin.qq.com/s/aiVIci0NQVyUTJ7V8ElH3g)
  1898. /// 完美反射理论假设图像中最亮的点就是白点,并以此白点为参考对图像进行自动白平衡,最亮点定义为[公式]的最大值(https://zhuanlan.zhihu.com/p/96001776)
  1899. ///
  1900. /// </summary>
  1901. /// <param name="src"></param>
  1902. /// <returns></returns>
  1903. public static Mat WhiteBalanceFunction(Mat src, List<Args> lists)
  1904. {
  1905. if (src.Channels() == 1)
  1906. {
  1907. src = src.CvtColor(ColorConversionCodes.GRAY2BGR);
  1908. }
  1909. Args args = lists[0];
  1910. int modeValue = int.Parse(args.Value.ToString());
  1911. if (modeValue == 2 || modeValue == 3)//色板取色、原图取色
  1912. {
  1913. Args objectSelectA;
  1914. if (modeValue == 2)
  1915. {
  1916. objectSelectA = args.choiseList[1];
  1917. }
  1918. else
  1919. {
  1920. objectSelectA = args.choiseList[2];
  1921. }
  1922. Color phaseColor = Color.FromArgb(int.Parse(objectSelectA.Lists[0].Value.ToString()));
  1923. //Mat[] dst = Cv2.Split(src);
  1924. //求原始图像的RGB分量的均值
  1925. double R, G, B;
  1926. B = phaseColor.B;// Cv2.Mean(dst[0])[0]; 21;// 226;// 217;//
  1927. G = phaseColor.G;// Cv2.Mean(dst[1])[0]; 24;// 163;// 150;//
  1928. R = phaseColor.R;// Cv2.Mean(dst[2])[0]; 32;// 111;// 98;//
  1929. /*
  1930. temp = Math.Max(1500.0/*min*//*, Math.Min(temp1, 60000.0/*max*///));
  1931. /*green = Math.Max(0.02, Math.Min(green1, 10.0));
  1932. equal = Math.Max(0.8, Math.Min(equal1, 1.5));
  1933. */
  1934. ColorTemp(R / 255.0, G / 255.0, B / 255.0, 1.0, out localTemp, out localGreen);//6464.4126892089844, 0.96839510452584376..
  1935. //temp2mul(localTemp, localGreen, localEqual, out localMulR, out localMulG, out localMulB);
  1936. //imgGetStdImage(src);
  1937. // compute channel multipliers
  1938. double rm = 1.0f, gm = 1.0f, bm = 1.0f;
  1939. if (localTemp >= 0)
  1940. {
  1941. temp2mul(localTemp, localGreen, localEqual, out rm, out gm, out bm);
  1942. rm = 1.0f / rm;
  1943. gm = 1.0f / gm;
  1944. bm = 1.0f / bm;
  1945. double mul_lum = 0.299f * rm + 0.587f * gm + 0.114f * bm;
  1946. rm /= mul_lum;
  1947. gm /= mul_lum;
  1948. bm /= mul_lum;
  1949. }
  1950. //phaseTemp1/*Mat dst1*/ = src.Clone();
  1951. //rm2 = rm;
  1952. //gm2 = gm;
  1953. //bm2 = bm;
  1954. //src.ForEachAsVec3b(ForeachFunctionVeb3ForWhiteBalance);
  1955. //if (phaseTemp1 != null && !phaseTemp1.IsDisposed) {
  1956. // phaseTemp1.CopyTo(src);
  1957. // phaseTemp1.Dispose();
  1958. //}
  1959. Mat[] dst = Cv2.Split(src);
  1960. if (dst.Length == 1)
  1961. {
  1962. dst[0] = dst[0] * bm;
  1963. dst[1] = dst[0] * gm;
  1964. dst[2] = dst[0] * rm;
  1965. }
  1966. else
  1967. {
  1968. dst[0] = dst[0] * bm;
  1969. dst[1] = dst[1] * gm;
  1970. dst[2] = dst[2] * rm;
  1971. }
  1972. Mat dst1 = new Mat();
  1973. Cv2.Merge(dst, dst1);
  1974. //Mat[] dst = Cv2.Split(src);
  1975. ////需要调整的RGB分量的增益
  1976. //double KR, KG, KB;
  1977. //KB = (R + G + B) / (3 * phaseColor.B);
  1978. //KG = (R + G + B) / (3 * phaseColor.G);
  1979. //KR = (R + G + B) / (3 * phaseColor.R);
  1980. //dst[0] = dst[0] * KB;
  1981. //dst[1] = dst[1] * KG;
  1982. //dst[2] = dst[2] * KR;
  1983. ////RGB三通道图像合并
  1984. //Mat dst1 = new Mat();
  1985. //Cv2.Merge(dst, dst1);
  1986. return dst1;// src;//
  1987. }
  1988. ////灰度世界算法-->
  1989. //OpenCvSharp.XPhoto.LearningBasedWB grayworldWB = OpenCvSharp.XPhoto.LearningBasedWB.Create();
  1990. //grayworldWB.BalanceWhite(src, src);
  1991. //grayworldWB.Dispose();
  1992. //return src;
  1993. //OpenCvSharp.XPhoto.SimpleWB simpleWB = OpenCvSharp.XPhoto.SimpleWB.Create();
  1994. //simpleWB.BalanceWhite(src, src);
  1995. //simpleWB.Dispose();
  1996. //return src;
  1997. //基于图像分析的偏色检测及颜色校正方法
  1998. //3 从原图中分离出三个通道
  1999. Mat[] vMatRGB = Cv2.Split(src);
  2000. //4 分别求三个通道的平均值
  2001. double fAverageR = Cv2.Mean(vMatRGB[2])[0]; //mean(dst[2])[0];
  2002. double fAverageG = Cv2.Mean(vMatRGB[1])[0];
  2003. double fAverageB = Cv2.Mean(vMatRGB[0])[0];
  2004. //5 求每个通道的平衡系数
  2005. double fKR = (fAverageR + fAverageG + fAverageB) / (3 * fAverageR);
  2006. double fKG = (fAverageR + fAverageG + fAverageB) / (3 * fAverageG);
  2007. double fKB = (fAverageR + fAverageG + fAverageB) / (3 * fAverageB);
  2008. //6 根据平衡系数,调整每个通道的像素值,以便图像达到白平衡
  2009. vMatRGB[2] = vMatRGB[2] * fKR;
  2010. vMatRGB[1] = vMatRGB[1] * fKG;
  2011. vMatRGB[0] = vMatRGB[0] * fKB;
  2012. //7 合并调整后的三个通道图,就是白平衡图
  2013. Mat matDst = new Mat();
  2014. Cv2.Merge(vMatRGB, matDst);
  2015. return matDst;
  2016. ////3 从原图中分离出三个通道
  2017. //Mat[] vMatRGB = Cv2.Split(src);
  2018. ////4 分别求三个通道的平均值
  2019. //double fAverageR = Cv2.Mean(vMatRGB[2])[0]; //mean(dst[2])[0];
  2020. //double fAverageG = Cv2.Mean(vMatRGB[1])[0];
  2021. //double fAverageB = Cv2.Mean(vMatRGB[0])[0];
  2022. ////5 求每个通道的平衡系数
  2023. //double fKR = (fAverageR + fAverageG + fAverageB) / (3 * fAverageR);
  2024. //double fKG = (fAverageR + fAverageG + fAverageB) / (3 * fAverageG);
  2025. //double fKB = (fAverageR + fAverageG + fAverageB) / (3 * fAverageB);
  2026. ////6 根据平衡系数,调整每个通道的像素值,以便图像达到白平衡
  2027. //vMatRGB[2] = vMatRGB[2] * fKR;
  2028. //vMatRGB[1] = vMatRGB[1] * fKG;
  2029. //vMatRGB[0] = vMatRGB[0] * fKB;
  2030. ////7 合并调整后的三个通道图,就是白平衡图
  2031. //Mat matDst = new Mat();
  2032. //Cv2.Merge(vMatRGB, matDst);
  2033. //return matDst;
  2034. //完美反射算法
  2035. //OpenCvSharp.XPhoto.SimpleWB simpleWB = OpenCvSharp.XPhoto.SimpleWB.Create();
  2036. //simpleWB.BalanceWhite(src, src);
  2037. //simpleWB.Dispose();
  2038. //return src;
  2039. }
  2040. /// <summary>
  2041. /// 图像旋转
  2042. /// </summary>
  2043. /// <param name="src"></param>
  2044. /// <param name="lists"></param>
  2045. /// <returns></returns>
  2046. public static Mat MatRotate(Mat src, List<Args> lists)
  2047. {
  2048. Color phaseColor = Color.Red;
  2049. int iColor = -1973791;
  2050. float rotate = 0;
  2051. if (lists.Count > 0)
  2052. {
  2053. foreach (Args args in lists)
  2054. {
  2055. switch (args.key)
  2056. {
  2057. case "Rotate":
  2058. rotate = float.Parse(lists[0].value.ToString());
  2059. break;
  2060. case "phaseColor":
  2061. iColor = int.Parse(args.Value.ToString());
  2062. phaseColor = Color.FromArgb(iColor);
  2063. break;
  2064. }
  2065. }
  2066. }
  2067. Mat mat = GeometryIntent.MatRotate(src, rotate, new OpenCvSharp.Scalar(phaseColor.B, phaseColor.G, phaseColor.R, 255));
  2068. return mat;
  2069. }
  2070. /// <summary>
  2071. /// 色彩平衡
  2072. /// </summary>
  2073. /// <param name="src"></param>
  2074. /// <returns></returns>
  2075. public static Mat ColorBalanceFunction(Mat src, List<Args> lists)
  2076. {
  2077. //保持明度
  2078. bool m_bPreserveLuminosity = true;
  2079. //0阴影 1中间调 2高光
  2080. int ToneRgn = 1;
  2081. //红
  2082. int cyan_red = 0;
  2083. //绿
  2084. int magenta_green = 0;
  2085. //蓝
  2086. int yellow_blue = 0;
  2087. //阴影
  2088. int TONE_SHADOWS = 0;
  2089. //中间调
  2090. int TONE_MIDTONES = 1;
  2091. //高光
  2092. int TONE_HIGHLIGHTS = 2;
  2093. foreach (Args args in lists)
  2094. {
  2095. switch (args.key)
  2096. {
  2097. case "Red":
  2098. cyan_red = int.Parse(args.Value.ToString());
  2099. break;
  2100. case "Green":
  2101. magenta_green = int.Parse(args.Value.ToString());
  2102. break;
  2103. case "Blue":
  2104. yellow_blue = int.Parse(args.Value.ToString());
  2105. break;
  2106. }
  2107. }
  2108. int[] cyan_red_rgn = new int[3] { 0, 0, 0 };
  2109. int[] magenta_green_rgn = new int[3] { 0, 0, 0 };
  2110. int[] yellow_blue_rgn = new int[3] { 0, 0, 0 };
  2111. cyan_red_rgn[ToneRgn] = cyan_red;
  2112. magenta_green_rgn[ToneRgn] = magenta_green;
  2113. yellow_blue_rgn[ToneRgn] = yellow_blue;
  2114. // add for lightening, sub for darkening
  2115. double[] highlights_add = new double[256];
  2116. double[] midtones_add = new double[256];
  2117. double[] shadows_add = new double[256];
  2118. double[] highlights_sub = new double[256];
  2119. double[] midtones_sub = new double[256];
  2120. double[] shadows_sub = new double[256];
  2121. for (int i = 0; i < 256; i++)
  2122. {
  2123. highlights_add[i] = shadows_sub[255 - i] = (1.075 - 1 / (i / 16.0 + 1));
  2124. midtones_add[i] = midtones_sub[i] = 0.667 * (1 - Math.Pow((i - 127.0) / 127.0, 2));
  2125. shadows_add[i] = highlights_sub[i] = 0.667 * (1 - Math.Pow((i - 127.0) / 127.0, 2));
  2126. }
  2127. // Set the transfer arrays (for speed)
  2128. double[][] cyan_red_transfer = new double[3][];
  2129. double[][] magenta_green_transfer = new double[3][];
  2130. double[][] yellow_blue_transfer = new double[3][];
  2131. cyan_red_transfer[TONE_SHADOWS] = (cyan_red_rgn[TONE_SHADOWS] > 0) ? shadows_add : shadows_sub;
  2132. cyan_red_transfer[TONE_MIDTONES] = (cyan_red_rgn[TONE_MIDTONES] > 0) ? midtones_add : midtones_sub;
  2133. cyan_red_transfer[TONE_HIGHLIGHTS] = (cyan_red_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub;
  2134. magenta_green_transfer[TONE_SHADOWS] = (magenta_green_rgn[TONE_SHADOWS] > 0) ? shadows_add : shadows_sub;
  2135. magenta_green_transfer[TONE_MIDTONES] = (magenta_green_rgn[TONE_MIDTONES] > 0) ? midtones_add : midtones_sub;
  2136. magenta_green_transfer[TONE_HIGHLIGHTS] = (magenta_green_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub;
  2137. yellow_blue_transfer[TONE_SHADOWS] = (yellow_blue_rgn[TONE_SHADOWS] > 0) ? shadows_add : shadows_sub;
  2138. yellow_blue_transfer[TONE_MIDTONES] = (yellow_blue_rgn[TONE_MIDTONES] > 0) ? midtones_add : midtones_sub;
  2139. yellow_blue_transfer[TONE_HIGHLIGHTS] = (yellow_blue_rgn[TONE_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub;
  2140. int[] m_pLookupR = new int[256];
  2141. int[] m_pLookupG = new int[256];
  2142. int[] m_pLookupB = new int[256];
  2143. for (int i = 0; i < 256; i++)
  2144. {
  2145. int r_n = i, g_n = i, b_n = i;
  2146. r_n += (int)(cyan_red_rgn[TONE_SHADOWS] * cyan_red_transfer[TONE_SHADOWS][r_n]); if (r_n < 0) r_n = 0; if (r_n > 255) r_n = 255;
  2147. r_n += (int)(cyan_red_rgn[TONE_MIDTONES] * cyan_red_transfer[TONE_MIDTONES][r_n]); if (r_n < 0) r_n = 0; if (r_n > 255) r_n = 255;
  2148. r_n += (int)(cyan_red_rgn[TONE_HIGHLIGHTS] * cyan_red_transfer[TONE_HIGHLIGHTS][r_n]); if (r_n < 0) r_n = 0; if (r_n > 255) r_n = 255;
  2149. g_n += (int)(magenta_green_rgn[TONE_SHADOWS] * magenta_green_transfer[TONE_SHADOWS][g_n]); if (g_n < 0) g_n = 0; if (g_n > 255) g_n = 255;
  2150. g_n += (int)(magenta_green_rgn[TONE_MIDTONES] * magenta_green_transfer[TONE_MIDTONES][g_n]); if (g_n < 0) g_n = 0; if (g_n > 255) g_n = 255;
  2151. g_n += (int)(magenta_green_rgn[TONE_HIGHLIGHTS] * magenta_green_transfer[TONE_HIGHLIGHTS][g_n]); if (g_n < 0) g_n = 0; if (g_n > 255) g_n = 255;
  2152. b_n += (int)(yellow_blue_rgn[TONE_SHADOWS] * yellow_blue_transfer[TONE_SHADOWS][b_n]); if (b_n < 0) b_n = 0; if (b_n > 255) b_n = 255;
  2153. b_n += (int)(yellow_blue_rgn[TONE_MIDTONES] * yellow_blue_transfer[TONE_MIDTONES][b_n]); if (b_n < 0) b_n = 0; if (b_n > 255) b_n = 255;
  2154. b_n += (int)(yellow_blue_rgn[TONE_HIGHLIGHTS] * yellow_blue_transfer[TONE_HIGHLIGHTS][b_n]); if (b_n < 0) b_n = 0; if (b_n > 255) b_n = 255;
  2155. m_pLookupR[i] = r_n;
  2156. m_pLookupG[i] = g_n;
  2157. m_pLookupB[i] = b_n;
  2158. }
  2159. for (int k = 0; k < src.Height; k++)
  2160. {
  2161. for (int m = 0; m < src.Width; m++)
  2162. {
  2163. Vec3b rgb123 = src.At<Vec3b>(k, m);
  2164. Vec3b rgb = new Vec3b();
  2165. rgb[0] = (byte)m_pLookupB[rgb123[0]];
  2166. rgb[1] = (byte)m_pLookupG[rgb123[1]];
  2167. rgb[2] = (byte)m_pLookupR[rgb123[2]];
  2168. //mat.Set<Vec3b>(k, m, rgb);
  2169. if (m_bPreserveLuminosity) // preserve luminosity
  2170. {
  2171. double H = 0, L = 0, S = 0;
  2172. BaseTools.RGBtoHLS(rgb, out H, out L, out S);
  2173. // calculate L value
  2174. int cmax = Math.Max(rgb123[0], Math.Max(rgb123[1], rgb123[2]));
  2175. int cmin = Math.Min(rgb123[0], Math.Min(rgb123[1], rgb123[2]));
  2176. L = (cmax + cmin) / 2.0 / 255.0;
  2177. rgb = BaseTools.HLStoRGB(H, L, S);
  2178. }
  2179. src.Set<Vec3b>(k, m, rgb);
  2180. }
  2181. }
  2182. return src;
  2183. }
  2184. /// <summary>
  2185. /// 阴影校正
  2186. /// </summary>
  2187. /// <param name="src"></param>
  2188. /// <returns></returns>
  2189. public static Mat ShadingCorrection(Mat src)
  2190. {
  2191. if (src.Channels() == 1)
  2192. return src;
  2193. Mat temp = null, Ag = null, A0 = null, Aglp = null, dst = null;
  2194. try
  2195. {
  2196. src.ConvertTo(src, MatType.CV_32FC3);
  2197. temp = src.CvtColor(ColorConversionCodes.BGR2YCrCb);
  2198. Mat[] tempArr = temp.Split();
  2199. Ag = new Mat();
  2200. tempArr[0].CopyTo(Ag); ;
  2201. A0 = new Mat();
  2202. Ag.CopyTo(A0);
  2203. Aglp = BaseTools.ImageSmoothIIR(Ag, 0.99);
  2204. tempArr[0] = A0 - Aglp + Cv2.Mean(Aglp);
  2205. dst = new Mat();
  2206. Cv2.Merge(tempArr, dst);
  2207. dst = dst.CvtColor(ColorConversionCodes.YCrCb2BGR);
  2208. dst.ConvertTo(dst, MatType.CV_8UC3);
  2209. dst.CopyTo(src);
  2210. return src;
  2211. }
  2212. catch (Exception e)
  2213. {
  2214. throw e;
  2215. }
  2216. finally
  2217. {
  2218. if (temp != null) temp.Dispose();
  2219. if (Ag != null) Ag.Dispose();
  2220. if (A0 != null) A0.Dispose();
  2221. if (Aglp != null) Aglp.Dispose();
  2222. if (dst != null) dst.Dispose();
  2223. GC.Collect();
  2224. }
  2225. }
  2226. /// <summary>
  2227. /// //调节图像的色相、饱和度、/*亮*/明度(明度)
  2228. /// HSL空间图像亮度、饱和度调节 https://blog.csdn.net/feilong_csdn/article/details/82755816?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
  2229. /// </summary>
  2230. /// <param name="src1"></param>
  2231. /// <param name="dH"></param>
  2232. /// <param name="dS"></param>
  2233. /// <param name="dV"></param>
  2234. public static bool AddHSV(Mat src1, double dH, double dS, double dV)
  2235. {
  2236. bool bResult = false;
  2237. dH *= 0.9;//根据PS效果图调试值,待确认
  2238. //dS *= 2.55;//根据PS效果图调试值,待确认
  2239. //dV *= 2.55;//根据PS效果图调试值,待确认
  2240. //phaseTemp1 = new Mat(src.Size(), src.Type()); //创建一个和原图像大小相同,类型相同,像素值为0的图像。
  2241. phaseTemp1 = src1.CvtColor(ColorConversionCodes.BGR2HLS/*BGR2HSV*/);
  2242. int height = phaseTemp1.Height;
  2243. int width = phaseTemp1.Width;
  2244. int channels = phaseTemp1.Channels();
  2245. //contrast = (contrast - 1.0) / 2.0 + 1.0;//待确认参数范围
  2246. //if (channels == 3 || channels == 4) //如果是彩色图像
  2247. //{
  2248. // src.ForEachAsVec3b(ForeachFunctionByteForBCGTransferMultiChannel);
  2249. //}
  2250. //else if (channels == 1) //灰度图像
  2251. //{
  2252. // src.ForEachAsDouble(ForeachFunctionByteForBCGTransferOneChannel);//ForEachAsByte
  2253. //}
  2254. ////src.ConvertTo(phaseTemp1, -1, contrast, brightness);
  2255. //////phaseTemp1 = src.ConvertScaleAbs((brightness + 100) / 100.0, (1.0 - contrast) * 50);
  2256. //////Cv2.Normalize(phaseTemp1, phaseTemp1, 1, 255, NormTypes.MinMax);
  2257. //对每个像素点的操作
  2258. for (int i = 0; i < height; i++)
  2259. {
  2260. for (int j = 0; j < width; j++)
  2261. {
  2262. if (channels == 3 || channels == 4) //如果是彩色图像
  2263. {
  2264. double v0 = (phaseTemp1.At<Vec3b>(i, j)[0]) + dH;
  2265. double v2 = (phaseTemp1.At<Vec3b>(i, j)[2]) + dS;
  2266. double v1 = (phaseTemp1.At<Vec3b>(i, j)[1]) + dV;
  2267. if (v0 > 180) v0 -= 180;
  2268. else if (v0 < 0) v0 += 180;
  2269. if (v1 > 255) v1 = 255;
  2270. else if (v1 < 0) v1 = 0;
  2271. if (v2 > 255) v2 = 255;
  2272. else if (v2 < 0) v2 = 0;
  2273. Vec3b vec = new Vec3b();
  2274. vec[0] = (byte)v0;
  2275. vec[1] = (byte)v1;
  2276. vec[2] = (byte)v2;
  2277. phaseTemp1.Set<Vec3b>(i, j, vec);
  2278. }
  2279. else if (channels == 1) //灰度图像
  2280. {
  2281. double v = contrast * (phaseTemp1.At<byte>(i, j)) + brightness;
  2282. if (v > 255) v = 255;
  2283. if (v < 0) v = 0;
  2284. phaseTemp1.Set<double>(i, j, v);
  2285. }
  2286. }
  2287. }
  2288. phaseTemp1 = phaseTemp1.CvtColor(ColorConversionCodes.HLS2BGR/*HSV2BGR*/);
  2289. return bResult;
  2290. }
  2291. /// <summary>
  2292. /// 色度/饱和度/亮度
  2293. /// gmip有源码,效果差不多,回头考虑换还是不换
  2294. /// </summary>
  2295. /// <param name="src"></param>
  2296. /// <returns></returns>
  2297. public static Mat BshTransferFunction(Mat src, List<Args> lists)
  2298. {
  2299. ImageMagick.MagickImage image = null;
  2300. try
  2301. {
  2302. image = new ImageMagick.MagickImage(OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src));
  2303. //参数读取
  2304. ImageMagick.Percentage brightness = new ImageMagick.Percentage(0);
  2305. ImageMagick.Percentage saturation = new ImageMagick.Percentage(0);
  2306. ImageMagick.Percentage hue = new ImageMagick.Percentage(0);
  2307. double dH = 0;
  2308. double dS = 0;
  2309. double dV = 0;
  2310. for (int i = 0; i < lists.Count; i++)
  2311. {
  2312. Args args = lists[i];
  2313. switch (args.Key)
  2314. {
  2315. case "Hue":
  2316. double hueNum = 0;
  2317. if (double.TryParse(args.Value.ToString(), out hueNum))
  2318. {
  2319. hue = new ImageMagick.Percentage(hueNum);
  2320. dH = hueNum - 100.0;
  2321. }
  2322. break;
  2323. case "Saturation":
  2324. double saturationNum = 0;
  2325. if (double.TryParse(args.Value.ToString(), out saturationNum))
  2326. {
  2327. saturation = new ImageMagick.Percentage(saturationNum);
  2328. dS = saturationNum - 100.0;
  2329. }
  2330. break;
  2331. case "Brightness":
  2332. double brightnessNum = 0;
  2333. if (double.TryParse(args.Value.ToString(), out brightnessNum))
  2334. {
  2335. brightness = new ImageMagick.Percentage(brightnessNum);
  2336. dV = brightnessNum - 100.0;
  2337. }
  2338. break;
  2339. default:
  2340. break;
  2341. }
  2342. }
  2343. //image.Modulate(brightness, saturation, hue);
  2344. AddHSV(src, dH, dS, dV);
  2345. phaseTemp1.CopyTo(src);
  2346. return src;
  2347. }
  2348. catch (Exception e)
  2349. {
  2350. throw e;
  2351. }
  2352. finally
  2353. {
  2354. if (image != null) image.Dispose();
  2355. if (phaseTemp1 != null && !phaseTemp1.IsDisposed) phaseTemp1.Dispose();
  2356. GC.Collect();
  2357. }
  2358. }
  2359. private static void ForeachFunctionByteForBCGTransferMultiChannel(Vec3b* value, int* position)
  2360. {
  2361. int y = position[0];
  2362. int x = position[1];
  2363. double v0 = contrast * (value->Item0 - 128.0) + 128.0 + brightness;
  2364. double v1 = contrast * (value->Item1 - 128.0) + 128.0 + brightness;
  2365. double v2 = contrast * (value->Item2 - 128.0) + 128.0 + brightness;
  2366. if (v0 > 255) v0 = 255;
  2367. else if (v0 < 0) v0 = 0;
  2368. if (v1 > 255) v1 = 255;
  2369. else if (v1 < 0) v1 = 0;
  2370. if (v2 > 255) v2 = 255;
  2371. else if (v2 < 0) v2 = 0;
  2372. Vec3b vec = new Vec3b();
  2373. vec[0] = (byte)v0;
  2374. vec[1] = (byte)v1;
  2375. vec[2] = (byte)v2;
  2376. phaseTemp1.Set<Vec3b>(y, x, vec);
  2377. }
  2378. private static void ForeachFunctionByteForBCGTransferOneChannel(double* value, int* position)
  2379. {
  2380. int y = position[0];
  2381. int x = position[1];
  2382. double v = contrast * (*value - 128.0) + 128.0 + brightness;
  2383. if (v > 255) v = 255;
  2384. else if (v < 0) v = 0;
  2385. phaseTemp1.Set<double>(y, x, v);
  2386. }
  2387. /// <summary>
  2388. /// 亮度/对比度/伽马值
  2389. /// </summary>
  2390. /// <param name="src"></param>
  2391. /// <returns></returns>
  2392. public static Mat BCGTransferFunction(Mat src, List<Args> lists)
  2393. {
  2394. bool isFourChannels = false;
  2395. if (src.Channels() == 4)
  2396. {
  2397. Cv2.CvtColor(src, src, OpenCvSharp.ColorConversionCodes.BGRA2BGR);
  2398. isFourChannels = true;
  2399. }
  2400. phaseTemp1 = new Mat(src.Size(), src.Type()); //创建一个和原图像大小相同,类型相同,像素值为0的图像。
  2401. Mat imageGamma = null;
  2402. try
  2403. {
  2404. // 需要确定这个范围,可能可以定义
  2405. //double contrast = 1.5; //对比度 contrast Enter the alpha value [1.0-3.0]:
  2406. //double brightness = 50; //亮度 brightness Enter the beta value [0-100]
  2407. double gamma = 5; //伽马值 gamma
  2408. for (int i = 0; i < lists.Count; i++)
  2409. {
  2410. Args args = lists[i];
  2411. switch (args.Key)
  2412. {
  2413. case "Brightness":
  2414. double.TryParse(args.Value.ToString(), out brightness);
  2415. break;
  2416. case "Contrast":
  2417. double.TryParse(args.Value.ToString(), out contrast);
  2418. break;
  2419. case "Gamma":
  2420. double.TryParse(args.Value.ToString(), out gamma);
  2421. break;
  2422. default:
  2423. break;
  2424. }
  2425. }
  2426. //int height = src.Height;
  2427. //int width = src.Width;
  2428. int channels = src.Channels();
  2429. contrast = (contrast - 1.0) / 2.0 + 1.0;//待确认参数范围
  2430. if (channels == 3 || channels == 4) //如果是彩色图像
  2431. {
  2432. src.ForEachAsVec3b(ForeachFunctionByteForBCGTransferMultiChannel);
  2433. }
  2434. else if (channels == 1) //灰度图像
  2435. {
  2436. src.ForEachAsDouble(ForeachFunctionByteForBCGTransferOneChannel);//ForEachAsByte
  2437. }
  2438. //对每个像素点的操作
  2439. //for (int i = 0; i < height; i++)
  2440. //{
  2441. // for (int j = 0; j < width; j++)
  2442. // {
  2443. // if (channels == 3 || channels == 4) //如果是彩色图像
  2444. // {
  2445. // double v0 = contrast * (src.At<Vec3b>(i, j)[0]) + brightness;
  2446. // double v1 = contrast * (src.At<Vec3b>(i, j)[1]) + brightness;
  2447. // double v2 = contrast * (src.At<Vec3b>(i, j)[2]) + brightness;
  2448. // if (v0 > 255) v0 = 255;
  2449. // if (v0 < 0) v0 = 0;
  2450. // if (v1 > 255) v1 = 255;
  2451. // if (v1 < 0) v1 = 0;
  2452. // if (v2 > 255) v2 = 255;
  2453. // if (v2 < 0) v2 = 0;
  2454. // Vec3b vec = new Vec3b();
  2455. // vec[0] = (byte)v0;
  2456. // vec[1] = (byte)v1;
  2457. // vec[2] = (byte)v2;
  2458. // phaseTemp1.Set<Vec3b>(i, j, vec);
  2459. // }
  2460. // else if (channels == 1) //灰度图像
  2461. // {
  2462. // double v = contrast * (src.At<byte>(i, j)) + brightness;
  2463. // if (v > 255) v = 255;
  2464. // if (v < 0) v = 0;
  2465. // phaseTemp1.Set<double>(i, j, v);
  2466. // }
  2467. // }
  2468. //}
  2469. imageGamma = new Mat();
  2470. //灰度归一化
  2471. phaseTemp1.ConvertTo(imageGamma, MatType.CV_64F, 1.0 / 255, 0);
  2472. Cv2.Pow(imageGamma, gamma, imageGamma);//dist 要与imageGamma有相同的数据类型
  2473. imageGamma.ConvertTo(imageGamma, MatType.CV_8U, 255, 0);
  2474. //return imageGamma;
  2475. imageGamma.CopyTo(phaseTemp1);
  2476. phaseTemp1.CopyTo(src);
  2477. if (isFourChannels)
  2478. {
  2479. Cv2.CvtColor(src, src, OpenCvSharp.ColorConversionCodes.BGR2BGRA);
  2480. }
  2481. return src;
  2482. }
  2483. catch (Exception ex)
  2484. {
  2485. throw ex;
  2486. }
  2487. finally
  2488. {
  2489. //if (dst != null) dst.Dispose();
  2490. if (imageGamma != null) imageGamma.Dispose();
  2491. if (phaseTemp1 != null && !phaseTemp1.IsDisposed) phaseTemp1.Dispose();
  2492. GC.Collect();
  2493. }
  2494. }
  2495. /// <summary>
  2496. /// 获取图像的局部均值与局部标准差的图
  2497. /// https://blog.csdn.net/u013921430/article/details/83865427
  2498. /// </summary>
  2499. /// <param name="src"></param>
  2500. /// <param name="meansDst"></param>
  2501. /// <param name="varianceDst"></param>
  2502. /// <param name="winSize"></param>
  2503. /// <returns></returns>
  2504. public static bool getVarianceMean(Mat src/*, Mat meansDst, Mat varianceDst*/, int winSize)
  2505. {
  2506. System.Diagnostics.Debug.Assert(winSize % 2 == 1);
  2507. int copyBorderSize = (winSize - 1) / 2;
  2508. //扩充图像边界;
  2509. Mat copyBorder_yChannels = src.CopyMakeBorder(copyBorderSize, copyBorderSize, copyBorderSize, copyBorderSize, BorderTypes.Replicate/*Reflect*/);
  2510. for (int i = 0; i < src.Rows; i++)
  2511. {
  2512. for (int j = 0; j < src.Cols; j++)
  2513. {
  2514. //Rect rect = new Rect(j, i, winSize, winSize);
  2515. Mat temp = new Mat(copyBorder_yChannels, new Rect(j, i, winSize, winSize));
  2516. //Mat temp = copyBorder_yChannels.Clone(rect); //截取扩展后的图像中的一个方块;
  2517. Mat mean = new Mat();
  2518. Mat dev = new Mat();
  2519. Cv2.MeanStdDev(temp, mean, dev);
  2520. localVarianceMatrix.Set(i, j, dev.At<double>(0, 0));
  2521. localMeansMatrix.Set(i, j, mean.At<double>(0, 0));
  2522. }
  2523. }
  2524. return true;
  2525. }
  2526. /// <summary>
  2527. /// 获取图像的局部均值与局部标准差对的图
  2528. /// </summary>
  2529. /// <param name="mat">源图像</param>
  2530. /// <param name="kernel">边径长度</param>
  2531. /// <param name="threshold">阈值</param>
  2532. /// <returns></returns>
  2533. public static bool adaptEdgeEnhancement(Mat mat, int kernel, int threshold)
  2534. {
  2535. localThreshold = threshold;
  2536. dstWidth = mat.Width;
  2537. dstChannel = mat.Channels();
  2538. phaseTemp1 = mat.Clone();
  2539. calMats = mat.Clone();
  2540. //求最大值最小值
  2541. Mat element = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(kernel, kernel));
  2542. //腐蚀
  2543. phaseTempMin = new Mat();
  2544. Cv2.Erode(mat, phaseTempMin, element, null, 1, BorderTypes.Constant);
  2545. //膨胀
  2546. phaseTempMax = new Mat();
  2547. Cv2.Dilate(mat, phaseTempMax, element, null, 1, BorderTypes.Constant);
  2548. Mat f = new Mat();
  2549. Cv2.Subtract(phaseTempMax, phaseTempMin, f);
  2550. //实现边界增强
  2551. f.ForEachAsVec4b(ForeachFunctionVeb4ForThreshold);
  2552. return true;
  2553. }
  2554. private static void ForeachFunctionVeb4ForThreshold(Vec4b* value, int* position)
  2555. {
  2556. ////对每个像素点的操作
  2557. byte* pixels3 = (byte*)phaseTempMax.Data;
  2558. byte* pixels4 = (byte*)phaseTempMin.Data;
  2559. byte* pixels5 = (byte*)calMats.Data;
  2560. int offset = (position[0] * dstWidth + position[1]) * dstChannel;
  2561. Vec4b aa = new Vec4b(pixels5[offset], pixels5[offset + 1], pixels5[offset + 2], 255);
  2562. bool toedit = false;
  2563. if (value->Item0 > localThreshold)
  2564. {
  2565. toedit = true;
  2566. byte ff = pixels3[offset];
  2567. byte pp = pixels4[offset];
  2568. if ((ff + pp) / 2 < aa.Item0)
  2569. aa.Item0 = ff;
  2570. else
  2571. aa.Item0 = pp;
  2572. }
  2573. if (value->Item1 > localThreshold)
  2574. {
  2575. toedit = true;
  2576. byte ff = pixels3[offset + 1];
  2577. byte pp = pixels4[offset + 1];
  2578. if ((ff + pp) / 2 < aa.Item1)
  2579. aa.Item1 = ff;
  2580. else
  2581. aa.Item1 = pp;
  2582. }
  2583. if (value->Item2 > localThreshold)
  2584. {
  2585. toedit = true;
  2586. byte ff = pixels3[offset + 2];
  2587. byte pp = pixels4[offset + 2];
  2588. if ((ff + pp) / 2 < aa.Item2)
  2589. aa.Item2 = ff;
  2590. else
  2591. aa.Item2 = pp;
  2592. }
  2593. if (toedit)
  2594. phaseTemp1.Set(position[0], position[1], aa);
  2595. }
  2596. /// <summary>
  2597. /// 获取图像的局部均值与局部标准差对的图
  2598. /// </summary>
  2599. /// <param name="src"></param>
  2600. /// <param name="winSize"></param>
  2601. /// <param name="maxCg"></param>
  2602. /// <returns></returns>
  2603. public static bool adaptContrastEnhancement(Mat src, int winSize, int maxCg)
  2604. {
  2605. bool bResult = false;
  2606. Mat ycc = src.CvtColor(ColorConversionCodes.BGR2YUV/*BGR2YCrCb*/);//转换空间到YCrCb
  2607. Mat[] channels = Cv2.Split(ycc);//分离通道
  2608. localMeansMatrix = new Mat(src.Rows, src.Cols, MatType.CV_64F);
  2609. localVarianceMatrix = new Mat(src.Rows, src.Cols, MatType.CV_64F);
  2610. if (!getVarianceMean(channels[0], winSize))//对Y通道进行增强
  2611. {
  2612. //phaseTemp1 = ycc.CvtColor(ColorConversionCodes.YUV2BGR/*YCrCb2BGR*/);
  2613. return false;
  2614. }
  2615. Mat temp = channels[0].Clone();
  2616. //Mat mean = new Mat();
  2617. //Mat dev1 = new Mat();
  2618. //Cv2.MeanStdDev(temp, mean, dev1);
  2619. double meansGlobal = Cv2.Mean(channels[0])[0];// mean.At<Vec4b>(0, 0)[0];
  2620. //for (int i = 0; i < mean.Rows; i++)
  2621. //{
  2622. // for (int j = 0; j < mean.Cols; j++)
  2623. // {
  2624. // meansGlobal += mean.At<Vec4b>(i, j)[0];
  2625. // }
  2626. //}
  2627. Mat enhanceMatrix = new Mat(src.Rows, src.Cols, MatType.CV_8UC1);
  2628. for (int i = 0; i < src.Rows; i++) //遍历,对每个点进行自适应调节
  2629. {
  2630. for (int j = 0; j < src.Cols; j++)
  2631. {
  2632. //if (localVarianceMatrix.At<float>(i, j) >= 0.01)
  2633. //{
  2634. double cg = (double)(/*1.0*/0.2 * meansGlobal / localVarianceMatrix.At<double>(i, j));
  2635. double cgs = cg > maxCg ? maxCg : cg;
  2636. cgs = cgs < 1 ? 1 : cgs;
  2637. if (localVarianceMatrix.At<double>(i, j) == 0)
  2638. {
  2639. cgs = maxCg;
  2640. }
  2641. int channel1 = temp.Channels();
  2642. int row1 = temp.Rows;
  2643. int col1 = temp.Cols;
  2644. //cgs = 1.0;
  2645. double mean1 = localMeansMatrix.At<double>(i, j);
  2646. byte temp1 = temp.At<byte>(i, j);
  2647. int e = (int)(localMeansMatrix.At<double>(i, j) + cgs * (temp.At<byte>(i, j) - localMeansMatrix.At<double>(i, j)));// cgs * (temp.At<double>(i, j)) + (localMeansMatrix.At<double>(i, j)) * (1.0 - cgs);// (double)(localMeansMatrix.At<double>(i, j)/*localMeansMatrix.At<double>(i, j)*/ + 1.0/*cgs*/ * (channels[0].At<double/*uchar*/>(i, j) - localMeansMatrix.At<double>(i, j)/*localMeansMatrix.At<double>(i, j)*/));
  2648. if (e > 255) { e = 255; }
  2649. else if (e < 0) { e = 0; }
  2650. enhanceMatrix.Set<byte>(i, j, (byte)e);
  2651. //enhanceMatrix.At<byte/*uchar*/>(i, j) = e;
  2652. //}
  2653. //else
  2654. //{
  2655. // enhanceMatrix.Set<byte>(i, j, temp.At<byte/*uchar*/>(i, j));
  2656. // //enhanceMatrix.At<byte/*uchar*/>(i, j) = temp.at<uchar>(i, j);
  2657. //}
  2658. }
  2659. }
  2660. channels[0] = enhanceMatrix;
  2661. Cv2.Merge(channels, ycc);
  2662. phaseTemp1 = ycc.CvtColor(ColorConversionCodes.YUV2BGR/*YCrCb2BGR*/);
  2663. //dH *= 0.9;//根据PS效果图调试值,待确认
  2664. ////dS *= 2.55;//根据PS效果图调试值,待确认
  2665. ////dV *= 2.55;//根据PS效果图调试值,待确认
  2666. ////phaseTemp1 = new Mat(src.Size(), src.Type()); //创建一个和原图像大小相同,类型相同,像素值为0的图像。
  2667. //phaseTemp1 = src1.CvtColor(ColorConversionCodes.BGR2HSV);
  2668. //int height = phaseTemp1.Height;
  2669. //int width = phaseTemp1.Width;
  2670. //int channels = phaseTemp1.Channels();
  2671. ////contrast = (contrast - 1.0) / 2.0 + 1.0;//待确认参数范围
  2672. ////if (channels == 3 || channels == 4) //如果是彩色图像
  2673. ////{
  2674. //// src.ForEachAsVec3b(ForeachFunctionByteForBCGTransferMultiChannel);
  2675. ////}
  2676. ////else if (channels == 1) //灰度图像
  2677. ////{
  2678. //// src.ForEachAsDouble(ForeachFunctionByteForBCGTransferOneChannel);//ForEachAsByte
  2679. ////}
  2680. //////src.ConvertTo(phaseTemp1, -1, contrast, brightness);
  2681. ////////phaseTemp1 = src.ConvertScaleAbs((brightness + 100) / 100.0, (1.0 - contrast) * 50);
  2682. ////////Cv2.Normalize(phaseTemp1, phaseTemp1, 1, 255, NormTypes.MinMax);
  2683. ////对每个像素点的操作
  2684. //for (int i = 0; i < height; i++)
  2685. //{
  2686. // for (int j = 0; j < width; j++)
  2687. // {
  2688. // if (channels == 3 || channels == 4) //如果是彩色图像
  2689. // {
  2690. // double v0 = (phaseTemp1.At<Vec3b>(i, j)[0]) + dH;
  2691. // double v1 = (phaseTemp1.At<Vec3b>(i, j)[1]) + dS;
  2692. // double v2 = (phaseTemp1.At<Vec3b>(i, j)[2]) + dV;
  2693. // if (v0 > 180) v0 -= 180;
  2694. // else if (v0 < 0) v0 += 180;
  2695. // if (v1 > 255) v1 = 255;
  2696. // else if (v1 < 0) v1 = 0;
  2697. // if (v2 > 255) v2 = 255;
  2698. // else if (v2 < 0) v2 = 0;
  2699. // Vec3b vec = new Vec3b();
  2700. // vec[0] = (byte)v0;
  2701. // vec[1] = (byte)v1;
  2702. // vec[2] = (byte)v2;
  2703. // phaseTemp1.Set<Vec3b>(i, j, vec);
  2704. // }
  2705. // else if (channels == 1) //灰度图像
  2706. // {
  2707. // double v = contrast * (phaseTemp1.At<byte>(i, j)) + brightness;
  2708. // if (v > 255) v = 255;
  2709. // if (v < 0) v = 0;
  2710. // phaseTemp1.Set<double>(i, j, v);
  2711. // }
  2712. // }
  2713. //}
  2714. //phaseTemp1 = phaseTemp1.CvtColor(ColorConversionCodes.HSV2BGR);
  2715. return bResult;
  2716. }
  2717. /// <summary>
  2718. /// 描绘
  2719. /// 目前用的是ImageMagick的局部对比度增强
  2720. /// 网上有opencv自适应局部对比度增强算法,回头看情况换不换
  2721. /// </summary>
  2722. /// <param name="src"></param>
  2723. /// <returns></returns>
  2724. public static Mat PortrayFunction(Mat src, List<Args> lists)
  2725. {
  2726. ImageMagick.MagickImage image = null;
  2727. try
  2728. {
  2729. image = new ImageMagick.MagickImage(OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src));
  2730. //参数读取
  2731. ImageMagick.Percentage hue = new ImageMagick.Percentage(0);
  2732. double radius = 49;
  2733. for (int i = 0; i < lists.Count; i++)
  2734. {
  2735. Args args = lists[i];
  2736. switch (args.Key)
  2737. {
  2738. case "Threshold":
  2739. double hueNum = 0;
  2740. if (double.TryParse(args.Value.ToString(), out hueNum))
  2741. {
  2742. hue = new ImageMagick.Percentage(hueNum);
  2743. }
  2744. break;
  2745. case "Size":
  2746. double sizeNum = 0;
  2747. if (double.TryParse(args.Value.ToString(), out sizeNum))
  2748. {
  2749. radius = sizeNum;
  2750. }
  2751. break;
  2752. default:
  2753. break;
  2754. }
  2755. }
  2756. adaptEdgeEnhancement(src, (int)/*15*/radius, (int)/*10*/hue);
  2757. phaseTemp1.CopyTo(src);
  2758. //image.LocalContrast(radius, hue);
  2759. //OpenCvSharp.Extensions.BitmapConverter.ToMat(image.ToBitmap()).CopyTo(src);
  2760. return src;
  2761. }
  2762. catch (Exception e)
  2763. {
  2764. throw e;
  2765. }
  2766. finally
  2767. {
  2768. if (image != null) image.Dispose();
  2769. if (phaseTemp1 != null && !phaseTemp1.IsDisposed) phaseTemp1.Dispose();
  2770. if (calMats != null && !calMats.IsDisposed) calMats.Dispose();
  2771. if (phaseTempMin != null && !phaseTempMin.IsDisposed) phaseTempMin.Dispose();
  2772. if (phaseTempMax != null && !phaseTempMax.IsDisposed) phaseTempMax.Dispose();
  2773. if (localMeansMatrix != null && !localMeansMatrix.IsDisposed) localMeansMatrix.Dispose();
  2774. if (localVarianceMatrix != null && !localVarianceMatrix.IsDisposed) localVarianceMatrix.Dispose();
  2775. GC.Collect();
  2776. }
  2777. }
  2778. /// <summary>
  2779. /// 加强轮廓
  2780. /// </summary>
  2781. /// <param name="src"></param>
  2782. /// <returns></returns>
  2783. public static Mat EnhanceContourFunction(Mat src, List<Args> lists)
  2784. {
  2785. Mat mat1 = null;
  2786. Mat dst = null;
  2787. Mat cc = null;
  2788. try
  2789. {
  2790. int strength = 1;
  2791. if (lists != null)
  2792. {
  2793. for (int i = 0; i < lists.Count; i++)
  2794. {
  2795. Args args = lists[i];
  2796. switch (args.Key)
  2797. {
  2798. case "Strength":
  2799. strength = int.Parse(args.Value.ToString());
  2800. break;
  2801. default:
  2802. break;
  2803. }
  2804. }
  2805. }
  2806. else
  2807. {
  2808. strength = 10;
  2809. }
  2810. mat1 = new Mat();
  2811. src.ConvertTo(mat1, MatType.CV_32F);
  2812. dst = new Mat();
  2813. Cv2.Laplacian(src, dst, MatType.CV_32F, 1);
  2814. for (int i = 0; i < dst.Height; i++)
  2815. {
  2816. for (int j = 0; j < dst.Width; j++)
  2817. {
  2818. byte value = dst.At<byte>(i, j);
  2819. if (value > 255) value = 255;
  2820. if (value < 0) value = 0;
  2821. dst.Set<byte>(i, j, value);
  2822. }
  2823. }
  2824. cc = mat1 - dst * strength;
  2825. cc.ConvertTo(cc, MatType.CV_8UC3);
  2826. cc.CopyTo(src);
  2827. return src;
  2828. }
  2829. catch (Exception ex)
  2830. {
  2831. throw ex;
  2832. }
  2833. finally
  2834. {
  2835. if (mat1 != null) mat1.Dispose();
  2836. if (dst != null) dst.Dispose();
  2837. if (cc != null) cc.Dispose();
  2838. }
  2839. }
  2840. /// <summary>
  2841. /// 虚化蒙版
  2842. /// 是从下面的第三方库中的代码翻译过来的
  2843. /// 库名:kaliko的图像处理库
  2844. /// 源码:引入的第三方库\NetImageLibrary-master
  2845. /// </summary>
  2846. /// <param name="src"></param>
  2847. /// <returns></returns>
  2848. public static Mat BlurMaskFunction(Mat src, List<Args> lists)
  2849. {
  2850. Bitmap map = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(src);
  2851. float radius = 3f;
  2852. int threshold = 0;
  2853. float amount = 3f;
  2854. for (int i = 0; i < lists.Count; i++)
  2855. {
  2856. Args args = lists[i];
  2857. switch (args.Key)
  2858. {
  2859. case "Radius":
  2860. radius = float.Parse(args.Value.ToString()) * 3.14f;
  2861. break;
  2862. case "Amount":
  2863. amount = float.Parse(args.Value.ToString());
  2864. break;
  2865. case "Threshold":
  2866. threshold = int.Parse(args.Value.ToString());
  2867. break;
  2868. default:
  2869. break;
  2870. }
  2871. }
  2872. //像素矩阵
  2873. var inPixels = BaseTools.ByteArray(map);
  2874. var workPixels = new int[inPixels.Length];
  2875. var outPixels = new int[inPixels.Length];
  2876. //半径
  2877. if (radius > 0)
  2878. {
  2879. Kernel kernel = BaseTools.CreateKernel(radius);
  2880. BaseTools.ConvolveAndTranspose(kernel, inPixels, workPixels, map.Width, map.Height, true, true, false, 1);
  2881. BaseTools.ConvolveAndTranspose(kernel, workPixels, outPixels, map.Height, map.Width, true, false, true, 1);
  2882. }
  2883. for (int index = 0; index < inPixels.Length; index++)
  2884. {
  2885. int rgb1 = inPixels[index];
  2886. int r1 = (rgb1 >> 16) & 0xff;
  2887. int g1 = (rgb1 >> 8) & 0xff;
  2888. int b1 = rgb1 & 0xff;
  2889. int rgb2 = outPixels[index];
  2890. int r2 = (rgb2 >> 16) & 0xff;
  2891. int g2 = (rgb2 >> 8) & 0xff;
  2892. int b2 = rgb2 & 0xff;
  2893. if (Math.Abs(r1 - r2) >= threshold)
  2894. {
  2895. r1 = (int)((amount + 1) * (r1 - r2) + r2);
  2896. if (r1 < 0) r1 = 0;
  2897. if (r1 > 255) r1 = 255;
  2898. }
  2899. if (Math.Abs(g1 - g2) >= threshold)
  2900. {
  2901. g1 = (int)((amount + 1) * (g1 - g2) + g2);
  2902. if (g1 < 0) g1 = 0;
  2903. if (g1 > 255) g1 = 255;
  2904. }
  2905. if (Math.Abs(b1 - b2) >= threshold)
  2906. {
  2907. b1 = (int)((amount + 1) * (b1 - b2) + b2);
  2908. if (b1 < 0) b1 = 0;
  2909. if (b1 > 255) b1 = 255;
  2910. }
  2911. inPixels[index] = (int)(rgb1 & 0xff000000) | (r1 << 16) | (g1 << 8) | b1;
  2912. }
  2913. var byteArray = new byte[inPixels.Length * 4];
  2914. for (int i = 0; i < inPixels.Length; i++)
  2915. {
  2916. Array.Copy(BitConverter.GetBytes(inPixels[i]), 0, byteArray, i * 4, 4);
  2917. }
  2918. Bitmap Image = new Bitmap(map.Width, map.Height, PixelFormat.Format32bppArgb);
  2919. var data = ((Bitmap)Image).LockBits(new Rectangle(0, 0, Image.Width, Image.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
  2920. if (data.Stride == Image.Width * 4)
  2921. {
  2922. Marshal.Copy(byteArray, 0, data.Scan0, byteArray.Length);
  2923. }
  2924. else
  2925. {
  2926. for (int i = 0, l = Image.Height; i < l; i++)
  2927. {
  2928. var p = new IntPtr(data.Scan0.ToInt32() + data.Stride * i);
  2929. Marshal.Copy(byteArray, i * Image.Width * 4, p, Image.Width * 4);
  2930. }
  2931. }
  2932. ((Bitmap)Image).UnlockBits(data);
  2933. return OpenCvSharp.Extensions.BitmapConverter.ToMat((Bitmap)Image);
  2934. }
  2935. /// <summary>
  2936. /// 实时图像拼接
  2937. /// </summary>
  2938. /// <param name="src"></param>
  2939. /// <returns></returns>
  2940. public static Mat RealTimeStitchingFunction(Mat src, List<Args> lists)
  2941. {
  2942. Mat dst = new Mat();
  2943. Mat mat1 = new Mat();
  2944. try
  2945. {
  2946. for (int i = 0; i < lists.Count; i++)
  2947. {
  2948. Args args = lists[i];
  2949. switch (args.Key)
  2950. {
  2951. case "Src2":
  2952. mat1 = (Mat)args.Value;
  2953. break;
  2954. default:
  2955. break;
  2956. }
  2957. }
  2958. Boolean errorFlag = false;
  2959. dst = MatchPicByXFeatures2D(new Mat[] { src, mat1 }, out errorFlag);
  2960. //dst = MatchPicBySift(src, mat1);
  2961. if (errorFlag)
  2962. {
  2963. MessageBox.Show("Picture splicing failed");
  2964. }
  2965. }
  2966. catch (Exception e)
  2967. {
  2968. Console.WriteLine(e.ToString());
  2969. src.CopyTo(dst);
  2970. }
  2971. finally
  2972. {
  2973. if (src != null) dst.CopyTo(src);
  2974. if (dst != null) dst.Dispose();
  2975. }
  2976. return src;
  2977. }
  2978. /// <summary>
  2979. /// 图像拼接方法,返回拼接好的mat
  2980. /// </summary>
  2981. /// <param name="matSrcs">需要拼接的mat集合</param>
  2982. /// <param name="errorFlag">返回true表示拼接失败</param>
  2983. /// <returns></returns>
  2984. public static Mat MatchPicByXFeatures2D(Mat[] matSrcs, out Boolean errorFlag)
  2985. {
  2986. Mat mat = matSrcs[0].Clone();// (~(matSrcs[0].Clone().CvtColor(ColorConversionCodes.BGRA2BGR))).ToMat().CvtColor(ColorConversionCodes.BGR2BGRA);//
  2987. errorFlag = false;//C:\Users\win10SSD\Desktop\工作目录\显微镜\图像拼接\Images0223\Images
  2988. int totalMat = matSrcs.Length;
  2989. int totalLen = matSrcs.Length;
  2990. if (totalMat < 2)
  2991. {
  2992. return mat;
  2993. }
  2994. totalMat -= 1;
  2995. int index = totalLen;
  2996. List<int> failureIndex = new List<int>();
  2997. List<int> finishIndex = new List<int>();
  2998. do
  2999. {
  3000. index = Math.Max(1, (index + 1) % totalLen);
  3001. if (finishIndex.Contains(index)) continue; //跳过拼接完成的图片
  3002. try
  3003. {
  3004. Mat mat1 = matSrcs[index];// (~(matSrcs[index].Clone().CvtColor(ColorConversionCodes.BGRA2BGR))).ToMat().CvtColor(ColorConversionCodes.BGR2BGRA);//
  3005. KeyPoint[] keyPointsSrc = new KeyPoint[0];
  3006. Mat matSrcRet = null;
  3007. KeyPoint[] keyPointsTo = new KeyPoint[0];
  3008. Mat matToRet = null;
  3009. int matCount = Math.Min(mat.Width * mat.Height, mat1.Width * mat1.Height);
  3010. int orbCount = matCount / 40000;
  3011. do
  3012. {
  3013. orbCount *= 10;
  3014. Mat resMat = MatchPicBySift(mat, mat1, out errorFlag, ref keyPointsSrc, ref matSrcRet,
  3015. ref keyPointsTo, ref matToRet, orbCount);
  3016. if (!errorFlag)
  3017. {
  3018. mat = resMat.Clone();
  3019. resMat.Dispose();
  3020. }
  3021. } while (orbCount <= matCount && errorFlag);
  3022. //mat = MatchPicBySift(mat, mat1);
  3023. if (errorFlag)
  3024. {
  3025. if (failureIndex.Contains(index)) break; //剩下一些无法拼接的图片后退出循环,避免程序卡死
  3026. failureIndex.Add(index);
  3027. }
  3028. }
  3029. catch (Exception)
  3030. {
  3031. errorFlag = true;
  3032. if (failureIndex.Contains(index)) break; //剩下一些无法拼接的图片后退出循环,避免程序卡死
  3033. failureIndex.Add(index);
  3034. }
  3035. finally
  3036. {
  3037. if (!failureIndex.Contains(index))
  3038. {
  3039. finishIndex.Add(index);
  3040. failureIndex.Clear();
  3041. }
  3042. GC.Collect();
  3043. }
  3044. } while (finishIndex.Count() < totalMat);
  3045. return mat;
  3046. }
  3047. public static Mat MosaicsMat = null;
  3048. public static System.Drawing.Point MosaicsMoveP;
  3049. /// <summary>
  3050. /// 图像拼接方法,返回拼接好的mat
  3051. /// </summary>
  3052. /// <param name="matSrcs">需要拼接的mat集合</param>
  3053. /// <param name="colNum">列数</param>
  3054. /// <param name="percent">拼接率</param>
  3055. /// <param name="errorFlag">返回true表示拼接失败</param>
  3056. /// <returns></returns>
  3057. public static Mat MatchPicOneByOne2D(Mat[] matSrcs, int colNum, double percent, out Boolean errorFlag, bool usePercent = true)
  3058. {
  3059. if (MosaicsMat != null)
  3060. MosaicsMat.Dispose();
  3061. MosaicsMat = new Mat();
  3062. MosaicsMoveP = new System.Drawing.Point(0, 0);
  3063. //Mat mat = matSrcs[0].Clone();// (~(matSrcs[0].Clone().CvtColor(ColorConversionCodes.BGRA2BGR))).ToMat().CvtColor(ColorConversionCodes.BGR2BGRA);//
  3064. errorFlag = false;//C:\Users\win10SSD\Desktop\工作目录\显微镜\图像拼接\Images0223\Images
  3065. int totalMat = matSrcs.Length;
  3066. int totalLen = matSrcs.Length;
  3067. if (totalMat < 2)
  3068. {
  3069. return matSrcs[0].Clone();// mat;
  3070. }
  3071. totalMat -= 1;
  3072. int moveindex = totalLen;
  3073. List<System.Drawing.Point> movePoints = new List<System.Drawing.Point>();
  3074. List<int> successIndex = new List<int>();
  3075. List<int> failureIndex = new List<int>();
  3076. List<int> finishIndex = new List<int>();
  3077. int rowIndex = 0;//行数 Y方向
  3078. int colIndex = 0;//列数 X方向
  3079. //从1到3分别是右、下、左
  3080. int directionRect = 1;
  3081. do
  3082. {
  3083. //int index = totalLen;
  3084. moveindex = Math.Max(1, (moveindex + 1) % totalLen);
  3085. rowIndex = (int)(moveindex * 1.0 / colNum);// + ((moveindex + 1) % colNum > 0 ? 1 : 0);
  3086. colIndex = moveindex % colNum;
  3087. if (finishIndex.Contains(moveindex)) continue; //跳过拼接完成的图片
  3088. try
  3089. {
  3090. int index = moveindex;
  3091. int lastindex = index - 1;
  3092. directionRect = 1;
  3093. if (rowIndex % 2 == 1)
  3094. {
  3095. index = colNum * (rowIndex + 1) - colIndex - 1;
  3096. if (colIndex == 0)
  3097. {
  3098. lastindex = index - colNum;
  3099. directionRect = 2;
  3100. }
  3101. else
  3102. {
  3103. lastindex = index + 1;
  3104. directionRect = 3;
  3105. }
  3106. }
  3107. else if (colIndex == 0)
  3108. {
  3109. lastindex = index - colNum;
  3110. directionRect = 2;
  3111. }
  3112. Mat mat1 = matSrcs[index];// (~(matSrcs[index].Clone().CvtColor(ColorConversionCodes.BGRA2BGR))).ToMat().CvtColor(ColorConversionCodes.BGR2BGRA);//
  3113. int matCount = Math.Min(matSrcs[lastindex]/*mat*/.Width * matSrcs[lastindex]/*mat*/.Height, mat1.Width * mat1.Height);
  3114. int orbCount = matCount / 40000;
  3115. do
  3116. {
  3117. orbCount *= 10;
  3118. System.Drawing.Point moveP = MatchOneBySift(matSrcs[lastindex]/*mat*/, mat1, out errorFlag, orbCount, percent, directionRect, usePercent);
  3119. movePoints.Add(moveP);
  3120. errorFlag = false;
  3121. MosaicsMoveP.X += moveP.X;
  3122. MosaicsMoveP.Y += moveP.Y;
  3123. successIndex.Add(index);
  3124. } while (orbCount <= matCount && errorFlag);
  3125. if (errorFlag)
  3126. {
  3127. if (failureIndex.Contains(moveindex)) break; //剩下一些无法拼接的图片后退出循环,避免程序卡死
  3128. failureIndex.Add(moveindex);
  3129. }
  3130. }
  3131. catch (Exception)
  3132. {
  3133. errorFlag = true;
  3134. if (failureIndex.Contains(moveindex)) break; //剩下一些无法拼接的图片后退出循环,避免程序卡死
  3135. failureIndex.Add(moveindex);
  3136. }
  3137. finally
  3138. {
  3139. if (!failureIndex.Contains(moveindex))
  3140. {
  3141. finishIndex.Add(moveindex);
  3142. failureIndex.Clear();
  3143. }
  3144. GC.Collect();
  3145. }
  3146. } while (finishIndex.Count() < totalMat);
  3147. if (errorFlag)
  3148. {
  3149. return matSrcs[0].Clone();// mat;
  3150. }
  3151. System.Drawing.Point mat0Point;
  3152. OpenCvSharp.Size outMatSize = GetNewSize(movePoints, matSrcs, successIndex, colNum, out mat0Point);
  3153. Mat outMat = new Mat(outMatSize, MatType.CV_8UC4);
  3154. var matSrc = matSrcs[0];
  3155. Mat posSrc = new Mat(outMat, new Rect(mat0Point.X, mat0Point.Y, matSrc.Width, matSrc.Height));
  3156. //Rect roi_rect = new Rect(mat0Point.X, mat0Point.Y, matSrc.Width, matSrc.Height);
  3157. matSrc.CopyTo(posSrc/*outMat.AdjustROI(mat0Point.X, mat0Point.Y, matSrc.Width, matSrc.Height)*/);
  3158. //Mat maskSrc = new Mat(outMatSize, MatType.CV_8UC1, Scalar.All(0));
  3159. //for (int i = 0; i < matSrc.Width; i++)
  3160. //{
  3161. // for (int j = 0; j < matSrc.Height; j++)
  3162. // {
  3163. // maskSrc.Set<Byte>(j, i, 1);
  3164. // }
  3165. //}
  3166. //matSrc.CopyTo(outMat, maskSrc/*, maskSrc*//*.CvtColor(ColorConversionCodes.BGRA2GRAY)*/);//原图像复制到新图像
  3167. System.Drawing.Point movePoint = new System.Drawing.Point(mat0Point.X, mat0Point.Y);
  3168. for (int indexP = 0; indexP < movePoints.Count; indexP++)
  3169. {
  3170. int aver_X = movePoints[indexP].X;
  3171. int aver_Y = movePoints[indexP].Y;
  3172. movePoint.X += (int)aver_X;
  3173. if (successIndex[indexP] % (colNum * 2) == 0)
  3174. {
  3175. movePoint.X = (int)aver_X;
  3176. }
  3177. movePoint.Y += (int)aver_Y;
  3178. aver_X = movePoint.X;
  3179. aver_Y = movePoint.Y;
  3180. int newOriX = 0;
  3181. int newOriY = 0;
  3182. var matTo = matSrcs[successIndex[indexP]];
  3183. //得到变换矩阵后拼接图像
  3184. if (aver_X > 0)
  3185. newOriX = (int)aver_X;
  3186. if (aver_Y > 0)
  3187. newOriY = (int)aver_Y;
  3188. if (newOriX + matTo.Width > outMat.Width || newOriY + matTo.Height > outMat.Height)
  3189. {
  3190. errorFlag = true;
  3191. return matSrcs[0].Clone();// mat;
  3192. }
  3193. Mat pos = new Mat(outMat, new Rect(newOriX, newOriY, matTo.Width, matTo.Height));
  3194. OptimizeSeam(pos, matTo);
  3195. matTo.CopyTo(pos/*, mask*//*.CvtColor(ColorConversionCodes.BGRA2GRAY)*/);//原图像复制到新图像
  3196. //pos.Dispose();
  3197. GC.Collect();
  3198. }
  3199. return outMat;
  3200. }
  3201. public unsafe static void OptimizeSeam(Mat matBig, Mat matNew)
  3202. {
  3203. //判断上边沿宽度
  3204. int i, j;
  3205. Mat mat;
  3206. Mat mean = new Mat();
  3207. Mat std = new Mat();
  3208. for (i = 0; i < 100; i++)
  3209. {
  3210. mat = new Mat(matBig, new Rect(100, i, matBig.Width - 200, 1));
  3211. mat.MeanStdDev(mean, std);
  3212. if (std.At<double>(0) == 0)
  3213. break;
  3214. }
  3215. if (i > 0)
  3216. {
  3217. OptimizeSeamTop(matNew, matBig, i);
  3218. }
  3219. //判断右边沿宽度
  3220. for (j = 0; j < 100; j++)
  3221. {
  3222. mat = new Mat(matBig, new Rect(j, 100, 1, matBig.Height - 200));
  3223. mat.MeanStdDev(mean, std);
  3224. if (std.At<double>(0) == 0)
  3225. break;
  3226. }
  3227. if (j > 0)
  3228. {
  3229. OptimizeSeamLeft(matNew, matBig, j);
  3230. }
  3231. //判断左边沿宽度
  3232. for (j = 0; j < 100; j++)
  3233. {
  3234. mat = new Mat(matBig, new Rect(matBig.Width - j - 1, 100, 1, matBig.Height - 200));
  3235. mat.MeanStdDev(mean, std);
  3236. if (std.At<double>(0) == 0)
  3237. break;
  3238. }
  3239. if (j > 0)
  3240. {
  3241. OptimizeSeamRight(matNew, matBig, j);
  3242. }
  3243. for (i = 0; i < 100; i++)
  3244. {
  3245. mat = new Mat(matBig, new Rect(100, matBig.Height - i - 1, matBig.Width - 200, 1));
  3246. mat.MeanStdDev(mean, std);
  3247. if (std.At<double>(0) == 0)
  3248. break;
  3249. }
  3250. if (i > 0)
  3251. {
  3252. OptimizeSeamBottom(matNew, matBig, i);
  3253. }
  3254. }
  3255. public unsafe static void OptimizeSeamLeft(Mat m1, Mat m2, int thickness)
  3256. {
  3257. int ch = m1.Channels();
  3258. for (int i = 0; i < m2.Height; i++)
  3259. {
  3260. var p1 = (byte*)m1.Ptr(i);
  3261. var p2 = (byte*)m2.Ptr(i);
  3262. for (int j = 0; j < thickness; j++)
  3263. {
  3264. double a = (j + 1.0) / (thickness + 1.0);
  3265. int j1 = j * ch;
  3266. if ((p2[j1] + p2[j1 + 1] + p2[j1 + 2]) == 0)
  3267. continue;
  3268. p1[j1] = (byte)(p1[j1] * a + p2[j1] * (1 - a));
  3269. p1[j1 + 1] = (byte)(p1[j1 + 1] * a + p2[j1 + 1] * (1 - a));
  3270. p1[j1 + 2] = (byte)(p1[j1 + 2] * a + p2[j1 + 2] * (1 - a));
  3271. }
  3272. }
  3273. }
  3274. public unsafe static void OptimizeSeamRight(Mat m1, Mat m2, int thickness)
  3275. {
  3276. int ch = m1.Channels();
  3277. for (int i = 0; i < m1.Height; i++)
  3278. {
  3279. var p1 = (byte*)m1.Ptr(i);
  3280. var p2 = (byte*)m2.Ptr(i);
  3281. for (int j = 1; j < thickness + 1; j++)
  3282. {
  3283. double a = j / (thickness + 1.0);
  3284. var j1 = (m2.Width - j) * ch;
  3285. if ((p2[j1] + p2[j1 + 1] + p2[j1 + 2]) == 0)
  3286. continue;
  3287. p1[j1] = (byte)(p1[j1] * a + p2[j1] * (1 - a));
  3288. p1[j1 + 1] = (byte)(p1[j1 + 1] * a + p2[j1 + 1] * (1 - a));
  3289. p1[j1 + 2] = (byte)(p1[j1 + 2] * a + p2[j1 + 2] * (1 - a));
  3290. }
  3291. }
  3292. }
  3293. public unsafe static void OptimizeSeamTop(Mat m1, Mat m2, int thickness)
  3294. {
  3295. int ch = m1.Channels();
  3296. for (int i = 0; i < thickness; i++)
  3297. {
  3298. var p1 = (byte*)m1.Ptr(i);
  3299. var p2 = (byte*)m2.Ptr(i);
  3300. double a = (i + 1.0) / (thickness + 1.0);
  3301. for (int j = 0; j < m1.Width; j++)
  3302. {
  3303. int j1 = j * ch;
  3304. int j2 = j * ch;
  3305. if ((p2[j1] + p2[j1 + 1] + p2[j1 + 2]) == 0)
  3306. continue;
  3307. p1[j1] = (byte)(p1[j1] * a + p2[j2] * (1 - a));
  3308. p1[j1 + 1] = (byte)(p1[j1 + 1] * a + p2[j2 + 1] * (1 - a));
  3309. p1[j1 + 2] = (byte)(p1[j1 + 2] * a + p2[j2 + 2] * (1 - a));
  3310. }
  3311. }
  3312. }
  3313. public unsafe static void OptimizeSeamBottom(Mat m1, Mat m2, int thickness)
  3314. {
  3315. int ch = m1.Channels();
  3316. for (int i = 0; i < thickness; i++)
  3317. {
  3318. var p1 = (byte*)m1.Ptr(m1.Height - i - 1);
  3319. var p2 = (byte*)m2.Ptr(m2.Height - i - 1);
  3320. double a = (i + 1.0) / (thickness + 1.0);
  3321. for (int j = 0; j < m1.Width; j++)
  3322. {
  3323. int j1 = j * ch;
  3324. int j2 = j * ch;
  3325. if ((p2[j1] + p2[j1 + 1] + p2[j1 + 2]) == 0)
  3326. continue;
  3327. p1[j1] = (byte)(p1[j1] * a + p2[j2] * (1 - a));
  3328. p1[j1 + 1] = (byte)(p1[j1 + 1] * a + p2[j2 + 1] * (1 - a));
  3329. p1[j1 + 2] = (byte)(p1[j1 + 2] * a + p2[j2 + 2] * (1 - a));
  3330. }
  3331. }
  3332. }
  3333. public static OpenCvSharp.Size GetNewSize(List<System.Drawing.Point> movePoints, Mat[] matSrcs, List<int> successIndex, int colNum, out System.Drawing.Point mat0Point)
  3334. {
  3335. mat0Point = new System.Drawing.Point(0, 0);
  3336. OpenCvSharp.Size newSize = new OpenCvSharp.Size(matSrcs[0].Width, matSrcs[0].Height);
  3337. System.Drawing.Point movePoint = new System.Drawing.Point(0, 0);
  3338. for (int indexP = 0; indexP < movePoints.Count; indexP++)
  3339. {
  3340. int aver_X = movePoints[indexP].X;
  3341. int aver_Y = movePoints[indexP].Y;
  3342. movePoint.X += (int)aver_X;
  3343. if (successIndex[indexP] % (colNum * 2) == 0)
  3344. {
  3345. movePoint.X = (int)aver_X;
  3346. }
  3347. movePoint.Y += (int)aver_Y;
  3348. aver_X = movePoint.X;
  3349. aver_Y = movePoint.Y;
  3350. var matTo = matSrcs[successIndex[indexP]];
  3351. //得到变换矩阵后拼接图像
  3352. int newWidth = newSize.Width;
  3353. int newHeight = newSize.Height;
  3354. if (aver_X <= 0)
  3355. {
  3356. newWidth = (int)(newWidth - aver_X);
  3357. mat0Point.X += (int)(-aver_X);
  3358. }
  3359. else
  3360. {
  3361. if (matTo.Width + aver_X > newWidth)
  3362. newWidth = (int)(matTo.Width + aver_X);
  3363. }
  3364. if (aver_Y <= 0)
  3365. {
  3366. newHeight = (int)(newHeight - aver_Y);
  3367. mat0Point.Y += (int)(-aver_Y);
  3368. }
  3369. else
  3370. {
  3371. if (matTo.Height + aver_Y > newHeight)
  3372. newHeight = (int)(matTo.Height + aver_Y);
  3373. }
  3374. newSize = new OpenCvSharp.Size(newWidth, newHeight);
  3375. }
  3376. return newSize;
  3377. }
  3378. /// <summary>
  3379. /// 图像拼接方法,返回拼接好的mat
  3380. /// </summary>
  3381. /// <param name="matSrc">需要拼接的mat1</param>
  3382. /// <param name="matTo">需要拼接的mat2</param>
  3383. /// <param name="errorFlag">返回true表示拼接失败</param>
  3384. /// <returns></returns>
  3385. public static Mat MatchPicBySift(Mat matSrc, Mat matTo, out Boolean errorFlag)
  3386. {
  3387. errorFlag = false;
  3388. Mat mat = matSrc.Clone();
  3389. try
  3390. {
  3391. mat = MatchPicBySift(matSrc, matTo);
  3392. }
  3393. catch (Exception)
  3394. {
  3395. errorFlag = true;
  3396. }
  3397. return mat;
  3398. }
  3399. /// <summary>
  3400. /// 图像拼接方法,返回拼接好的mat
  3401. /// </summary>
  3402. /// <param name="matSrc">需要拼接的mat1</param>
  3403. /// <param name="matTo">需要拼接的mat2</param>
  3404. /// <returns></returns>
  3405. public static Mat MatchPicBySift(Mat matSrc, Mat matTo)
  3406. {
  3407. using (Mat matSrcRet = new Mat())
  3408. using (Mat matToRet = new Mat())
  3409. {
  3410. KeyPoint[] keyPointsSrc, keyPointsTo;
  3411. //using (var surf = OpenCvSharp.XFeatures2D.SURF.Create(800/*2000*/))
  3412. using (var surf = OpenCvSharp.ORB.Create(800))
  3413. //using (var sift = OpenCvSharp.XFeatures2D.SIFT.Create(2000))//var sift = OpenCvSharp.XFeatures2D.SIFT.Create()
  3414. {
  3415. surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
  3416. surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
  3417. }
  3418. using (var bfMatcher = new OpenCvSharp.BFMatcher())//FlannBasedMatcher
  3419. {
  3420. var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
  3421. var pointsSrc = new List<Point2f>();
  3422. var pointsDst = new List<Point2f>();
  3423. var goodMatches = new List<DMatch>();
  3424. //数组按照元素个数由多到少排序
  3425. var arrXMatches = new List<int>();
  3426. var arrYMatches = new List<int>();
  3427. float XCompute = 0; float YCompute = 0; int coutPt = 0;
  3428. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  3429. {
  3430. if (items[0].Distance < 0.5 * items[1].Distance)
  3431. {
  3432. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  3433. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  3434. arrXMatches.Add((int)X_dis);
  3435. arrYMatches.Add((int)Y_dis);
  3436. }
  3437. }
  3438. int[] arrX = arrXMatches.ToArray();
  3439. int[] arrY = arrYMatches.ToArray();
  3440. Array.Sort(arrX);
  3441. Array.Sort(arrY);
  3442. int valX1 = arrX[0];//当前
  3443. int valX2 = 0;//上一个
  3444. int timeX1 = 1;//当前
  3445. int timeX2 = 0;//上一个
  3446. for (int sortI = 1; sortI < arrX.Length; sortI++)
  3447. {
  3448. if (arrX[sortI] == valX1)
  3449. {
  3450. timeX1++;
  3451. }
  3452. else
  3453. {
  3454. if (timeX1 > timeX2)
  3455. {
  3456. valX2 = valX1;
  3457. timeX2 = timeX1;
  3458. }
  3459. valX1 = arrX[sortI];
  3460. timeX1 = 1;
  3461. }
  3462. }
  3463. if (timeX1 > timeX2)
  3464. {
  3465. valX2 = valX1;
  3466. timeX2 = timeX1;
  3467. }
  3468. int valY1 = arrY[0];//当前
  3469. int valY2 = 0;//上一个
  3470. int timeY1 = 1;//当前
  3471. int timeY2 = 0;//上一个
  3472. for (int sortI = 1; sortI < arrY.Length; sortI++)
  3473. {
  3474. if (arrY[sortI] == valY1)
  3475. {
  3476. timeY1++;
  3477. }
  3478. else
  3479. {
  3480. if (timeY1 > timeY2)
  3481. {
  3482. valY2 = valY1;
  3483. timeY2 = timeY1;
  3484. }
  3485. valY1 = arrY[sortI];
  3486. timeY1 = 1;
  3487. }
  3488. }
  3489. if (timeY1 > timeY2)
  3490. {
  3491. valY2 = valY1;
  3492. timeY2 = timeY1;
  3493. }
  3494. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  3495. {
  3496. if (items[0].Distance < 0.5 * items[1].Distance)
  3497. {
  3498. //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  3499. //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  3500. //goodMatches.Add(items[0]);
  3501. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  3502. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  3503. if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))
  3504. {
  3505. Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);
  3506. pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  3507. pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  3508. goodMatches.Add(items[0]);
  3509. //arrXMatches.Add((int)X_dis);
  3510. ////arrYMatches.Add((int)Y_dis);
  3511. coutPt++;
  3512. XCompute += X_dis; YCompute += Y_dis;
  3513. }
  3514. else
  3515. {
  3516. Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);
  3517. }
  3518. }
  3519. }
  3520. float aver_X = XCompute / coutPt;// 600;//
  3521. float aver_Y = YCompute / coutPt;// 600;//
  3522. Console.WriteLine("平均横向距离差:{0} 平均纵向距离差:{1}", aver_X, aver_Y);//计算原图像相对于新图像的(距离差)、-->变换矩阵
  3523. var outMat = new Mat();
  3524. // 算法RANSAC对匹配的结果做过滤
  3525. var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
  3526. var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
  3527. var outMask = new Mat();
  3528. var result = new Mat();
  3529. // 如果原始的匹配结果为空, 则跳过过滤步骤
  3530. if (pSrc.Count > 0 && pDst.Count > 0)
  3531. {
  3532. int srcOriX = 0;
  3533. int srcOriY = 0;
  3534. int newOriX = 0;
  3535. int newOriY = 0;
  3536. Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
  3537. //得到变换矩阵后拼接图像
  3538. int newWidth = matSrc.Width;// 2448;
  3539. int newHeight = matSrc.Height;// 2040;
  3540. if (aver_X <= 0)
  3541. {
  3542. newWidth = (int)(newWidth - aver_X);
  3543. srcOriX = (int)(-aver_X);
  3544. }
  3545. else
  3546. {
  3547. for (int i = 0; i < pDst.Count; i++)
  3548. {
  3549. pDst[i] = new Point2d(pSrc[i].X, pDst[i].Y);
  3550. }
  3551. newOriX = (int)aver_X;
  3552. if (matTo.Width + aver_X > newWidth)
  3553. newWidth = (int)(matTo.Width + aver_X);
  3554. }
  3555. if (aver_Y <= 0)
  3556. {
  3557. newHeight = (int)(newHeight - aver_Y);
  3558. srcOriY = (int)(-aver_Y);
  3559. }
  3560. else
  3561. {
  3562. for (int i = 0; i < pDst.Count; i++)
  3563. {
  3564. pDst[i] = new Point2d(pDst[i].X, pSrc[i].Y);
  3565. }
  3566. newOriY = (int)aver_Y;
  3567. if (matTo.Height + aver_Y > newHeight)
  3568. newHeight = (int)(matTo.Height + aver_Y);
  3569. }
  3570. result = new Mat(new OpenCvSharp.Size(newWidth, newHeight), matSrc.Type());
  3571. //<-- int index = 9; matSrc
  3572. Rect rectSrc = new Rect(0, 0, matSrc.Width, matSrc.Height);
  3573. Mat tempMatSrc = matSrc.Clone(rectSrc);
  3574. //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)
  3575. Mat maskSrc = tempMatSrc.CvtColor(ColorConversionCodes.RGBA2GRAY);
  3576. Mat posSrc = new Mat(result, new Rect(srcOriX, srcOriY, matSrc.Width, matSrc.Height));
  3577. tempMatSrc.CopyTo(posSrc, maskSrc);//原图像复制到新图像
  3578. Rect rect = new Rect(0, 0, matTo.Width, matTo.Height);
  3579. Mat tempMat = matTo.Clone(rect);
  3580. //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像)
  3581. Mat mask = tempMat.CvtColor(ColorConversionCodes.RGBA2GRAY);
  3582. Mat pos = new Mat(result, new Rect(newOriX, newOriY, matTo.Width, matTo.Height));
  3583. tempMat.CopyTo(pos, mask);//原图像复制到新图像
  3584. //Bitmap part2 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(result);
  3585. ////、、R3a
  3586. //part2.Save(@"ResSurfA" + indexRes + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
  3587. return result;
  3588. }
  3589. result = matSrc.Clone();
  3590. return result;
  3591. //// 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).
  3592. //if (outMask.Rows > 10)
  3593. //{
  3594. // byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];
  3595. // outMask.GetArray(0, 0, maskBytes);
  3596. // Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);
  3597. //}
  3598. //else
  3599. // Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
  3600. //return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(/*result*/outMat);
  3601. }
  3602. }
  3603. }
  3604. //大图模式
  3605. private static Mat m_merge;
  3606. private static bool isDebug = false;
  3607. public static double LastWidth;
  3608. public static double LastHeight;
  3609. public static Mat LastMat;
  3610. public static double LastX;
  3611. public static double LastY;
  3612. public static void InitMatchPicOneByOne(bool is_Debug, double lastX = 0, double lastY = 0, Mat mmerge = null)
  3613. {
  3614. isDebug = is_Debug;
  3615. LastMat = null;
  3616. LastX = lastX;
  3617. LastY = lastY;
  3618. m_merge = mmerge;
  3619. }
  3620. public static System.Drawing.Point MatchPicOneByOne(Bitmap img0, Bitmap img1, out Boolean errorFlag)
  3621. {
  3622. errorFlag = false;
  3623. try
  3624. {
  3625. return MatchPic(img0, img1);
  3626. }
  3627. catch (Exception)
  3628. {
  3629. errorFlag = true;
  3630. }
  3631. return new System.Drawing.Point(0, 0);
  3632. }
  3633. public static System.Drawing.Point MatchPic(Bitmap img0, Bitmap img1)
  3634. {
  3635. var matNew = BitmapConverter.ToMat(img0);
  3636. LastMat = BitmapConverter.ToMat(img1);
  3637. using (Mat matSrcRet = new Mat())
  3638. using (Mat matToRet = new Mat())
  3639. {
  3640. KeyPoint[] keyPointsSrc, keyPointsTo;
  3641. using (var surf = OpenCvSharp.ORB.Create(800))
  3642. {
  3643. surf.DetectAndCompute(LastMat, null, out keyPointsSrc, matSrcRet);
  3644. surf.DetectAndCompute(matNew, null, out keyPointsTo, matToRet);
  3645. LastMat = matNew;
  3646. }
  3647. using (var bfMatcher = new OpenCvSharp.BFMatcher())//FlannBasedMatcher
  3648. {
  3649. var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
  3650. var pointsSrc = new List<Point2f>();
  3651. var pointsDst = new List<Point2f>();
  3652. var goodMatches = new List<DMatch>();
  3653. //数组按照元素个数由多到少排序
  3654. var arrXMatches = new List<int>();
  3655. var arrYMatches = new List<int>();
  3656. float XCompute = 0; float YCompute = 0; int coutPt = 0;
  3657. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  3658. {
  3659. if (items[0].Distance < 0.5 * items[1].Distance)
  3660. {
  3661. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  3662. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  3663. arrXMatches.Add((int)X_dis);
  3664. arrYMatches.Add((int)Y_dis);
  3665. }
  3666. }
  3667. int[] arrX = arrXMatches.ToArray();
  3668. int[] arrY = arrYMatches.ToArray();
  3669. Array.Sort(arrX);
  3670. Array.Sort(arrY);
  3671. int valX1 = arrX[0];//当前
  3672. int valX2 = 0;//上一个
  3673. int timeX1 = 1;//当前
  3674. int timeX2 = 0;//上一个
  3675. for (int sortI = 1; sortI < arrX.Length; sortI++)
  3676. {
  3677. if (arrX[sortI] == valX1)
  3678. {
  3679. timeX1++;
  3680. }
  3681. else
  3682. {
  3683. if (timeX1 > timeX2)
  3684. {
  3685. valX2 = valX1;
  3686. timeX2 = timeX1;
  3687. }
  3688. valX1 = arrX[sortI];
  3689. timeX1 = 1;
  3690. }
  3691. }
  3692. if (timeX1 > timeX2)
  3693. {
  3694. valX2 = valX1;
  3695. timeX2 = timeX1;
  3696. }
  3697. int valY1 = arrY[0];//当前
  3698. int valY2 = 0;//上一个
  3699. int timeY1 = 1;//当前
  3700. int timeY2 = 0;//上一个
  3701. for (int sortI = 1; sortI < arrY.Length; sortI++)
  3702. {
  3703. if (arrY[sortI] == valY1)
  3704. {
  3705. timeY1++;
  3706. }
  3707. else
  3708. {
  3709. if (timeY1 > timeY2)
  3710. {
  3711. valY2 = valY1;
  3712. timeY2 = timeY1;
  3713. }
  3714. valY1 = arrY[sortI];
  3715. timeY1 = 1;
  3716. }
  3717. }
  3718. if (timeY1 > timeY2)
  3719. {
  3720. valY2 = valY1;
  3721. timeY2 = timeY1;
  3722. }
  3723. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  3724. {
  3725. if (items[0].Distance < 0.5 * items[1].Distance)
  3726. {
  3727. //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  3728. //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  3729. //goodMatches.Add(items[0]);
  3730. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  3731. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  3732. if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))
  3733. {
  3734. Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);
  3735. pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  3736. pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  3737. goodMatches.Add(items[0]);
  3738. coutPt++;
  3739. XCompute += X_dis;
  3740. YCompute += Y_dis;
  3741. }
  3742. else
  3743. {
  3744. Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);
  3745. }
  3746. }
  3747. }
  3748. return new System.Drawing.Point((int)(XCompute / coutPt), (int)(YCompute / coutPt));
  3749. }
  3750. }
  3751. }
  3752. public static Mat MatchPicOneByOne(Mat matNew, Mat matBig)
  3753. {
  3754. if (LastMat == null)
  3755. {
  3756. LastMat = matNew;
  3757. return matNew.Clone();
  3758. }
  3759. using (Mat matSrcRet = new Mat())
  3760. using (Mat matToRet = new Mat())
  3761. {
  3762. KeyPoint[] keyPointsSrc, keyPointsTo;
  3763. //using (var surf = OpenCvSharp.XFeatures2D.SURF.Create(800/*2000*/))
  3764. using (var surf = OpenCvSharp.ORB.Create(800))
  3765. //using (var sift = OpenCvSharp.XFeatures2D.SIFT.Create(2000))//var sift = OpenCvSharp.XFeatures2D.SIFT.Create()
  3766. {
  3767. surf.DetectAndCompute(LastMat, null, out keyPointsSrc, matSrcRet);
  3768. surf.DetectAndCompute(matNew, null, out keyPointsTo, matToRet);
  3769. LastMat = matNew;
  3770. }
  3771. using (var bfMatcher = new OpenCvSharp.BFMatcher())//FlannBasedMatcher
  3772. {
  3773. var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
  3774. var pointsSrc = new List<Point2f>();
  3775. var pointsDst = new List<Point2f>();
  3776. var goodMatches = new List<DMatch>();
  3777. //数组按照元素个数由多到少排序
  3778. var arrXMatches = new List<int>();
  3779. var arrYMatches = new List<int>();
  3780. float XCompute = 0; float YCompute = 0; int coutPt = 0;
  3781. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  3782. {
  3783. if (items[0].Distance < 0.5 * items[1].Distance)
  3784. {
  3785. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  3786. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  3787. arrXMatches.Add((int)X_dis);
  3788. arrYMatches.Add((int)Y_dis);
  3789. }
  3790. }
  3791. int[] arrX = arrXMatches.ToArray();
  3792. int[] arrY = arrYMatches.ToArray();
  3793. Array.Sort(arrX);
  3794. Array.Sort(arrY);
  3795. int valX1 = arrX[0];//当前
  3796. int valX2 = 0;//上一个
  3797. int timeX1 = 1;//当前
  3798. int timeX2 = 0;//上一个
  3799. for (int sortI = 1; sortI < arrX.Length; sortI++)
  3800. {
  3801. if (arrX[sortI] == valX1)
  3802. {
  3803. timeX1++;
  3804. }
  3805. else
  3806. {
  3807. if (timeX1 > timeX2)
  3808. {
  3809. valX2 = valX1;
  3810. timeX2 = timeX1;
  3811. }
  3812. valX1 = arrX[sortI];
  3813. timeX1 = 1;
  3814. }
  3815. }
  3816. if (timeX1 > timeX2)
  3817. {
  3818. valX2 = valX1;
  3819. timeX2 = timeX1;
  3820. }
  3821. int valY1 = arrY[0];//当前
  3822. int valY2 = 0;//上一个
  3823. int timeY1 = 1;//当前
  3824. int timeY2 = 0;//上一个
  3825. for (int sortI = 1; sortI < arrY.Length; sortI++)
  3826. {
  3827. if (arrY[sortI] == valY1)
  3828. {
  3829. timeY1++;
  3830. }
  3831. else
  3832. {
  3833. if (timeY1 > timeY2)
  3834. {
  3835. valY2 = valY1;
  3836. timeY2 = timeY1;
  3837. }
  3838. valY1 = arrY[sortI];
  3839. timeY1 = 1;
  3840. }
  3841. }
  3842. if (timeY1 > timeY2)
  3843. {
  3844. valY2 = valY1;
  3845. timeY2 = timeY1;
  3846. }
  3847. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  3848. {
  3849. if (items[0].Distance < 0.5 * items[1].Distance)
  3850. {
  3851. //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  3852. //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  3853. //goodMatches.Add(items[0]);
  3854. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  3855. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  3856. if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))
  3857. {
  3858. Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);
  3859. pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  3860. pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  3861. goodMatches.Add(items[0]);
  3862. //arrXMatches.Add((int)X_dis);
  3863. ////arrYMatches.Add((int)Y_dis);
  3864. coutPt++;
  3865. XCompute += X_dis; YCompute += Y_dis;
  3866. }
  3867. else
  3868. {
  3869. Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);
  3870. }
  3871. }
  3872. }
  3873. LastX += XCompute / coutPt;
  3874. LastY += YCompute / coutPt;// 600;//
  3875. //Console.WriteLine("平均横向距离差:{0} 平均纵向距离差:{1}", currentX, currentY);//计算原图像相对于新图像的(距离差)、-->变换矩阵
  3876. var outMat = new Mat();
  3877. // 算法RANSAC对匹配的结果做过滤
  3878. var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
  3879. var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
  3880. var outMask = new Mat();
  3881. var result = new Mat();
  3882. // 如果原始的匹配结果为空, 则跳过过滤步骤
  3883. if (pSrc.Count > 0 && pDst.Count > 0)
  3884. {
  3885. int srcOriX = 0;
  3886. int srcOriY = 0;
  3887. int newOriX = 0;
  3888. int newOriY = 0;
  3889. // Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
  3890. //得到变换矩阵后拼接图像
  3891. int viewWidth = matBig.Width;// 2448;
  3892. int viewHeight = matBig.Height;// 2040;
  3893. if (LastX <= 0)
  3894. {
  3895. viewWidth = (int)(viewWidth - LastX);
  3896. srcOriX = (int)(-LastX);
  3897. newOriX = 0;
  3898. LastX = 0;
  3899. }
  3900. else
  3901. {
  3902. viewWidth = (int)Math.Max(LastX + matNew.Width, matBig.Width);
  3903. newOriX = (int)LastX;
  3904. //for (int i = 0; i < pDst.Count; i++)
  3905. //{
  3906. // pDst[i] = new Point2d(pSrc[i].X, pDst[i].Y);
  3907. //}
  3908. }
  3909. if (LastY <= 0)
  3910. {
  3911. viewHeight = (int)(viewHeight - LastY);
  3912. srcOriY = (int)(-LastY);
  3913. newOriY = 0;
  3914. LastY = 0;
  3915. }
  3916. else
  3917. {
  3918. //for (int i = 0; i < pDst.Count; i++)
  3919. //{
  3920. // pDst[i] = new Point2d(pDst[i].X, pSrc[i].Y);
  3921. //}
  3922. newOriY = (int)LastY;
  3923. viewHeight = (int)Math.Max(matBig.Height, matNew.Height + LastY);
  3924. }
  3925. result = new Mat(new OpenCvSharp.Size(viewWidth, viewHeight), matNew.Type());
  3926. //Rect rectSrc = new Rect(0, 0, matNew.Width, matNew.Height);
  3927. //Mat tempMatSrc = matNew.Clone(rectSrc);
  3928. Mat tempMatSrc = matNew.Clone();
  3929. //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)
  3930. Mat mask = tempMatSrc.CvtColor(ColorConversionCodes.RGBA2GRAY);
  3931. Mat posSrc = new Mat(result, new Rect(newOriX, newOriY, matNew.Width, matNew.Height));
  3932. tempMatSrc.CopyTo(posSrc, mask);//原图像复制到新图像
  3933. //Rect rect = new Rect(0, 0, matBig.Width, matBig.Height);
  3934. //Mat tempMat = matBig.Clone(rect);
  3935. Mat tempMat = matBig.Clone();
  3936. //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像)
  3937. mask = tempMat.CvtColor(ColorConversionCodes.RGBA2GRAY);
  3938. Mat pos = new Mat(result, new Rect(srcOriX, srcOriY, matBig.Width, matBig.Height));
  3939. tempMat.CopyTo(pos, mask);//原图像复制到新图像
  3940. //Bitmap part2 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(result);
  3941. ////、、R3a
  3942. //part2.Save(@"ResSurfA" + indexRes + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
  3943. return result;
  3944. }
  3945. result = matNew.Clone();
  3946. return result;
  3947. }
  3948. }
  3949. }
  3950. private static Mat BackupMat;
  3951. private static Rect LastRect;
  3952. public static Mat MatchPicRealtime(Mat matSrc, Mat matTo, out Boolean errorFlag, out Rect rect)
  3953. {
  3954. errorFlag = false;
  3955. Mat mat = matSrc.Clone();
  3956. try
  3957. {
  3958. BackupMat = LastMat;
  3959. mat = MatchPicRealtime(matSrc, matTo);
  3960. }
  3961. catch (Exception ex)
  3962. {
  3963. //Console.WriteLine(ex.Message);
  3964. LastMat = BackupMat;
  3965. errorFlag = true;
  3966. }
  3967. rect = LastRect;
  3968. return !isDebug ? mat : null;
  3969. }
  3970. public static Mat MatchPicRealtime(Mat matNew, Mat matBig)
  3971. {
  3972. var time = DateTime.Now;
  3973. if (LastMat == null)
  3974. {
  3975. LastMat = matNew;
  3976. if (isDebug)
  3977. {
  3978. int srcOriX = 0;
  3979. int srcOriY = 0;
  3980. int newOriX = 0;
  3981. int newOriY = 0;
  3982. //得到变换矩阵后拼接图像
  3983. int viewWidth = m_merge.Width;// 2448;
  3984. int viewHeight = m_merge.Height;// 2040;
  3985. if (LastX <= 0)
  3986. {
  3987. viewWidth = (int)(viewWidth - LastX);
  3988. srcOriX = (int)(-LastX);
  3989. newOriX = 0;
  3990. LastX = 0;
  3991. }
  3992. else
  3993. {
  3994. viewWidth = (int)Math.Max(LastX + matNew.Width, m_merge.Width);
  3995. newOriX = (int)LastX;
  3996. //for (int i = 0; i < pDst.Count; i++)
  3997. //{
  3998. // pDst[i] = new Point2d(pSrc[i].X, pDst[i].Y);
  3999. //}
  4000. }
  4001. if (LastY <= 0)
  4002. {
  4003. viewHeight = (int)(viewHeight - LastY);
  4004. srcOriY = (int)(-LastY);
  4005. newOriY = 0;
  4006. LastY = 0;
  4007. }
  4008. else
  4009. {
  4010. //for (int i = 0; i < pDst.Count; i++)
  4011. //{
  4012. // pDst[i] = new Point2d(pDst[i].X, pSrc[i].Y);
  4013. //}
  4014. newOriY = (int)LastY;
  4015. viewHeight = (int)Math.Max(m_merge.Height, matNew.Height + LastY);
  4016. }
  4017. LastWidth = viewWidth;
  4018. LastHeight = viewHeight;
  4019. //result = new Mat(new OpenCvSharp.Size(viewWidth, viewHeight), matNew.Type());
  4020. Mat tempMatSrc = matNew.Clone();
  4021. //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)
  4022. Mat mask = new Mat(tempMatSrc.Rows, tempMatSrc.Cols, MatType.CV_8UC1, new Scalar(255));// tempMatSrc.CvtColor(ColorConversionCodes.RGBA2GRAY);
  4023. Mat posSrc = new Mat(m_merge/*result*/, new Rect(newOriX, newOriY, matNew.Width, matNew.Height));
  4024. tempMatSrc.CopyTo(posSrc, mask);
  4025. LastRect = new Rect(newOriX, newOriY, matNew.Width, matNew.Height);
  4026. return null;// result;
  4027. }
  4028. else
  4029. {
  4030. LastRect = new Rect(0, 0, matNew.Width, matNew.Height);
  4031. }
  4032. return matNew.Clone();
  4033. }
  4034. using (Mat matSrcRet = new Mat())
  4035. using (Mat matToRet = new Mat())
  4036. {
  4037. KeyPoint[] keyPointsSrc, keyPointsTo;
  4038. using (var surf = OpenCvSharp.ORB.Create(800))
  4039. {
  4040. surf.DetectAndCompute(LastMat, null, out keyPointsSrc, matSrcRet);
  4041. surf.DetectAndCompute(matNew, null, out keyPointsTo, matToRet);
  4042. LastMat = matNew;
  4043. }
  4044. using (var bfMatcher = new OpenCvSharp.BFMatcher())//FlannBasedMatcher
  4045. {
  4046. var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
  4047. var pointsSrc = new List<Point2f>();
  4048. var pointsDst = new List<Point2f>();
  4049. var goodMatches = new List<DMatch>();
  4050. //数组按照元素个数由多到少排序
  4051. var arrXMatches = new List<int>();
  4052. var arrYMatches = new List<int>();
  4053. float XCompute = 0; float YCompute = 0; int coutPt = 0;
  4054. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  4055. {
  4056. if (items[0].Distance < 0.5 * items[1].Distance)
  4057. {
  4058. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  4059. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  4060. arrXMatches.Add((int)X_dis);
  4061. arrYMatches.Add((int)Y_dis);
  4062. }
  4063. }
  4064. int[] arrX = arrXMatches.ToArray();
  4065. int[] arrY = arrYMatches.ToArray();
  4066. Array.Sort(arrX);
  4067. Array.Sort(arrY);
  4068. int valX1 = arrX[0];//当前
  4069. int valX2 = 0;//上一个
  4070. int timeX1 = 1;//当前
  4071. int timeX2 = 0;//上一个
  4072. for (int sortI = 1; sortI < arrX.Length; sortI++)
  4073. {
  4074. if (arrX[sortI] == valX1)
  4075. {
  4076. timeX1++;
  4077. }
  4078. else
  4079. {
  4080. if (timeX1 > timeX2)
  4081. {
  4082. valX2 = valX1;
  4083. timeX2 = timeX1;
  4084. }
  4085. valX1 = arrX[sortI];
  4086. timeX1 = 1;
  4087. }
  4088. }
  4089. if (timeX1 > timeX2)
  4090. {
  4091. valX2 = valX1;
  4092. timeX2 = timeX1;
  4093. }
  4094. int valY1 = arrY[0];//当前
  4095. int valY2 = 0;//上一个
  4096. int timeY1 = 1;//当前
  4097. int timeY2 = 0;//上一个
  4098. for (int sortI = 1; sortI < arrY.Length; sortI++)
  4099. {
  4100. if (arrY[sortI] == valY1)
  4101. {
  4102. timeY1++;
  4103. }
  4104. else
  4105. {
  4106. if (timeY1 > timeY2)
  4107. {
  4108. valY2 = valY1;
  4109. timeY2 = timeY1;
  4110. }
  4111. valY1 = arrY[sortI];
  4112. timeY1 = 1;
  4113. }
  4114. }
  4115. if (timeY1 > timeY2)
  4116. {
  4117. valY2 = valY1;
  4118. timeY2 = timeY1;
  4119. }
  4120. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  4121. {
  4122. if (items[0].Distance < 0.5 * items[1].Distance)
  4123. {
  4124. //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  4125. //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  4126. //goodMatches.Add(items[0]);
  4127. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  4128. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  4129. if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))
  4130. {
  4131. //Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);
  4132. pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  4133. pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  4134. goodMatches.Add(items[0]);
  4135. //arrXMatches.Add((int)X_dis);
  4136. ////arrYMatches.Add((int)Y_dis);
  4137. coutPt++;
  4138. XCompute += X_dis; YCompute += Y_dis;
  4139. }
  4140. else
  4141. {
  4142. //Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);
  4143. }
  4144. }
  4145. }
  4146. if (coutPt < 3)
  4147. {
  4148. throw new Exception("点太少");
  4149. }
  4150. var ofx = XCompute / coutPt;
  4151. var ofy = YCompute / coutPt;
  4152. if (Math.Abs(ofx) < matNew.Width / 10 && Math.Abs(ofy) < matNew.Height / 10)
  4153. throw new Exception("太近了");
  4154. LastX += XCompute / coutPt;
  4155. LastY += YCompute / coutPt;// 600;//
  4156. //Console.WriteLine("平均横向距离差:{0} 平均纵向距离差:{1}", currentX, currentY);//计算原图像相对于新图像的(距离差)、-->变换矩阵
  4157. var outMat = new Mat();
  4158. // 算法RANSAC对匹配的结果做过滤
  4159. var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
  4160. var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
  4161. var outMask = new Mat();
  4162. var result = new Mat();
  4163. // 如果原始的匹配结果为空, 则跳过过滤步骤
  4164. if (pSrc.Count > 0 && pDst.Count > 0)
  4165. {
  4166. int srcOriX = 0;
  4167. int srcOriY = 0;
  4168. int newOriX = 0;
  4169. int newOriY = 0;
  4170. // Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
  4171. //得到变换矩阵后拼接图像
  4172. int viewWidth = matBig.Width;// 2448;
  4173. int viewHeight = matBig.Height;// 2040;
  4174. if (LastX <= 0)
  4175. {
  4176. viewWidth = (int)(viewWidth - LastX);
  4177. srcOriX = (int)(-LastX);
  4178. newOriX = 0;
  4179. LastX = 0;
  4180. }
  4181. else
  4182. {
  4183. viewWidth = (int)Math.Max(LastX + matNew.Width, matBig.Width);
  4184. newOriX = (int)LastX;
  4185. //for (int i = 0; i < pDst.Count; i++)
  4186. //{
  4187. // pDst[i] = new Point2d(pSrc[i].X, pDst[i].Y);
  4188. //}
  4189. }
  4190. if (LastY <= 0)
  4191. {
  4192. viewHeight = (int)(viewHeight - LastY);
  4193. srcOriY = (int)(-LastY);
  4194. newOriY = 0;
  4195. LastY = 0;
  4196. }
  4197. else
  4198. {
  4199. //for (int i = 0; i < pDst.Count; i++)
  4200. //{
  4201. // pDst[i] = new Point2d(pDst[i].X, pSrc[i].Y);
  4202. //}
  4203. newOriY = (int)LastY;
  4204. viewHeight = (int)Math.Max(matBig.Height, matNew.Height + LastY);
  4205. }
  4206. if (!isDebug)
  4207. {
  4208. Console.WriteLine("开始创建");
  4209. result = new Mat(new OpenCvSharp.Size(viewWidth, viewHeight), matNew.Type());//非大图模式 //大图模式不需要赋值
  4210. Mat tempMat = matBig;
  4211. Mat pos = new Mat(result, new Rect(srcOriX, srcOriY, matBig.Width, matBig.Height));
  4212. tempMat.CopyTo(pos);//原图像复制到新图像
  4213. Console.WriteLine("创建完成");
  4214. }
  4215. else
  4216. result = m_merge;
  4217. //Rect rectSrc = new Rect(0, 0, matNew.Width, matNew.Height);
  4218. //Mat tempMatSrc = matNew.Clone(rectSrc);
  4219. Mat tempMatSrc = matNew.Clone();
  4220. //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)
  4221. Mat mask = new Mat(tempMatSrc.Rows, tempMatSrc.Cols, MatType.CV_8UC1, new Scalar(255));// tempMatSrc.CvtColor(ColorConversionCodes.RGBA2GRAY);
  4222. Mat posSrc = new Mat(result, new Rect(newOriX, newOriY, matNew.Width, matNew.Height));
  4223. Console.WriteLine((DateTime.Now - time).TotalMilliseconds);
  4224. time = DateTime.Now;
  4225. OptimizeSeam(posSrc, tempMatSrc);
  4226. Console.WriteLine((DateTime.Now - time).TotalMilliseconds);
  4227. time = DateTime.Now;
  4228. tempMatSrc.CopyTo(posSrc);//原图像复制到新图像
  4229. //Rect rect = new Rect(0, 0, matBig.Width, matBig.Height);
  4230. //Mat tempMat = matBig.Clone(rect);
  4231. //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像)
  4232. LastRect = new Rect(newOriX, newOriY, matNew.Width, matNew.Height);
  4233. //Bitmap part2 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(result);
  4234. ////、、R3a
  4235. //part2.Save(@"ResSurfA" + indexRes + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
  4236. return isDebug ? null : result;
  4237. }
  4238. result = isDebug ? null : matNew.Clone();
  4239. return result;
  4240. }
  4241. }
  4242. }
  4243. /// <summary>
  4244. /// 图像拼接方法,返回拼接好的mat
  4245. /// </summary>
  4246. /// <param name="matSrc">需要拼接的mat1</param>
  4247. /// <param name="matTo">需要拼接的mat2</param>
  4248. /// <param name="errorFlag">返回true表示拼接失败</param>
  4249. /// <param name="keyPointsSrc">matSrc的检测点Points</param>
  4250. /// <param name="matSrcRet">matSrc的检测点Mat</param>
  4251. /// <param name="keyPointsTo">matTo的检测点Points</param>
  4252. /// <param name="matSrcRet">matTo的检测点Mat</param>
  4253. /// <returns></returns>
  4254. public static Mat MatchPicBySift(Mat matSrc, Mat matTo, out Boolean errorFlag, ref KeyPoint[] keyPointsSrc
  4255. , ref Mat matSrcRet, ref KeyPoint[] keyPointsTo, ref Mat matToRet, int orbCount1)
  4256. {
  4257. var result = new Mat();
  4258. errorFlag = false;
  4259. try
  4260. {
  4261. using (var surf = ORB.Create(orbCount1 * 100))
  4262. {
  4263. if (keyPointsSrc == null || matSrcRet == null)
  4264. {
  4265. matSrcRet = new Mat();
  4266. surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
  4267. }
  4268. if (keyPointsTo == null || matToRet == null)
  4269. {
  4270. matToRet = new Mat();
  4271. surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
  4272. }
  4273. }
  4274. using (var bfMatcher = new BFMatcher())
  4275. {
  4276. var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
  4277. var pointsSrc = new List<Point2f>();
  4278. var pointsDst = new List<Point2f>();
  4279. var goodMatches = new List<DMatch>();
  4280. //数组按照元素个数由多到少排序
  4281. var arrXMatches = new List<int>();
  4282. var arrYMatches = new List<int>();
  4283. double scaleI = 0.9;
  4284. float XCompute = 0; float YCompute = 0; int coutPt = 0;
  4285. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  4286. {
  4287. if (items[0].Distance < scaleI * items[1].Distance)
  4288. {
  4289. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  4290. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  4291. arrXMatches.Add((int)X_dis);
  4292. arrYMatches.Add((int)Y_dis);
  4293. }
  4294. }
  4295. int[] arrX = arrXMatches.ToArray();
  4296. int[] arrY = arrYMatches.ToArray();
  4297. Array.Sort(arrX);
  4298. Array.Sort(arrY);
  4299. int valX1 = arrX[0];//当前
  4300. int valX2 = 0;//上一个
  4301. int timeX1 = 1;//当前
  4302. int timeX2 = 0;//上一个
  4303. for (int sortI = 1; sortI < arrX.Length; sortI++)
  4304. {
  4305. if (arrX[sortI] == valX1)
  4306. {
  4307. timeX1++;
  4308. }
  4309. else
  4310. {
  4311. if (timeX1 > timeX2)
  4312. {
  4313. valX2 = valX1;
  4314. timeX2 = timeX1;
  4315. }
  4316. valX1 = arrX[sortI];
  4317. timeX1 = 1;
  4318. }
  4319. }
  4320. if (timeX1 > timeX2)
  4321. {
  4322. valX2 = valX1;
  4323. timeX2 = timeX1;
  4324. }
  4325. int valY1 = arrY[0];//当前
  4326. int valY2 = 0;//上一个
  4327. int timeY1 = 1;//当前
  4328. int timeY2 = 0;//上一个
  4329. for (int sortI = 1; sortI < arrY.Length; sortI++)
  4330. {
  4331. if (arrY[sortI] == valY1)
  4332. {
  4333. timeY1++;
  4334. }
  4335. else
  4336. {
  4337. if (timeY1 > timeY2)
  4338. {
  4339. valY2 = valY1;
  4340. timeY2 = timeY1;
  4341. }
  4342. valY1 = arrY[sortI];
  4343. timeY1 = 1;
  4344. }
  4345. }
  4346. if (timeY1 > timeY2)
  4347. {
  4348. valY2 = valY1;
  4349. timeY2 = timeY1;
  4350. }
  4351. foreach (DMatch[] items in matches.Where(x => x.Length > 1))
  4352. {
  4353. if (items[0].Distance < scaleI * items[1].Distance)
  4354. {
  4355. //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  4356. //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  4357. //goodMatches.Add(items[0]);
  4358. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  4359. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  4360. if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))
  4361. {
  4362. Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);
  4363. pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  4364. pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  4365. goodMatches.Add(items[0]);
  4366. //arrXMatches.Add((int)X_dis);
  4367. ////arrYMatches.Add((int)Y_dis);
  4368. coutPt++;
  4369. XCompute += X_dis; YCompute += Y_dis;
  4370. }
  4371. else
  4372. {
  4373. Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);
  4374. }
  4375. }
  4376. }
  4377. float aver_X = XCompute / coutPt;// 600;//
  4378. float aver_Y = YCompute / coutPt;// 600;//
  4379. Console.WriteLine("平均横向距离差:{0} 平均纵向距离差:{1}", aver_X, aver_Y);//计算原图像相对于新图像的(距离差)、-->变换矩阵
  4380. var outMat = new Mat();
  4381. // 算法RANSAC对匹配的结果做过滤
  4382. var pSrc = pointsSrc.ConvertAll(Point2fToPoint2d);
  4383. var pDst = pointsDst.ConvertAll(Point2fToPoint2d);
  4384. var outMask = new Mat();
  4385. // 如果原始的匹配结果为空, 则跳过过滤步骤
  4386. if (pSrc.Count > 0 && pDst.Count > 0)
  4387. {
  4388. int srcOriX = 0;
  4389. int srcOriY = 0;
  4390. int newOriX = 0;
  4391. int newOriY = 0;
  4392. Cv2.FindHomography(pSrc, pDst, HomographyMethods.Ransac, mask: outMask);
  4393. //得到变换矩阵后拼接图像
  4394. int newWidth = matSrc.Width;// 2448;
  4395. int newHeight = matSrc.Height;// 2040;
  4396. if (aver_X <= 0)
  4397. {
  4398. newWidth = (int)(newWidth - aver_X);
  4399. srcOriX = (int)(-aver_X);
  4400. }
  4401. else
  4402. {
  4403. for (int i = 0; i < pDst.Count; i++)
  4404. {
  4405. pDst[i] = new Point2d(pSrc[i].X, pDst[i].Y);
  4406. }
  4407. newOriX = (int)aver_X;
  4408. if (matTo.Width + aver_X > newWidth)
  4409. newWidth = (int)(matTo.Width + aver_X);
  4410. }
  4411. if (aver_Y <= 0)
  4412. {
  4413. newHeight = (int)(newHeight - aver_Y);
  4414. srcOriY = (int)(-aver_Y);
  4415. }
  4416. else
  4417. {
  4418. for (int i = 0; i < pDst.Count; i++)
  4419. {
  4420. pDst[i] = new Point2d(pDst[i].X, pSrc[i].Y);
  4421. }
  4422. newOriY = (int)aver_Y;
  4423. if (matTo.Height + aver_Y > newHeight)
  4424. newHeight = (int)(matTo.Height + aver_Y);
  4425. }
  4426. result = new Mat(new OpenCvSharp.Size(newWidth, newHeight), matSrc.Type());
  4427. //<-- int index = 9; matSrc
  4428. Rect rectSrc = new Rect(0, 0, matSrc.Width, matSrc.Height);
  4429. Mat tempMatSrc = matSrc.Clone(rectSrc);
  4430. //复制原有区域part1(<--用户选中的区域)到新图像(<--原图像)
  4431. Mat maskSrc = tempMatSrc.CvtColor(ColorConversionCodes.RGBA2GRAY);
  4432. Mat posSrc = new Mat(result, new Rect(srcOriX, srcOriY, matSrc.Width, matSrc.Height));
  4433. tempMatSrc.CopyTo(posSrc, maskSrc);//原图像复制到新图像
  4434. Rect rect = new Rect(0, 0, matTo.Width, matTo.Height);
  4435. Mat tempMat = matTo.Clone(rect);
  4436. //复制原有区域part2(<--用户选中的区域)到新图像(<--原图像)
  4437. Mat mask = tempMat.CvtColor(ColorConversionCodes.RGBA2GRAY);
  4438. Mat pos = new Mat(result, new Rect(newOriX, newOriY, matTo.Width, matTo.Height));
  4439. tempMat.CopyTo(pos, mask);//原图像复制到新图像
  4440. //Bitmap part2 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(result);
  4441. ////、、R3a
  4442. //part2.Save(@"ResSurfA" + indexRes + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
  4443. return result;
  4444. }
  4445. result = matSrc.Clone();
  4446. //// 如果通过RANSAC处理后的匹配点大于10个,才应用过滤. 否则使用原始的匹配点结果(匹配点过少的时候通过RANSAC处理后,可能会得到0个匹配点的结果).
  4447. //if (outMask.Rows > 10)
  4448. //{
  4449. // byte[] maskBytes = new byte[outMask.Rows * outMask.Cols];
  4450. // outMask.GetArray(0, 0, maskBytes);
  4451. // Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, matchesMask: maskBytes, flags: DrawMatchesFlags.NotDrawSinglePoints);
  4452. //}
  4453. //else
  4454. // Cv2.DrawMatches(matSrc, keyPointsSrc, matTo, keyPointsTo, goodMatches, outMat, flags: DrawMatchesFlags.NotDrawSinglePoints);
  4455. //return OpenCvSharp.Extensions.BitmapConverter.ToBitmap(/*result*/outMat);
  4456. }
  4457. }
  4458. catch (Exception)
  4459. {
  4460. errorFlag = true;
  4461. }
  4462. return result;
  4463. }
  4464. /// <summary>
  4465. /// 图像拼接方法,返回拼接好的位移
  4466. /// </summary>
  4467. /// <param name="matSrc">需要拼接的mat1</param>
  4468. /// <param name="matTo">需要拼接的mat2</param>
  4469. /// <param name="errorFlag">返回true表示拼接失败</param>
  4470. /// <param name="keyPointsSrc">matSrc的检测点Points</param>
  4471. /// <param name="matSrcRet">matSrc的检测点Mat</param>
  4472. /// <param name="keyPointsTo">matTo的检测点Points</param>
  4473. /// <param name="matSrcRet">matTo的检测点Mat</param>
  4474. /// <returns></returns>
  4475. public static System.Drawing.Point MatchOneBySift(Mat matSrc00, Mat matTo00, out Boolean errorFlag, int orbCount1, double percent, int directionRect, bool usePercent = true)
  4476. {
  4477. ////从1到3分别是右、下、左
  4478. //int directionRect = 1;double percent, int directionRect
  4479. System.Drawing.Point movePoint = new System.Drawing.Point(-1, -1);
  4480. Mat matSrc = null;// new Mat();
  4481. Mat matTo = null;// new Mat();
  4482. KeyPoint[] keyPointsSrc;
  4483. Mat matSrcRet = null;
  4484. KeyPoint[] keyPointsTo;
  4485. Mat matToRet = null;
  4486. // Rect rectSrc = new Rect(0, 0, matSrc.Width, matSrc.Height);
  4487. // Mat tempMatSrc = matSrc.Clone(rectSrc);
  4488. if (!usePercent)
  4489. {
  4490. movePoint.X = 0;
  4491. movePoint.Y = 0;
  4492. matSrc = matSrc00;//.Clone();
  4493. matTo = matTo00;//.Clone();
  4494. }
  4495. else
  4496. switch (directionRect)
  4497. {
  4498. case 1:
  4499. {
  4500. movePoint.X = matSrc00.Width - (int)(matSrc00.Width * percent * 1.0);
  4501. movePoint.Y = 0;
  4502. matSrc = new Mat(matSrc00, new Rect(movePoint.X, 0, (int)(matSrc00.Width * percent * 1.0), matSrc00.Height));
  4503. matTo = new Mat(matTo00, new Rect(0, 0, (int)(matSrc00.Width * percent * 1.0), matSrc00.Height));
  4504. }
  4505. break;
  4506. case 2:
  4507. {
  4508. movePoint.X = 0;
  4509. movePoint.Y = matSrc00.Height - (int)(matSrc00.Height * percent * 1.0);
  4510. matSrc = new Mat(matSrc00, new Rect(0, movePoint.Y, matSrc00.Width, (int)(matSrc00.Height * percent * 1.0)));
  4511. matTo = new Mat(matTo00, new Rect(0, 0, matSrc00.Width, (int)(matSrc00.Height * percent * 1.0)));
  4512. }
  4513. break;
  4514. case 3:
  4515. {
  4516. movePoint.X = (int)(matSrc00.Width * percent * 1.0) - matSrc00.Width;
  4517. movePoint.Y = 0;
  4518. matSrc = new Mat(matSrc00, new Rect(0, 0, (int)(matSrc00.Width * percent * 1.0), matSrc00.Height));
  4519. matTo = new Mat(matTo00, new Rect(-movePoint.X, 0, (int)(matSrc00.Width * percent * 1.0), matSrc00.Height));
  4520. }
  4521. break;
  4522. default:
  4523. break;
  4524. }
  4525. //var result = new Mat();
  4526. errorFlag = false;
  4527. try
  4528. {
  4529. using (var surf = ORB.Create(orbCount1 * 1000))
  4530. {
  4531. matSrcRet = new Mat();
  4532. surf.DetectAndCompute(matSrc, null, out keyPointsSrc, matSrcRet);
  4533. matToRet = new Mat();
  4534. surf.DetectAndCompute(matTo, null, out keyPointsTo, matToRet);
  4535. }
  4536. //Cv2.ImShow("matTo", matTo);
  4537. //Cv2.WaitKey();
  4538. using (var bfMatcher = new BFMatcher())
  4539. {
  4540. var matches = bfMatcher.KnnMatch(matSrcRet, matToRet, k: 2);
  4541. var pointsSrc = new List<Point2f>();
  4542. var pointsDst = new List<Point2f>();
  4543. var goodMatches = new List<DMatch>();
  4544. //数组按照元素个数由多到少排序
  4545. var arrXMatches = new List<int>();
  4546. var arrYMatches = new List<int>();
  4547. double scaleI = 0.9;
  4548. float XCompute = 0; float YCompute = 0; int coutPt = 0;
  4549. foreach (DMatch[] items in matches.Where((e) => e.Length > 1))
  4550. {
  4551. if (items[0].Distance < scaleI * items[1].Distance)
  4552. {
  4553. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  4554. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  4555. arrXMatches.Add((int)X_dis);
  4556. arrYMatches.Add((int)Y_dis);
  4557. }
  4558. }
  4559. int[] arrX = arrXMatches.ToArray();
  4560. int[] arrY = arrYMatches.ToArray();
  4561. Array.Sort(arrX);
  4562. Array.Sort(arrY);
  4563. int valX1 = arrX[0];//当前
  4564. int valX2 = 0;//上一个
  4565. int timeX1 = 1;//当前
  4566. int timeX2 = 0;//上一个
  4567. for (int sortI = 1; sortI < arrX.Length; sortI++)
  4568. {
  4569. if (arrX[sortI] == valX1)
  4570. {
  4571. timeX1++;
  4572. }
  4573. else
  4574. {
  4575. if (timeX1 > timeX2)
  4576. {
  4577. valX2 = valX1;
  4578. timeX2 = timeX1;
  4579. }
  4580. valX1 = arrX[sortI];
  4581. timeX1 = 1;
  4582. }
  4583. }
  4584. if (timeX1 > timeX2)
  4585. {
  4586. valX2 = valX1;
  4587. timeX2 = timeX1;
  4588. }
  4589. int valY1 = arrY[0];//当前
  4590. int valY2 = 0;//上一个
  4591. int timeY1 = 1;//当前
  4592. int timeY2 = 0;//上一个
  4593. for (int sortI = 1; sortI < arrY.Length; sortI++)
  4594. {
  4595. if (arrY[sortI] == valY1)
  4596. {
  4597. timeY1++;
  4598. }
  4599. else
  4600. {
  4601. if (timeY1 > timeY2)
  4602. {
  4603. valY2 = valY1;
  4604. timeY2 = timeY1;
  4605. }
  4606. valY1 = arrY[sortI];
  4607. timeY1 = 1;
  4608. }
  4609. }
  4610. if (timeY1 > timeY2)
  4611. {
  4612. valY2 = valY1;
  4613. timeY2 = timeY1;
  4614. }
  4615. foreach (DMatch[] items in matches.Where((e) => e.Length > 1))
  4616. {
  4617. if (items[0].Distance < scaleI * items[1].Distance)
  4618. {
  4619. //pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  4620. //pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  4621. //goodMatches.Add(items[0]);
  4622. var X_dis = (keyPointsSrc[items[0].QueryIdx].Pt.X - keyPointsTo[items[0].TrainIdx].Pt.X);
  4623. var Y_dis = (keyPointsSrc[items[0].QueryIdx].Pt.Y - keyPointsTo[items[0].TrainIdx].Pt.Y);
  4624. if ((valX2 >= X_dis - 5 && valX2 <= X_dis + 5) && (valY2 >= Y_dis - 5 && valY2 <= Y_dis + 5))
  4625. {
  4626. Console.WriteLine("横向距离差:{0} 纵向距离差:{1}", X_dis, Y_dis);
  4627. pointsSrc.Add(keyPointsSrc[items[0].QueryIdx].Pt);
  4628. pointsDst.Add(keyPointsTo[items[0].TrainIdx].Pt);
  4629. goodMatches.Add(items[0]);
  4630. //arrXMatches.Add((int)X_dis);
  4631. ////arrYMatches.Add((int)Y_dis);
  4632. coutPt++;
  4633. XCompute += X_dis; YCompute += Y_dis;
  4634. }
  4635. else
  4636. {
  4637. //Console.WriteLine("横向距离差:{0} 纵向距离差:{1} 舍弃", X_dis, Y_dis);
  4638. }
  4639. }
  4640. }
  4641. float aver_X = XCompute / coutPt;// 600;//
  4642. float aver_Y = YCompute / coutPt;// 600;//
  4643. Console.WriteLine("平均横向距离差:{0} 平均纵向距离差:{1}", aver_X, aver_Y);//计算原图像相对于新图像的(距离差)、-->变换矩阵
  4644. if (usePercent && coutPt > 0 && (Math.Abs(movePoint.X) > 0 ? Math.Abs(aver_X) < Math.Abs(movePoint.X) * 0.15 : Math.Abs(aver_X) < 15)
  4645. && (Math.Abs(movePoint.Y) > 0 ? Math.Abs(aver_Y) < Math.Abs(movePoint.Y) * 0.15 : Math.Abs(aver_Y) < 15))
  4646. {
  4647. movePoint.X += (int)aver_X;
  4648. movePoint.Y += (int)aver_Y;
  4649. }
  4650. else if (!usePercent && coutPt > 0)
  4651. {
  4652. movePoint.X += (int)aver_X;
  4653. movePoint.Y += (int)aver_Y;
  4654. }
  4655. else
  4656. {
  4657. errorFlag = true;
  4658. //errorFlag = false;//集成另一套算法进行拼接
  4659. }
  4660. }
  4661. }
  4662. catch (Exception)
  4663. {
  4664. errorFlag = true;
  4665. }
  4666. finally
  4667. {
  4668. //if (matSrc != null)
  4669. // matSrc.Dispose();
  4670. //if (matTo != null)
  4671. // matTo.Dispose();
  4672. if (matSrcRet != null)
  4673. matSrcRet.Dispose();
  4674. if (matToRet != null)
  4675. matToRet.Dispose();
  4676. GC.Collect();
  4677. }
  4678. //matSrc, matTo
  4679. //
  4680. if (errorFlag)//集成另一套算法进行拼接
  4681. {
  4682. System.Drawing.Point movePointByAccordDotNet = MatchByAccordDotNet(matSrc, matTo, out errorFlag);
  4683. if (!errorFlag && (Math.Abs(movePoint.X) > 0 ? Math.Abs(movePointByAccordDotNet.X) < Math.Abs(movePoint.X) * 0.25 : Math.Abs(movePointByAccordDotNet.X) < 15)
  4684. && (Math.Abs(movePoint.Y) > 0 ? Math.Abs(movePointByAccordDotNet.Y) < Math.Abs(movePoint.Y) * 0.25 : Math.Abs(movePointByAccordDotNet.Y) < 15))
  4685. {
  4686. //Cv2.ImShow("matTo", matTo);
  4687. //Cv2.WaitKey();
  4688. if ((Math.Abs(movePoint.X) > 0 ? Math.Abs(movePointByAccordDotNet.X) < Math.Abs(movePoint.X) * 0.1 : Math.Abs(movePointByAccordDotNet.X) < 15)
  4689. && (Math.Abs(movePoint.Y) > 0 ? Math.Abs(movePointByAccordDotNet.Y) < Math.Abs(movePoint.Y) * 0.1 : Math.Abs(movePointByAccordDotNet.Y) < 15))
  4690. {
  4691. string savePath = @"C:\Users\win10SSD\Desktop\工作目录\企业解决方案_显微镜图像处理及分析系统\bin\Debug\test\";
  4692. Cv2.ImWrite(savePath + "matSrc" + movePoint.X.ToString() + "_" + movePoint.Y.ToString() + ".jpg", matSrc);
  4693. Cv2.ImWrite(savePath + "matTo" + movePoint.X.ToString() + "_" + movePoint.Y.ToString() + ".jpg", matTo);
  4694. movePoint.X += movePointByAccordDotNet.X;
  4695. movePoint.Y += movePointByAccordDotNet.Y;
  4696. }
  4697. }
  4698. errorFlag = false;//集成另一套算法后重置标记位
  4699. }
  4700. return movePoint;
  4701. }
  4702. /// <summary>
  4703. /// 图片切割
  4704. /// </summary>
  4705. public static Bitmap Cut(Bitmap src, int x, int y, int width, int height)
  4706. {
  4707. var mat = BitmapConverter.ToMat(src);
  4708. mat = new Mat(mat, new Rect(x, y, width, height));
  4709. return BitmapConverter.ToBitmap(mat);
  4710. }
  4711. public enum Side
  4712. {
  4713. Top,
  4714. Left,
  4715. Right,
  4716. Buttom
  4717. }
  4718. /// <summary>
  4719. /// 图片切割
  4720. /// </summary>
  4721. /// <param name="src"></param>
  4722. /// <param name="rate">切割律</param>
  4723. /// <param name="side">切割方向</param>
  4724. /// <returns></returns>
  4725. public static Bitmap Cut(Bitmap src, double rate, Side side)
  4726. {
  4727. int x = 0;
  4728. int y = 0;
  4729. int width = src.Width;
  4730. int height = src.Height;
  4731. switch (side)
  4732. {
  4733. case Side.Top:
  4734. height = (int)(height * rate);
  4735. break;
  4736. case Side.Left:
  4737. width = (int)(width * rate);
  4738. break;
  4739. case Side.Right:
  4740. x = (int)(width * (1 - rate));
  4741. width = (int)(width * rate);
  4742. break;
  4743. case Side.Buttom:
  4744. y = (int)(height * (1 - rate));
  4745. height = (int)(height * rate);
  4746. break;
  4747. }
  4748. return Cut(src, x, y, width, height);
  4749. }
  4750. private static Point2d Point2fToPoint2d(Point2f input)
  4751. {
  4752. Point2d p2 = new Point2d(input.X, input.Y);
  4753. return p2;
  4754. }
  4755. /// <summary>
  4756. /// 集成Accord.NET的算法计算拼接坐标
  4757. /// </summary>
  4758. /// <param name="matSrc"></param>
  4759. /// <param name="matTo"></param>
  4760. /// <param name="errorFlag"></param>
  4761. /// <returns></returns>
  4762. public static System.Drawing.Point MatchByAccordDotNet(Mat matSrc, Mat matTo, out Boolean errorFlag)
  4763. {
  4764. errorFlag = true;
  4765. System.Drawing.Point movePoint = new System.Drawing.Point(-1, -1);
  4766. Bitmap img1 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(matSrc);
  4767. Bitmap img2 = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(matTo);
  4768. // Step 1: Detect feature points using Harris Corners Detector
  4769. movePoint = VisualMath.Tools.MatchByAccordDotNet(img1, img2, out errorFlag);
  4770. //int/*VisualMath.Accord.External.AForge.IntPoint*/[] harrisPoints2 = harris.ProcessImageMethod(img2).ToArray();
  4771. //// Show the marked points in the original images
  4772. //Bitmap img1mark = new PointsMarker(harrisPoints1).Apply(img1);
  4773. //Bitmap img2mark = new PointsMarker(harrisPoints2).Apply(img2);
  4774. //// Concatenate the two images together in a single image (just to show on screen)
  4775. //Concatenate concatenate = new Concatenate(img1mark);
  4776. //pictureBox.Image = concatenate.Apply(img2mark);
  4777. return movePoint;
  4778. }
  4779. /// <summary>
  4780. /// Log
  4781. /// </summary>
  4782. /// <param name="src"></param>
  4783. /// <param name="dst"></param>
  4784. public static Mat ResizeMat(Mat src, List<Args> lists)
  4785. {
  4786. try
  4787. {
  4788. int width = 0;
  4789. int height = 0;
  4790. for (int i = 0; i < lists.Count; i++)
  4791. {
  4792. Args args = lists[i];
  4793. switch (args.Key)
  4794. {
  4795. case "height":
  4796. height = Convert.ToInt32(args.Value);
  4797. break;
  4798. case "width":
  4799. width = Convert.ToInt32(args.Value);
  4800. break;
  4801. default:
  4802. break;
  4803. }
  4804. }
  4805. Cv2.Resize(src, src, new OpenCvSharp.Size(width, height));
  4806. return src;
  4807. }
  4808. catch (Exception ex)
  4809. {
  4810. throw ex;
  4811. }
  4812. finally
  4813. {
  4814. GC.Collect();
  4815. }
  4816. }
  4817. }
  4818. }