From 872f3201148bfea013929a912edd69db312aaec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Tue, 28 Apr 2026 13:28:32 +0800 Subject: [PATCH 01/17] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20CfgControl=20?= =?UTF-8?q?=E5=92=8C=20Camera=20=E9=A1=B9=E7=9B=AE=E4=B8=AD=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=20MahApps=20=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XP.Camera/XP.Camera.csproj | 1 - .../XP.ImageProcessing.CfgControl.csproj | 5 ----- 2 files changed, 6 deletions(-) diff --git a/XP.Camera/XP.Camera.csproj b/XP.Camera/XP.Camera.csproj index 413cef1..ab74c11 100644 --- a/XP.Camera/XP.Camera.csproj +++ b/XP.Camera/XP.Camera.csproj @@ -15,7 +15,6 @@ - diff --git a/XP.ImageProcessing.CfgControl/XP.ImageProcessing.CfgControl.csproj b/XP.ImageProcessing.CfgControl/XP.ImageProcessing.CfgControl.csproj index 3f5417f..67d2cf3 100644 --- a/XP.ImageProcessing.CfgControl/XP.ImageProcessing.CfgControl.csproj +++ b/XP.ImageProcessing.CfgControl/XP.ImageProcessing.CfgControl.csproj @@ -19,11 +19,6 @@ - - - - - From 0c2e360f21bcbf03182d98392f410df47c919e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Tue, 28 Apr 2026 14:05:53 +0800 Subject: [PATCH 02/17] =?UTF-8?q?=E5=8E=BB=E6=8E=89MahApps=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controls/CalibrationControl.xaml | 34 +++---------------- .../ChessboardCalibrationControl.xaml | 28 ++++----------- 2 files changed, 11 insertions(+), 51 deletions(-) diff --git a/XP.Camera/Calibration/Controls/CalibrationControl.xaml b/XP.Camera/Calibration/Controls/CalibrationControl.xaml index a7bc653..3fdb67c 100644 --- a/XP.Camera/Calibration/Controls/CalibrationControl.xaml +++ b/XP.Camera/Calibration/Controls/CalibrationControl.xaml @@ -3,7 +3,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:cal="clr-namespace:XP.Camera.Calibration" xmlns:controls="clr-namespace:XP.Camera.Calibration.Controls" mc:Ignorable="d" @@ -36,9 +35,6 @@ BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3"> - + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> - + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> + Style="{StaticResource ToolbarButtonStyle}" /> From 1822e159089eeedf8164022413761f34a663ba80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Tue, 28 Apr 2026 14:37:15 +0800 Subject: [PATCH 03/17] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B0=94=E6=B3=A1?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E7=95=8C=E9=9D=A2=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XplorePlane/Assets/Icons/Clear.png | Bin 0 -> 1059 bytes XplorePlane/Assets/Icons/Undo.png | Bin 0 -> 442 bytes XplorePlane/Assets/Icons/brush32.png | Bin 0 -> 609 bytes XplorePlane/Assets/Icons/eraser32.png | Bin 0 -> 697 bytes XplorePlane/Assets/Icons/magic32.png | Bin 0 -> 516 bytes XplorePlane/Assets/Icons/rectangle32.png | Bin 0 -> 209 bytes .../ImageProcessing/BubbleMeasurePanel.xaml | 38 ++++++++++++------ .../BubbleMeasurePanel.xaml.cs | 13 ++++++ 8 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 XplorePlane/Assets/Icons/Clear.png create mode 100644 XplorePlane/Assets/Icons/Undo.png create mode 100644 XplorePlane/Assets/Icons/brush32.png create mode 100644 XplorePlane/Assets/Icons/eraser32.png create mode 100644 XplorePlane/Assets/Icons/magic32.png create mode 100644 XplorePlane/Assets/Icons/rectangle32.png diff --git a/XplorePlane/Assets/Icons/Clear.png b/XplorePlane/Assets/Icons/Clear.png new file mode 100644 index 0000000000000000000000000000000000000000..285eeae277c9b9dcec94689d77a3f85335de29e8 GIT binary patch literal 1059 zcmV+;1l;?HP)*2S!gU$n8FAuT4`mc7m36_2>t=F zP)I-<6%~>T7b1AE3u0p@BqaX6$h**Oyz z(UJfXD%nnD!;Uk*Lho$E0`iTGjVFL+J32b@aS^EnkWl1G>hX6QQya%$Cjy^v!h4WU zE-Wk@U0Yi_#R4OO>-fspv{V8}sANj2MT3<}DT=?GJ-ZJEv0xL7lLd$zfZe%{a|GWde32FtA>0&qZjN2RM&yb+ zPXHqA#F7sJoWRs3h&e?NyoTL}{3N|;&Bz6+697SkT*r=G2Ha2tm~rd`IMdRQ3m6gL zA{R(T@}?q$lTo;D;~B$0E=oATyX3VMhZ@g@TC&Ln{q{X-}d>vvoiuXuJe%R zQLQ2xg(x6L*nzIDuB~=8v8E!ZgInMmUKw%Ii~ucw{F(81-Z`$qoCM_42z#B&<;MJ& z>C%WugHbXgK!erQ)lvEhgybPDL;i+-7@wEPWIm`5TN;8im_UGDmAtR-L1IPhXY3*9 z@Z8+o3yo#^njy{&jhPBhmV=WLMM@Ym+&9NVx!Y_K$M9zn#jIV63DNcaD?mZz4 z8+o84tQ{^C3c>G*hyVe65krhsMB7O3Q?&Ls0j|xKBtqou{`n@#dkD^aTl{(Qw;(J6@D6M@yI66N z6EltEk(1DU$H?s|7`*;DPe1`#NQ6D^-`ufzL=|T|1j&t3skB9NSy%*uEunU9$ASgc zP=HXr2z}k`(_w0Yqdi9a5hP=3cw&iPyyO(5Z4Dgjy>7QuWQrq}i>ws%@%S)80$;?9Mar4}Ht6~PYQYmODD z15*?2kh4DdDNxX562YD8{=+qK5mCXhr`fs9-O>rzMG_HyZR5X+sU=psf-Y-IfD(m7 zywsc%sI{_lt&z1YK#L^;(u0i8Q0=?uTW)_Pz_KCYjvdGQX7fJ)00960ZgkDo00006 dNkl%YJ=|mo61Nz06MGWo781nX#2!T0_k@Y1B8UDqW|)10<~&<3D6R_#D6F&|q<3qUfbubXAr4=c~= zE`V%~El3T+u$c=gVT_}@MT-EKsKN@zu%jvj%p*V~OA z-09Ia7czxt+xAnQYgYi85rS_D+j({am6|48%zL4Clpb0D z(ip8KR-aPn?5fQ1pU?s*%kqp#j5XpI3S+)$q>>hZYVa1{4}c>A?;nACC*>Ca0RR8} kTI0t6000I_L_t&o0GetGP^mzyX8-^I07*qoM6N<$f@Vg!jsO4v literal 0 HcmV?d00001 diff --git a/XplorePlane/Assets/Icons/brush32.png b/XplorePlane/Assets/Icons/brush32.png new file mode 100644 index 0000000000000000000000000000000000000000..39ca1d6dd9388e41d8ae05a16c9ff494c2b8c204 GIT binary patch literal 609 zcmV-n0-pVeP)j);qJ~pZNXl zpMRYam`BefP^4u`%<`Q`jFfozXUe#P^q?2pIex9^Bl zULp{aURZUqm)}bSB)x)^nYH-bn5PM_>I+-W1(p2P;&Z-F5dd6sUf6OjXkGc`-($pi7aEReg90=ycQ~ARv4bfc$BvI=1Nd`#VUa)HgEx8WocO zna>F9FBf5S-VHMnTc*W4`NHug0c8CO2Ze2sU~0TN;rpt#Nr1uH^E|4HNK|{2zcmTe z4UAIJdtW*9z1JjgceDRlh?N(QScFyxkiB{F=!}5CnWkk7!0I;@5I|XwtUu9d$oA9G zT;^u>nFPr0cBgZIM4SWI%YYm2d&cLANg(syJ3zpn&Nhpcdzb`JKquThH>$;kNucS+ vCFEwc{{R30|Nl2M1R($b00v1!K~w_(e`3l({-cU000000NkvXXu0mjfet{lP literal 0 HcmV?d00001 diff --git a/XplorePlane/Assets/Icons/eraser32.png b/XplorePlane/Assets/Icons/eraser32.png new file mode 100644 index 0000000000000000000000000000000000000000..651e27e296f5004f64c4a5a8e94e7bb7a9f6118f GIT binary patch literal 697 zcmV;q0!ICbP)_YD+@LO^_I)^#3n2*sdRLD~2;a~1{Upcx+duy% z0c$r;q~CQIo0mELF$h4B4Xv>)ORPV#0h;Jd zUZAR9o@_toCF9eOU5iB<`-0Hj3fCmlG3=J|Y{%$$1`fVSNp;XfGF?RLAn zc6tHWPOid~`Q!08`1(nJrtw-e^9|%atB3Y}^ynr5q(tqJn>y~->$MX-Mxy{~JR%>v z?XYc!dT3`Kyh#+G>DJ1VAMgo7OuaD>1!x*@ive}- zPW`}EY;7T9Byq1&(W4gykV6`HoP%e+e(h2Rz`Oy3dMd><^hu5byr^ zczu8@%Lc^KfqeZDkb0gZ$fJx84g(D(f{ilXCw zzyE;YPI*9!WFNL>$LAQ*W0}fZrxJNdSQg@6dz*@=e zM9=QO0sM7xK+OP4le@N87;9q&pp656uK0me{mEz(NV*w-*6xkg`5iBf)M(A;Gr;u5 zUe+|%c+CJB@fMoR0VL=z00030|IycsyZ`_I21!IgR09Cfl`~LGQu|E+0000;n%AIkRO2LEZJC5I*)@!;Y7;@cD^Lrc7 z5N`bFVP)d>)EZ_HN_5a wESmj~`Hx@?&>{c-@1DDRCy>DgauGAb^67exQ{v|I0!0`+UHx3vIVCg!0K<$-U;qFB literal 0 HcmV?d00001 diff --git a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml index 46f1700..07d443a 100644 --- a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml +++ b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml @@ -43,14 +43,22 @@ - - - - + + + + + + + + + + + + @@ -58,9 +66,9 @@ - - @@ -86,9 +94,13 @@ - + + + + @@ -97,10 +139,6 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs index 8169eac..99fa7aa 100644 --- a/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs +++ b/XplorePlane/Views/ImageProcessing/BubbleMeasurePanel.xaml.cs @@ -56,6 +56,7 @@ namespace XplorePlane.Views.ImageProcessing }; // 初始同步:确保面板默认值推送到 canvas + _canvas?.SetBubbleTool(PolygonRoiCanvas.BubbleSubTool.Roi); _canvas?.SetBubbleThreshold((int)SliderThreshold.Value); _canvas?.SetBubbleBrushSize((int)SliderBrushSize.Value); if (double.TryParse(TbVoidLimit.Text, out double initLimit)) From 36083993ea09a960c9d32f118ca7c7d3e158620c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Wed, 29 Apr 2026 10:34:25 +0800 Subject: [PATCH 11/17] =?UTF-8?q?BGA=E7=A9=BA=E9=9A=99=E6=B5=8B=E9=87=8F?= =?UTF-8?q?=E9=9D=A2=E6=9D=BF:=20=E7=95=8C=E9=9D=A2=E9=A3=8E=E6=A0=BC?= =?UTF-8?q?=E7=8E=B0=E4=BB=A3=E5=8C=96=EF=BC=8C=E7=BB=9F=E4=B8=80=E5=8D=A1?= =?UTF-8?q?=E7=89=87+=E6=8C=89=E9=92=AE=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ImageProcessing/BgaMeasurePanel.xaml | 116 +++++++++++------- 1 file changed, 69 insertions(+), 47 deletions(-) diff --git a/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml b/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml index 6467a2e..f24b39a 100644 --- a/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml +++ b/XplorePlane/Views/ImageProcessing/BgaMeasurePanel.xaml @@ -3,72 +3,94 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="BGA空隙测量" - Width="240" Height="260" + Width="280" Height="280" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" - Topmost="True" - ShowInTaskbar="False"> + Topmost="True" ShowInTaskbar="False" + Background="#F5F5F5" FontFamily="Microsoft YaHei UI"> - + + + + + - - - - - - - + + + + + + + + + + - + + - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b287b83c9f3fc6a6452d33e9fd8b7a90b5e0dbdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Wed, 29 Apr 2026 10:55:27 +0800 Subject: [PATCH 13/17] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E6=B5=8B=E9=87=8F=E5=B7=A5=E5=85=B7=E5=9B=BE=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XplorePlane/Assets/Icons/angle.png | Bin 0 -> 568 bytes XplorePlane/Assets/Icons/bubble.png | Bin 0 -> 676 bytes XplorePlane/Assets/Icons/cylinder.png | Bin 0 -> 801 bytes XplorePlane/Assets/Icons/ptol.png | Bin 0 -> 647 bytes XplorePlane/Assets/Icons/ptop.png | Bin 0 -> 424 bytes .../ImageProcessing/BgaMeasurePanel.xaml | 4 ++-- XplorePlane/Views/Main/MainWindow.xaml | 18 ++++++------------ 7 files changed, 8 insertions(+), 14 deletions(-) create mode 100644 XplorePlane/Assets/Icons/angle.png create mode 100644 XplorePlane/Assets/Icons/bubble.png create mode 100644 XplorePlane/Assets/Icons/cylinder.png create mode 100644 XplorePlane/Assets/Icons/ptol.png create mode 100644 XplorePlane/Assets/Icons/ptop.png diff --git a/XplorePlane/Assets/Icons/angle.png b/XplorePlane/Assets/Icons/angle.png new file mode 100644 index 0000000000000000000000000000000000000000..19c7ab0cf0cd1e088803140ff99e729f002867f1 GIT binary patch literal 568 zcmV-80>}M{P)BXsm&>h0hHtS@p!yB2>=}5D#wqi6*ZzA zQ0fDC+(uEfMJp~MfJ%LqWp`rFYGH4Hn))C~l2q9dH@yLB>R-iPYYTe;xK>Y&UI3%f zXw5|kJgdm3jjDDAp!(r(xWYn4KN>fsGXTzhQxa=Ba`OFfks0XU%4`q*~f^;B=2^R&BLjR3r0c-DEI-(bNvY6g%g-hO{sfd9^l z5uma@nM`~gZ+L6FD#9n}+DAsVE#&P_>9RUneFkoEZ*-2>ypi-!wdY<=x=_rUT z!5FA62wDMPJfQk83>&G(Hz2{PTM_fDiV=Y7X%&vN*DV7SV>}AR2OjN;2B5Z<4)%R) zd;pGFVGW@H;L@o+wFbP1Och6SuXI0|#@qT#!K(q#FdU?){Mw~LQ@zH#AI!NzYZ`Cs z!}Mm+02t{=yURlr&c9&l?a;jX_-;UB{Xhd?XP1f?aB?+^0ho?Zr)5bO`1%|%fJ(=@ zEzz?WK;+G^=;#0jpN+0x00030|CSCPKL7v#21!IgR09C?AM!zuP5kNr0000-B?vGaiqR&hebwS_5EUgZ3p- zYn@JKz~E94`lQwh0OJd^Mnf$K5JrXN;noTOReGM&&k>*L?zS1gQP^Yv6HQZix8Ch` z`RR08`+iSY=jZr$Z~kXI8Q^lc6w2rqdPV}Kg!pw4z@smz>GjM+j4J1J6norvPm&{m zg8xXX*6ntqdy)b8=235|bT5s-;cyTjmie~~xygDv(Da-f0XGwcb&6N6!MI1&Z9!=T zU=+^hvx-BJ$oKpGFlhB=vK4^)guuHMr{SG1ez<0OqhxTViA-Eti83ds4Sp9-3$dAw9g2-eLz%w5+ zKm>xn3nKQjAb^{xd@CRtBf+?}AU9VyE&fjMcz*cq-V})f7zH4#ZdSS+qhE+&pHp(* zHAb!+G3NY?h`f0`0ZK~FC;*BxA<9ap(V>QUFRC8KYR3==leadmuBs#fR5w-L8$BgT zLR6O4U!MlR+s6E;n`$0;1wi8|0LyX06oY|(PXnkM zV_wA_`VI*?q+dCnA};|58H&w)0{{U3|0p(QMF0Q*21!IgR09A@3-m#UDGm$(0000< KMNUMnLSTX-n=y(2 literal 0 HcmV?d00001 diff --git a/XplorePlane/Assets/Icons/cylinder.png b/XplorePlane/Assets/Icons/cylinder.png new file mode 100644 index 0000000000000000000000000000000000000000..3931601418308fa1f3c31a8dd2ca7582bbaa8f97 GIT binary patch literal 801 zcmV++1K#|JP)+WUQQOL35ke{m~9h8xuvuArUGcm*D zKmUFYf%$wsT`rgTVzJn%E!AGtzG)HlnPV+yZ&$}gJs{vzQjW*t>-+s)Tj0ZBFxab~ z4Tr-5QU4%G*u!2+Drc@uS_#N70Hpu`&(7!bOtLwhPKA}j@p#-Lj9HV+9*@V&65Lu0 zLHM5_0V$T8Mrs-05=dwme=e8HP5TRofFW<}LRww|GM-8y)hRe_XT#F@cpw6XWNk4& z)){ySNMXvNPSM*q`Un{E!p&haR~IhPCdjpt2H<~wrsXl?4iWtR-tkF`!nyD8UMmLH4q6C~iU;;fz z3J9sCJ~(5vq$~vr5>74Jb|w%->bc>Mz@G=c@_;Kcb$2&^VX4ln_-yu_tO>i#E40060M5rNNSyih;-P_XO`DHDeImZ-&JUfm!8c1w{{bu!HUrdZNh zbG|-qCBRAQoBQnQ*n6)&liI-AjP?D22U* zPi}7#9N_hO<-*zPb(lkaSl7TyK=aA-`79Izh6E`E81r3(^wWN#-(2Yx#C*oRszCyH zL9ET64iO=WtNaF>8xo>^YFmmBQq>DtG@og;!6!(-X%L7aQsuXuPpxaYa+UNo&*cQ7 zRlSg&*X`O{Jy8N~Cmw+e?i4U5qc#lGH^oUUb6=-zX9AAMw{2|yKL7v#|Nnu&c1i#M f00v1!K~w_(MgrMTFbJ1J00000NkvXXu0mjf4e(^w literal 0 HcmV?d00001 diff --git a/XplorePlane/Assets/Icons/ptol.png b/XplorePlane/Assets/Icons/ptol.png new file mode 100644 index 0000000000000000000000000000000000000000..b635ceec84b95d0c11fbb59d490115f81d16a808 GIT binary patch literal 647 zcmV;20(kw2P)+0&$qkx zF8ba-|0)2><#H$6uh;8M5CpGN^W^{tu2!pbHk%z~QJSWw`Fwtw8o~e|f?&;TU#EsJ z0KV_P*NEG$Nw>iOSf!@B05?rzuKgC^yDg9alD2V|F#~YB-C_l468XGbE@zETav1<3 zKOT>*?q!G{^}Ud!-XHx`;-<`PxE$bqzbDu0b)gd6sv<%GEo5)JNF{K0HA-FaO_>X1 zPrMv}2aM%rO8~+I!OD0#Bfc0PYlv%Nr_4W*#({PPfXjl8e8N@>ErzFyI<5efl78f0Q1KG&CBCf_C*EKHoHB?=fh*gQi5F+yC{Cjaom9QsZG&D`#JqAeI)=ZLgfCxGgkAOe|0l3q9Cd-| z-lDgc4yNBsZ7^*OK53d3h%rf$19E|q+GEjlk8UNx1VOMvF0(AVLsofs0$1}+<2c^V zYf|qPyFNM=e|OYGN(4MRR=$bj_`*^5Ub1yvS2%?n$6jIe7i1)3qA2>%K=40ch-lk3 zZ<^-XT6;eU@D+yPt2AN)px4&}%o9#zLLgsCBYprV(L^`_nuuQkT8KXZ8i;=Z(ulJF zl8CbbQiw$W3B+Q6Z^SBqPsD0~FT^H*55#7`R)iP87KAszT7*}?8iaSiQiKR#2|^6u zLhz!C$?K7W5ArmRhyvyaz9SxR^WHNE5eJ|lZ{57;p3EP(@a~3TC{zGMV8;jM??Hqb zpzr&W6CebrN*usOjIQgB*l~{EZ)nVUwB#`K2><~9|Id%htpET321!IgR09AqA-2vN SjFB1u0000 - + @@ -93,4 +93,4 @@ - + \ No newline at end of file diff --git a/XplorePlane/Views/Main/MainWindow.xaml b/XplorePlane/Views/Main/MainWindow.xaml index f9b886a..b83d2f6 100644 --- a/XplorePlane/Views/Main/MainWindow.xaml +++ b/XplorePlane/Views/Main/MainWindow.xaml @@ -193,8 +193,6 @@ - - @@ -207,14 +205,14 @@ telerik:ScreenTip.Title="点点距测量" Command="{Binding PointDistanceMeasureCommand}" Size="Medium" - SmallImage="/Assets/Icons/crosshair.png" + SmallImage="/Assets/Icons/ptop.png" Text="点点距测量" /> @@ -225,14 +223,14 @@ telerik:ScreenTip.Title="角度测量" Command="{Binding AngleMeasureCommand}" Size="Medium" - SmallImage="/Assets/Icons/dynamic-range.png" + SmallImage="/Assets/Icons/angle.png" Text="角度测量" /> @@ -385,7 +383,6 @@ Size="Large" SmallImage="/Assets/Icons/spiral.png" /> - - - + - - @@ -584,4 +578,4 @@ - + \ No newline at end of file From eeaa6b4c987c6d54e9a45fe06f4c9228acd780b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Wed, 29 Apr 2026 13:24:37 +0800 Subject: [PATCH 14/17] =?UTF-8?q?=E5=AD=94=E9=9A=99=E7=8E=87=EF=BC=9A?= =?UTF-8?q?=E4=B8=BB=E6=A1=86=E6=9E=B6=E5=AE=9E=E7=8E=B0=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=BE=85=E5=8A=A9=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ImageProcessing/BgaDetectionViewModel.cs | 2 +- .../ImageProcessing/VoidDetectionViewModel.cs | 383 ++++++++++++++++++ XplorePlane/ViewModels/Main/MainViewModel.cs | 22 + .../ImageProcessing/VoidDetectionPanel.xaml | 179 ++++++++ .../VoidDetectionPanel.xaml.cs | 50 +++ XplorePlane/Views/Main/MainWindow.xaml | 7 +- 6 files changed, 638 insertions(+), 5 deletions(-) create mode 100644 XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs create mode 100644 XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml create mode 100644 XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml.cs diff --git a/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs b/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs index c3b901c..5d6b31f 100644 --- a/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs +++ b/XplorePlane/ViewModels/ImageProcessing/BgaDetectionViewModel.cs @@ -125,7 +125,7 @@ namespace XplorePlane.ViewModels.ImageProcessing } }; - // 禁用右键菜单(参考点点距方式) + // 禁用右键菜单 _canvas.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, false); // 订阅画布点击事件来添加 ROI 顶点 diff --git a/XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs b/XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs new file mode 100644 index 0000000..96e7646 --- /dev/null +++ b/XplorePlane/ViewModels/ImageProcessing/VoidDetectionViewModel.cs @@ -0,0 +1,383 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Emgu.CV; +using Emgu.CV.CvEnum; +using Emgu.CV.Structure; +using Emgu.CV.Util; +using Prism.Commands; +using Prism.Mvvm; +using XP.ImageProcessing.Processors; +using XP.ImageProcessing.RoiControl.Controls; +using XP.ImageProcessing.RoiControl.Models; +using XplorePlane.Services.MainViewport; + +namespace XplorePlane.ViewModels.ImageProcessing +{ + public class VoidDetectionViewModel : BindableBase + { + private readonly IMainViewportService _viewportService; + private BitmapSource _originalImage; + private System.Threading.CancellationTokenSource _debounceCts; + private const int DebounceMs = 300; + + public VoidDetectionViewModel(IMainViewportService viewportService) + { + _viewportService = viewportService; + ExecuteCommand = new DelegateCommand(Execute); + PropertyChanged += OnAnyPropertyChanged; + } + + private void OnAnyPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ResultText) || e.PropertyName == nameof(ResultImage) || e.PropertyName == nameof(RoiEnabled)) + return; + TriggerDebouncedExecution(); + } + + private void TriggerDebouncedExecution() + { + _debounceCts?.Cancel(); + _debounceCts = new System.Threading.CancellationTokenSource(); + var token = _debounceCts.Token; + System.Threading.Tasks.Task.Delay(DebounceMs, token).ContinueWith(t => + { + if (!t.IsCanceled) Execute(); + }, System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext()); + } + + // 参数 + private int _minThreshold = 128; + public int MinThreshold { get => _minThreshold; set => SetProperty(ref _minThreshold, value); } + + private int _maxThreshold = 255; + public int MaxThreshold { get => _maxThreshold; set => SetProperty(ref _maxThreshold, value); } + + private int _minVoidArea = 10; + public int MinVoidArea { get => _minVoidArea; set => SetProperty(ref _minVoidArea, value); } + + private int _mergeRadius = 3; + public int MergeRadius { get => _mergeRadius; set => SetProperty(ref _mergeRadius, value); } + + private int _blurSize = 3; + public int BlurSize { get => _blurSize; set => SetProperty(ref _blurSize, value); } + + private double _voidLimit = 25.0; + public double VoidLimit { get => _voidLimit; set => SetProperty(ref _voidLimit, value); } + + // ROI + private bool _roiEnabled; + public bool RoiEnabled + { + get => _roiEnabled; + set + { + if (SetProperty(ref _roiEnabled, value)) + OnRoiEnabledChanged(); + } + } + + private PolygonRoiCanvas _canvas; + private PolygonROI _roiShape; + private System.Windows.Controls.Image _resultOverlayImage; + + public void SetCanvas(PolygonRoiCanvas canvas) => _canvas = canvas; + + private void OnRoiEnabledChanged() + { + if (_canvas == null) return; + if (RoiEnabled) + { + if (_canvas.ROIItems == null) + _canvas.ROIItems = new ObservableCollection(); + _roiShape = new PolygonROI { Color = "Cyan", IsSelected = true }; + _canvas.ROIItems.Add(_roiShape); + _canvas.SelectedROI = _roiShape; + _roiShape.Points.CollectionChanged += (s, e) => + { + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add || + e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove) + { + _canvas.SelectedROI = null; + _canvas.SelectedROI = _roiShape; + } + }; + _canvas.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, false); + _canvas.AddHandler(PolygonRoiCanvas.CanvasClickedEvent, new RoutedEventHandler(OnCanvasClickedForRoi)); + } + else + { + CleanupRoi(); + } + } + + private void OnCanvasClickedForRoi(object sender, RoutedEventArgs e) + { + if (!RoiEnabled || _roiShape == null) return; + if (e is CanvasClickedEventArgs args) + { + InsertPointToPolygon(args.Position, _roiShape.Points); + _roiShape.IsSelected = true; + _canvas.SelectedROI = _roiShape; + } + } + + public void CleanupRoi() + { + if (_canvas != null) + { + _canvas.RemoveHandler(PolygonRoiCanvas.CanvasClickedEvent, new RoutedEventHandler(OnCanvasClickedForRoi)); + _canvas.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, true); + } + if (_roiShape != null && _canvas?.ROIItems != null) + { + _canvas.ROIItems.Remove(_roiShape); + _canvas.SelectedROI = null; + _roiShape = null; + } + } + + public void RestoreContextMenu() + { + if (_canvas != null) + { + _canvas.RemoveHandler(PolygonRoiCanvas.CanvasClickedEvent, new RoutedEventHandler(OnCanvasClickedForRoi)); + _canvas.SetValue(System.Windows.Controls.ContextMenuService.IsEnabledProperty, true); + if (_roiShape != null) + { + _roiShape.IsSelected = false; + _roiShape.IsEditable = false; + } + _canvas.SelectedROI = null; + } + } + + // 结果 + private string _resultText = "结果: --"; + public string ResultText { get => _resultText; set => SetProperty(ref _resultText, value); } + + private BitmapSource _resultImage; + public BitmapSource ResultImage { get => _resultImage; set => SetProperty(ref _resultImage, value); } + + public ObservableCollection Results { get; } = new(); + + public DelegateCommand ExecuteCommand { get; } + + private void Execute() + { + if (_originalImage == null) + _originalImage = _viewportService?.CurrentDisplayImage as BitmapSource; + var image = _originalImage; + if (image == null) { ResultText = "请先加载图像"; return; } + + try + { + var processor = new VoidMeasurementProcessor(); + processor.SetParameter("MinThreshold", MinThreshold); + processor.SetParameter("MaxThreshold", MaxThreshold); + processor.SetParameter("MinVoidArea", MinVoidArea); + processor.SetParameter("MergeRadius", MergeRadius); + processor.SetParameter("BlurSize", BlurSize); + processor.SetParameter("VoidLimit", VoidLimit); + + // ROI 注入 + if (RoiEnabled && _roiShape != null && _roiShape.Points.Count >= 3) + { + int count = Math.Min(_roiShape.Points.Count, 32); + processor.SetParameter("PolyCount", count); + for (int i = 0; i < count; i++) + { + processor.SetParameter($"PolyX{i}", (int)_roiShape.Points[i].X); + processor.SetParameter($"PolyY{i}", (int)_roiShape.Points[i].Y); + } + } + + var grayImage = BitmapSourceToGray(image); + processor.Process(grayImage); + var output = processor.OutputData; + + ResultText = output.ContainsKey("ResultText") + ? output["ResultText"]?.ToString() ?? "--" + : "未检测到空隙"; + + // 填充结果表格 + Results.Clear(); + if (output.ContainsKey("Voids")) + { + var voids = output["Voids"] as List; + if (voids != null) + { + foreach (var v in voids) + { + Results.Add(new VoidResultItem + { + Index = v.Index, + CenterX = v.CenterX.ToString("F1"), + CenterY = v.CenterY.ToString("F1"), + Area = v.Area.ToString(), + AreaPercent = $"{v.AreaPercent:F2}%" + }); + } + } + } + + ResultImage = RenderResults(grayImage, output); + ShowResultOnOverlay(ResultImage); + grayImage.Dispose(); + } + catch (Exception ex) + { + ResultText = $"错误: {ex.Message}"; + } + } + + private void ShowResultOnOverlay(BitmapSource resultBmp) + { + if (_canvas == null) return; + RemoveResultOverlay(); + if (resultBmp == null) return; + + _resultOverlayImage = new System.Windows.Controls.Image + { + Source = resultBmp, + IsHitTestVisible = false, + Stretch = System.Windows.Media.Stretch.Fill + }; + _resultOverlayImage.SetBinding(System.Windows.FrameworkElement.WidthProperty, + new System.Windows.Data.Binding("CanvasWidth") { Source = _canvas }); + _resultOverlayImage.SetBinding(System.Windows.FrameworkElement.HeightProperty, + new System.Windows.Data.Binding("CanvasHeight") { Source = _canvas }); + + var mainCanvas = _canvas.FindName("mainCanvas") as System.Windows.Controls.Canvas; + if (mainCanvas != null) + { + int insertIndex = Math.Min(1, mainCanvas.Children.Count); + mainCanvas.Children.Insert(insertIndex, _resultOverlayImage); + } + } + + public void RemoveResultOverlay() + { + if (_resultOverlayImage == null || _canvas == null) return; + _canvas.RemoveFromCanvas(_resultOverlayImage); + _resultOverlayImage = null; + } + + private BitmapSource RenderResults(Image grayImage, IDictionary output) + { + if (!output.ContainsKey("VoidMeasurementResult")) return null; + int voidCount = (int)output["VoidCount"]; + if (voidCount == 0) return null; + + double voidRate = (double)output["VoidRate"]; + string classification = (string)output["Classification"]; + double voidLimitVal = (double)output["VoidLimit"]; + var voids = output["Voids"] as List; + + var colorImage = new Image(grayImage.Width, grayImage.Height); + CvInvoke.CvtColor(grayImage, colorImage, ColorConversion.Gray2Bgr); + + if (voids != null && voids.Count > 0) + { + // 半透明气泡填充 + var overlay = colorImage.Clone(); + foreach (var v in voids) + { + if (v.ContourPoints.Length > 0) + { + using var vop = new VectorOfPoint(v.ContourPoints); + using var vvop = new VectorOfVectorOfPoint(vop); + CvInvoke.DrawContours(overlay, vvop, 0, new MCvScalar(0, 200, 255), -1); + } + } + CvInvoke.AddWeighted(overlay, 0.4, colorImage, 0.6, 0, colorImage); + overlay.Dispose(); + + // 绘制轮廓 + 编号 + foreach (var v in voids) + { + if (v.ContourPoints.Length > 0) + { + using var vop = new VectorOfPoint(v.ContourPoints); + using var vvop = new VectorOfVectorOfPoint(vop); + CvInvoke.DrawContours(colorImage, vvop, 0, new MCvScalar(0, 255, 255), 1); + } + CvInvoke.PutText(colorImage, $"#{v.Index}", + new System.Drawing.Point((int)v.CenterX - 8, (int)v.CenterY + 5), + FontFace.HersheySimplex, 0.35, new MCvScalar(255, 100, 0), 1); + } + + // 左上角总览 + var overallColor = classification == "PASS" + ? new MCvScalar(0, 255, 0) : new MCvScalar(0, 0, 255); + CvInvoke.PutText(colorImage, + $"Void: {voidRate:F1}% | Limit: {voidLimitVal:F0}% | {voidCount} voids | {classification}", + new System.Drawing.Point(10, 25), + FontFace.HersheySimplex, 0.5, overallColor, 2); + } + + using var bitmap = colorImage.ToBitmap(); + var bmpSrc = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( + bitmap.GetHbitmap(), IntPtr.Zero, System.Windows.Int32Rect.Empty, + BitmapSizeOptions.FromEmptyOptions()); + bmpSrc.Freeze(); + colorImage.Dispose(); + return bmpSrc; + } + + private static void InsertPointToPolygon(Point newPoint, ObservableCollection points) + { + if (points.Count < 2) { points.Add(newPoint); return; } + int insertIndex = 0; + double minDistance = double.MaxValue; + double d = PointToSegmentDistance(points[points.Count - 1], points[0], newPoint); + if (d < minDistance) { minDistance = d; insertIndex = 0; } + for (int i = 1; i < points.Count; i++) + { + d = PointToSegmentDistance(points[i - 1], points[i], newPoint); + if (d < minDistance) { minDistance = d; insertIndex = i; } + } + points.Insert(insertIndex, newPoint); + } + + private static double PointToSegmentDistance(Point a, Point b, Point p) + { + double dx = b.X - a.X, dy = b.Y - a.Y; + double lenSq = dx * dx + dy * dy; + if (lenSq < 1e-10) return Math.Sqrt((p.X - a.X) * (p.X - a.X) + (p.Y - a.Y) * (p.Y - a.Y)); + double t = Math.Clamp(((p.X - a.X) * dx + (p.Y - a.Y) * dy) / lenSq, 0, 1); + double projX = a.X + t * dx, projY = a.Y + t * dy; + return Math.Sqrt((p.X - projX) * (p.X - projX) + (p.Y - projY) * (p.Y - projY)); + } + + private static Image BitmapSourceToGray(BitmapSource bmp) + { + var converted = new FormatConvertedBitmap(bmp, PixelFormats.Bgra32, null, 0); + int w = converted.PixelWidth, h = converted.PixelHeight; + int stride = w * 4; + var pixels = new byte[stride * h]; + converted.CopyPixels(pixels, stride, 0); + var gray = new Image(w, h); + for (int y = 0; y < h; y++) + for (int x = 0; x < w; x++) + { + int idx = y * stride + x * 4; + gray.Data[y, x, 0] = (byte)(pixels[idx + 2] * 0.299 + pixels[idx + 1] * 0.587 + pixels[idx] * 0.114); + } + return gray; + } + } + + public class VoidResultItem + { + public int Index { get; set; } + public string CenterX { get; set; } = ""; + public string CenterY { get; set; } = ""; + public string Area { get; set; } = ""; + public string AreaPercent { get; set; } = ""; + } +} diff --git a/XplorePlane/ViewModels/Main/MainViewModel.cs b/XplorePlane/ViewModels/Main/MainViewModel.cs index d2ed694..51ce60d 100644 --- a/XplorePlane/ViewModels/Main/MainViewModel.cs +++ b/XplorePlane/ViewModels/Main/MainViewModel.cs @@ -92,6 +92,7 @@ namespace XplorePlane.ViewModels public DelegateCommand ThroughHoleFillRateMeasureCommand { get; } public DelegateCommand BgaVoidMeasureCommand { get; } public DelegateCommand BgaDetectionCommand { get; } + public DelegateCommand VoidDetectionCommand { get; } public DelegateCommand BubbleMeasureCommand { get; } // 辅助线命令 @@ -203,6 +204,7 @@ namespace XplorePlane.ViewModels ThroughHoleFillRateMeasureCommand = new DelegateCommand(ExecuteThroughHoleFillRateMeasure); BgaVoidMeasureCommand = new DelegateCommand(ExecuteBgaVoidMeasure); BgaDetectionCommand = new DelegateCommand(ExecuteBgaDetection); + VoidDetectionCommand = new DelegateCommand(ExecuteVoidDetection); BubbleMeasureCommand = new DelegateCommand(ExecuteBubbleMeasure); // 辅助线命令 @@ -553,6 +555,26 @@ namespace XplorePlane.ViewModels _bgaDetectionPanel.Show(); } + private Window _voidDetectionPanel; + + private void ExecuteVoidDetection() + { + if (!CheckImageLoaded()) return; + _logger.Info("空隙检测功能已触发"); + + if (_voidDetectionPanel != null && _voidDetectionPanel.IsVisible) + { + _voidDetectionPanel.Activate(); + return; + } + + _voidDetectionPanel = new Views.ImageProcessing.VoidDetectionPanel + { + Owner = System.Windows.Application.Current.MainWindow + }; + _voidDetectionPanel.Show(); + } + private Window _bubbleMeasurePanel; private void ExecuteBubbleMeasure() diff --git a/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml b/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml new file mode 100644 index 0000000..71a9587 --- /dev/null +++ b/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml.cs b/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml.cs new file mode 100644 index 0000000..2f9e2b5 --- /dev/null +++ b/XplorePlane/Views/ImageProcessing/VoidDetectionPanel.xaml.cs @@ -0,0 +1,50 @@ +using System.Windows; +using Prism.Ioc; +using XP.ImageProcessing.RoiControl.Controls; +using XplorePlane.Services.MainViewport; +using XplorePlane.ViewModels.ImageProcessing; + +namespace XplorePlane.Views.ImageProcessing +{ + public partial class VoidDetectionPanel : Window + { + public VoidDetectionPanel() + { + InitializeComponent(); + var viewportService = ContainerLocator.Current?.Resolve(); + DataContext = new VoidDetectionViewModel(viewportService); + + Loaded += (s, e) => + { + var mainWin = Owner as MainWindow; + if (mainWin != null) + { + var canvas = FindChild(mainWin); + if (DataContext is VoidDetectionViewModel vm) + vm.SetCanvas(canvas); + } + }; + + Closed += (s, e) => + { + if (DataContext is VoidDetectionViewModel vm) + vm.RestoreContextMenu(); + }; + } + + private void Close_Click(object sender, RoutedEventArgs e) => Close(); + + private static T FindChild(DependencyObject parent) where T : DependencyObject + { + int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(parent); + for (int i = 0; i < count; i++) + { + var child = System.Windows.Media.VisualTreeHelper.GetChild(parent, i); + if (child is T t) return t; + var result = FindChild(child); + if (result != null) return result; + } + return null; + } + } +} diff --git a/XplorePlane/Views/Main/MainWindow.xaml b/XplorePlane/Views/Main/MainWindow.xaml index b83d2f6..9c168f5 100644 --- a/XplorePlane/Views/Main/MainWindow.xaml +++ b/XplorePlane/Views/Main/MainWindow.xaml @@ -353,11 +353,10 @@ Size="Large" SmallImage="/Assets/Icons/bga.png" /> From 3f034b34ae0342c68542f9d3f769e5893efbb43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Wed, 29 Apr 2026 13:54:00 +0800 Subject: [PATCH 15/17] =?UTF-8?q?XP.Camera:=E7=BB=99=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E6=A0=87=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E5=B8=83=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controls/CalibrationControl.xaml | 41 ++++++++++------ .../ChessboardCalibrationControl.xaml | 45 ++++++++++++------ XP.Camera/Calibration/Resources/保存结果.png | Bin 0 -> 1123 bytes XP.Camera/Calibration/Resources/加载数据.png | Bin 0 -> 1402 bytes XP.Camera/Calibration/Resources/外部导入.png | Bin 0 -> 759 bytes XP.Camera/Calibration/Resources/执行.png | Bin 0 -> 1931 bytes XP.Camera/Calibration/Resources/校准.png | Bin 0 -> 2447 bytes XP.Camera/Calibration/Resources/添加图像.png | Bin 0 -> 1299 bytes XP.Camera/Calibration/Resources/清空列表.png | Bin 0 -> 1297 bytes XP.Camera/XP.Camera.csproj | 4 ++ 10 files changed, 61 insertions(+), 29 deletions(-) create mode 100644 XP.Camera/Calibration/Resources/保存结果.png create mode 100644 XP.Camera/Calibration/Resources/加载数据.png create mode 100644 XP.Camera/Calibration/Resources/外部导入.png create mode 100644 XP.Camera/Calibration/Resources/执行.png create mode 100644 XP.Camera/Calibration/Resources/校准.png create mode 100644 XP.Camera/Calibration/Resources/添加图像.png create mode 100644 XP.Camera/Calibration/Resources/清空列表.png diff --git a/XP.Camera/Calibration/Controls/CalibrationControl.xaml b/XP.Camera/Calibration/Controls/CalibrationControl.xaml index 3fdb67c..7803ebf 100644 --- a/XP.Camera/Calibration/Controls/CalibrationControl.xaml +++ b/XP.Camera/Calibration/Controls/CalibrationControl.xaml @@ -19,9 +19,9 @@ + + + + + + + + + + + + + + + + + + + + + - - - + + - \ No newline at end of file + diff --git a/XplorePlane/Views/Setting/CameraSettingsWindow.xaml.cs b/XplorePlane/Views/Setting/CameraSettingsWindow.xaml.cs index e9f43f9..338c524 100644 --- a/XplorePlane/Views/Setting/CameraSettingsWindow.xaml.cs +++ b/XplorePlane/Views/Setting/CameraSettingsWindow.xaml.cs @@ -1,4 +1,5 @@ using System.Windows; +using System.Windows.Input; namespace XplorePlane.Views { @@ -9,5 +10,24 @@ namespace XplorePlane.Views InitializeComponent(); DataContext = viewModel; } + + private void ApplyAll_Click(object sender, RoutedEventArgs e) + { + var dc = DataContext; + if (dc == null) return; + var type = dc.GetType(); + ExecuteCommand(type, dc, "ApplyExposureCommand"); + ExecuteCommand(type, dc, "ApplyGainCommand"); + ExecuteCommand(type, dc, "ApplyWidthCommand"); + ExecuteCommand(type, dc, "ApplyHeightCommand"); + ExecuteCommand(type, dc, "ApplyPixelFormatCommand"); + } + + private static void ExecuteCommand(System.Type type, object dc, string cmdName) + { + var prop = type.GetProperty(cmdName); + if (prop?.GetValue(dc) is ICommand cmd && cmd.CanExecute(null)) + cmd.Execute(null); + } } -} \ No newline at end of file +} From a3155f8e4a54e16b4b83d856c99c65e64e63c8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=BC=9F?= Date: Wed, 29 Apr 2026 14:14:50 +0800 Subject: [PATCH 17/17] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=20HalfValueConverter?= =?UTF-8?q?=20=E5=88=B0=20Views/ImageProcessing=20=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- XplorePlane/Views/{ => ImageProcessing}/HalfValueConverter.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename XplorePlane/Views/{ => ImageProcessing}/HalfValueConverter.cs (100%) diff --git a/XplorePlane/Views/HalfValueConverter.cs b/XplorePlane/Views/ImageProcessing/HalfValueConverter.cs similarity index 100% rename from XplorePlane/Views/HalfValueConverter.cs rename to XplorePlane/Views/ImageProcessing/HalfValueConverter.cs