source: other-projects/playing-in-the-street/summer-2013/trunk/Playing-in-the-Street-WPF/Microsoft.Samples.Kinect.Webserver/Sensor/UserViewerColorizer.cs@ 28897

Last change on this file since 28897 was 28897, checked in by davidb, 10 years ago

GUI front-end to server base plus web page content

File size: 9.3 KB
Line 
1// -----------------------------------------------------------------------
2// <copyright file="UserViewerColorizer.cs" company="Microsoft">
3// Copyright (c) Microsoft Corporation. All rights reserved.
4// </copyright>
5// -----------------------------------------------------------------------
6
7namespace Microsoft.Samples.Kinect.Webserver.Sensor
8{
9 using System;
10 using System.Collections.Generic;
11 using System.Diagnostics;
12 using System.Globalization;
13
14 using Microsoft.Kinect;
15 using Microsoft.Kinect.Toolkit.Interaction;
16
17 /// <summary>
18 /// Colorizes a depth image according to desired size and color mapping.
19 /// </summary>
20 internal class UserViewerColorizer
21 {
22 /// <summary>
23 /// Number of bytes per pixel in colorized image.
24 /// </summary>
25 private const int BytesPerPixel = 4;
26
27 /// <summary>
28 /// Background color is always transparent.
29 /// </summary>
30 private const int BackgroundColor = 0x00000000;
31
32 /// <summary>
33 /// Lookup table mapping player indexes (observable in depth image pixels) to 32-bit
34 /// ARGB color.
35 /// </summary>
36 private readonly int[] playerColorLookupTable;
37
38 /// <summary>
39 /// Initializes a new instance of the <see cref="UserViewerColorizer"/> class.
40 /// </summary>
41 /// <param name="width">
42 /// Desired width of colorized image.
43 /// </param>
44 /// <param name="height">
45 /// Desired height of colorized image.
46 /// </param>
47 public UserViewerColorizer(int width, int height)
48 {
49 this.playerColorLookupTable = new int[SharedConstants.MaxUsersTracked + 1];
50
51 this.SetResolution(width, height);
52 }
53
54 /// <summary>
55 /// Desired width of colorized image.
56 /// </summary>
57 public int Width { get; private set; }
58
59 /// <summary>
60 /// Desired height of colorized image.
61 /// </summary>
62 public int Height { get; private set; }
63
64 /// <summary>
65 /// Buffer that holds colorized image.
66 /// </summary>
67 public byte[] Buffer { get; private set; }
68
69 /// <summary>
70 /// Updates the desired resolution for user viewer image.
71 /// </summary>
72 /// <param name="width">
73 /// Desired width of colorized image.
74 /// </param>
75 /// <param name="height">
76 /// Desired height of colorized image.
77 /// </param>
78 public void SetResolution(int width, int height)
79 {
80 if ((this.Buffer == null) || (this.Width != width) || (this.Height != height))
81 {
82 this.Width = width;
83 this.Height = height;
84
85 this.Buffer = new byte[width * height * BytesPerPixel];
86 }
87 }
88
89 /// <summary>
90 /// Color the user viewer image pixels appropriately given the specified depth image.
91 /// </summary>
92 /// <param name="depthImagePixels">
93 /// Depth image from which we will colorize user viewer image.
94 /// </param>
95 /// <param name="depthWidth">
96 /// Width of depth image, in pixels.
97 /// </param>
98 /// <param name="depthHeight">
99 /// Height of depth image, in pixels.
100 /// </param>
101 public void ColorizeDepthPixels(DepthImagePixel[] depthImagePixels, int depthWidth, int depthHeight)
102 {
103 if (depthImagePixels == null)
104 {
105 throw new ArgumentNullException("depthImagePixels");
106 }
107
108 if (depthWidth <= 0)
109 {
110 throw new ArgumentException(@"Width of depth image must be greater than zero", "depthWidth");
111 }
112
113 if (depthWidth % this.Width != 0)
114 {
115 throw new ArgumentException(
116 string.Format(
117 CultureInfo.InvariantCulture,
118 "Depth image width '{0}' is not a multiple of the desired user viewer image width '{1}'",
119 depthWidth,
120 this.Width),
121 "depthWidth");
122 }
123
124 if (depthHeight <= 0)
125 {
126 throw new ArgumentException(@"Height of depth image must be greater than zero", "depthHeight");
127 }
128
129 if (depthHeight % this.Height != 0)
130 {
131 throw new ArgumentException(
132 string.Format(
133 CultureInfo.InvariantCulture,
134 "Depth image height '{0}' is not a multiple of the desired user viewer image height '{1}'",
135 depthHeight,
136 this.Height),
137 "depthHeight");
138 }
139
140 int downscaleFactor = depthWidth / this.Width;
141 Debug.Assert(depthHeight / this.Height == downscaleFactor, "Downscale factor in x and y dimensions should be exactly the same.");
142
143 int pixelDisplacementBetweenRows = depthWidth * downscaleFactor;
144
145 unsafe
146 {
147 fixed (byte* colorBufferPtr = this.Buffer)
148 {
149 fixed (DepthImagePixel* depthImagePixelPtr = depthImagePixels)
150 {
151 fixed (int* playerColorLookupPtr = this.playerColorLookupTable)
152 {
153 // Write color values using int pointers instead of byte pointers,
154 // since each color pixel is 32-bits wide.
155 int* colorBufferIntPtr = (int*)colorBufferPtr;
156 DepthImagePixel* currentPixelRowPtr = depthImagePixelPtr;
157
158 for (int row = 0; row < depthHeight; row += downscaleFactor)
159 {
160 DepthImagePixel* currentPixelPtr = currentPixelRowPtr;
161 for (int column = 0; column < depthWidth; column += downscaleFactor)
162 {
163 *colorBufferIntPtr++ = playerColorLookupPtr[currentPixelPtr->PlayerIndex];
164 currentPixelPtr += downscaleFactor;
165 }
166
167 currentPixelRowPtr += pixelDisplacementBetweenRows;
168 }
169 }
170 }
171 }
172 }
173 }
174
175 /// <summary>
176 /// Reset the lookup table mapping user indexes (observable in depth image pixels)
177 /// to 32-bit ARGB color to map all indexes to background color.
178 /// </summary>
179 public void ResetColorLookupTable()
180 {
181 // Initialize all player indexes to background color
182 for (int entryIndex = 0; entryIndex < this.playerColorLookupTable.Length; ++entryIndex)
183 {
184 this.playerColorLookupTable[entryIndex] = BackgroundColor;
185 }
186 }
187
188 /// <summary>
189 /// Update the lookup table mapping user indexes (observable in depth image pixels)
190 /// to 32-bit ARGB color.
191 /// </summary>
192 /// <param name="userInfos">
193 /// User information obtained from an <see cref="InteractionFrame"/>.
194 /// </param>
195 /// <param name="defaultUserColor">
196 /// 32-bit ARGB representation of default color assigned to users.
197 /// </param>
198 /// <param name="userStates">
199 /// Mapping between user tracking IDs and user states (obtained from
200 /// <see cref="IUserStateManager"/>).
201 /// </param>
202 /// <param name="userColors">
203 /// Mapping between user states and 32-bit ARGB color.
204 /// </param>
205 public void UpdateColorLookupTable(UserInfo[] userInfos, int defaultUserColor, IDictionary<int, string> userStates, IDictionary<string, int> userColors)
206 {
207 if ((userInfos == null) || (userStates == null) || (userColors == null))
208 {
209 this.ResetColorLookupTable();
210 return;
211 }
212
213 // Reset lookup table to have all player indexes map to default user color
214 for (int i = 1; i < this.playerColorLookupTable.Length; i++)
215 {
216 this.playerColorLookupTable[i] = defaultUserColor;
217 }
218
219 // Iterate through user tracking Ids to populate color table.
220 for (int i = 0; i < userInfos.Length; ++i)
221 {
222 // Player indexes in depth image are shifted by one in order to be able to
223 // use zero as a marker to mean "pixel does not correspond to any player".
224 int depthPlayerIndex = i + 1;
225 var trackingId = userInfos[i].SkeletonTrackingId;
226
227 string state;
228 if (userStates.TryGetValue(trackingId, out state))
229 {
230 int color;
231 if (userColors.TryGetValue(state, out color))
232 {
233 this.playerColorLookupTable[depthPlayerIndex] = color;
234 }
235 }
236 }
237 }
238 }
239}
Note: See TracBrowser for help on using the repository browser.