1+ using System . Collections . Concurrent ;
2+ using System . Threading ;
13using OpenCvSharp . Internal ;
24
35// ReSharper disable UnusedMember.Local
@@ -11,10 +13,10 @@ public sealed class Window : IDisposable
1113{
1214 #region Field
1315
14- internal static Dictionary < string , Window > Windows = new ( ) ;
15- private static uint windowCount ;
16+ internal static readonly ConcurrentDictionary < string , Window > Windows = new ( ) ;
17+ private static int windowCount ;
1618
17- private string name ;
19+ private readonly string name ;
1820 private Mat ? image ;
1921 // ReSharper disable once IdentifierTypo
2022 private readonly Dictionary < string , CvTrackbar > trackbars ;
@@ -31,36 +33,6 @@ public Window()
3133 {
3234 }
3335
34- /// <summary>
35- /// Creates a window
36- /// </summary>
37- /// <param name="name">Name of the window which is used as window identifier and appears in the window caption. </param>
38- public Window ( string name )
39- : this ( name , null , WindowFlags . AutoSize )
40- {
41- }
42-
43- /// <summary>
44- /// Creates a window
45- /// </summary>
46- /// <param name="name">Name of the window which is used as window identifier and appears in the window caption. </param>
47- /// <param name="flags">Flags of the window. Currently the only supported flag is WindowMode.AutoSize.
48- /// If it is set, window size is automatically adjusted to fit the displayed image (see cvShowImage), while user can not change the window size manually. </param>
49- public Window ( string name , WindowFlags flags = WindowFlags . AutoSize )
50- : this ( name , null , flags )
51- {
52- }
53-
54- /// <summary>
55- /// Creates a window
56- /// </summary>
57- /// <param name="name">Name of the window which is used as window identifier and appears in the window caption. </param>
58- /// <param name="image">Image to be shown.</param>
59- public Window ( string name , Mat image )
60- : this ( name , image ?? throw new ArgumentNullException ( nameof ( image ) ) , WindowFlags . AutoSize )
61- {
62- }
63-
6436 /// <summary>
6537 /// Creates a window
6638 /// </summary>
@@ -82,8 +54,7 @@ public Window(string name, Mat? image = null, WindowFlags flags = WindowFlags.Au
8254
8355 trackbars = new Dictionary < string , CvTrackbar > ( ) ;
8456
85- if ( ! Windows . ContainsKey ( name ) )
86- Windows . Add ( name , this ) ;
57+ Windows [ name ] = this ;
8758 }
8859
8960 /// <summary>
@@ -92,7 +63,7 @@ public Window(string name, Mat? image = null, WindowFlags flags = WindowFlags.Au
9263 /// <returns></returns>
9364 private static string DefaultName ( )
9465 {
95- return $ "window{ windowCount ++ } ";
66+ return $ "window{ Interlocked . Increment ( ref windowCount ) - 1 } ";
9667 }
9768
9869 /// <summary>
@@ -109,7 +80,9 @@ public void Dispose()
10980 return ;
11081 IsDisposed = true ;
11182
112- Windows . Remove ( name ) ;
83+ // Only remove the map entry if it still points at this instance: another Window may have
84+ // since reused the same name (see the constructor), and that instance's entry must survive.
85+ ( ( ICollection < KeyValuePair < string , Window > > ) Windows ) . Remove ( new KeyValuePair < string , Window > ( name , this ) ) ;
11386 trackbars . Clear ( ) ;
11487
11588 // Destroying the window also releases OpenCV's references to its mouse/trackbar
@@ -150,11 +123,7 @@ public Mat? Image
150123 /// <summary>
151124 /// Gets window name
152125 /// </summary>
153- public string Name
154- {
155- get => name ;
156- private set => name = value ;
157- }
126+ public string Name => name ;
158127
159128 #endregion
160129
@@ -169,7 +138,7 @@ public string Name
169138 public CvTrackbar CreateTrackbar ( string trackbarName , TrackbarCallback callback )
170139 {
171140 var trackbar = new CvTrackbar ( trackbarName , name , callback ) ;
172- trackbars . Add ( trackbarName , trackbar ) ;
141+ trackbars [ trackbarName ] = trackbar ;
173142 return trackbar ;
174143 }
175144
@@ -183,8 +152,8 @@ public CvTrackbar CreateTrackbar(string trackbarName, TrackbarCallback callback)
183152 /// <returns></returns>
184153 public CvTrackbar CreateTrackbar ( string trackbarName , int initialPos , int max , TrackbarCallback callback )
185154 {
186- var trackbar = new CvTrackbar ( trackbarName , name , initialPos , max , callback ) ;
187- trackbars . Add ( trackbarName , trackbar ) ;
155+ var trackbar = new CvTrackbar ( trackbarName , name , callback , initialPos , max ) ;
156+ trackbars [ trackbarName ] = trackbar ;
188157 return trackbar ;
189158 }
190159
@@ -290,52 +259,36 @@ public static void ShowImages(params Mat[] images)
290259 {
291260 if ( images is null )
292261 throw new ArgumentNullException ( nameof ( images ) ) ;
293- if ( images . Length == 0 )
294- return ;
295262
296- var windows = new List < Window > ( ) ;
297- foreach ( var img in images )
298- {
299- windows . Add ( new Window { Image = img } ) ;
300- }
301-
302- WaitKey ( ) ;
303-
304- foreach ( var w in windows )
305- {
306- w . Close ( ) ;
307- }
263+ ShowImagesAndWaitKey ( images . Select ( img => new Window { Image = img } ) ) ;
308264 }
309265
310266 /// <summary>
311- ///
267+ /// Shows each of the given (title, image) pairs in its own window.
268+ /// Pairing each title with its image in a single tuple makes a length mismatch
269+ /// between titles and images structurally impossible.
312270 /// </summary>
313- /// <param name="images"></param>
314- /// <param name="names"></param>
315- public static void ShowImages ( IEnumerable < Mat > images , IEnumerable < string > names )
271+ /// <param name="images">Pairs of window title and image to display</param>
272+ public static void ShowImages ( params ( string Title , Mat Image ) [ ] images )
316273 {
317274 if ( images is null )
318275 throw new ArgumentNullException ( nameof ( images ) ) ;
319- if ( names is null )
320- throw new ArgumentNullException ( nameof ( names ) ) ;
321276
322- var imagesArray = images . ToArray ( ) ;
323- var namesArray = names . ToArray ( ) ;
277+ ShowImagesAndWaitKey ( images . Select ( t => new Window ( t . Title , image : t . Image ) ) ) ;
278+ }
324279
325- if ( imagesArray . Length == 0 )
280+ /// <summary>
281+ /// Opens the given windows, blocks until a key is pressed, then closes them all.
282+ /// </summary>
283+ private static void ShowImagesAndWaitKey ( IEnumerable < Window > windows )
284+ {
285+ var windowList = windows . ToList ( ) ;
286+ if ( windowList . Count == 0 )
326287 return ;
327- if ( namesArray . Length < imagesArray . Length )
328- throw new ArgumentException ( "names.Length < images.Length" ) ;
329288
330- var windows = new List < Window > ( ) ;
331- for ( var i = 0 ; i < imagesArray . Length ; i ++ )
332- {
333- windows . Add ( new Window ( namesArray [ i ] , image : imagesArray [ i ] ) ) ;
334- }
335-
336- Cv2 . WaitKey ( ) ;
289+ WaitKey ( ) ;
337290
338- foreach ( var w in windows )
291+ foreach ( var w in windowList )
339292 {
340293 w . Close ( ) ;
341294 }
0 commit comments