2 * calculations.c: calculations needed by the input devices
4 * See the README file for copyright information and how to reach the author.
18 #include "AtmoCalculations.h"
19 #include "AtmoConfig.h"
20 #include "AtmoZoneDefinition.h"
23 // set accuracy of color calculation
29 #define POS_DIV(a, b) ( (a)/(b) + ( ((a)%(b) >= (b)/2 ) ? 1 : 0) )
32 CAtmoColorCalculator::CAtmoColorCalculator(CAtmoConfig *pAtmoConfig)
34 m_pAtmoConfig = pAtmoConfig;
37 m_windowed_hue_hist = NULL;
38 m_most_used_hue_last = NULL;
39 m_most_used_hue = NULL;
41 m_windowed_sat_hist = NULL;
42 m_most_used_sat = NULL;
43 m_Zone_Weights = NULL;
45 m_average_counter = NULL;
47 m_LastEdgeWeighting = -1;
48 m_LastWidescreenMode = -1;
49 m_LastLayout_TopCount = -1;
50 m_LastLayout_BottomCount = -1;
51 m_LastLayout_LRCount = -1;
55 CAtmoColorCalculator::~CAtmoColorCalculator(void)
59 delete[] m_windowed_hue_hist;
60 delete[] m_most_used_hue_last;
61 delete[] m_most_used_hue;
63 delete[] m_windowed_sat_hist;
64 delete[] m_most_used_sat;
65 delete[] m_Zone_Weights;
67 delete[] m_average_counter;
70 void CAtmoColorCalculator::UpdateParameters()
72 // Zonen Definition neu laden
73 // diverse Vorberechnungen neu ausführen
74 // Speicherbuffer neu allokieren!
77 void CAtmoColorCalculator::FindMostUsed(int AtmoSetup_NumZones,int *most_used,long int *windowed_hist)
79 memset(most_used, 0, sizeof(int) * AtmoSetup_NumZones);
82 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
85 // walk trough histogram
86 for (int i = 0; i < s_MAX+1; i++) // assume s_MAX = h_MAX = v_Max
88 // if new value bigger then old one
89 int tmp = *windowed_hist; // windowed_hist[zone * (s_MAX+1) + i];
90 // if (w_sat_hist[channel][i] > value)
103 pColorPacket CAtmoColorCalculator::AnalyzeHSV(tHSVColor *HSV_Img)
107 int AtmoSetup_EdgeWeighting = m_pAtmoConfig->getLiveView_EdgeWeighting();
108 int AtmoSetup_WidescreenMode = m_pAtmoConfig->getLiveView_WidescreenMode();
109 int AtmoSetup_DarknessLimit = m_pAtmoConfig->getLiveView_DarknessLimit();
110 int AtmoSetup_BrightCorrect = m_pAtmoConfig->getLiveView_BrightCorrect();
111 int AtmoSetup_SatWinSize = m_pAtmoConfig->getLiveView_SatWinSize();
112 int AtmoSetup_NumZones = m_pAtmoConfig->getZoneCount();
115 if(AtmoSetup_NumZones != m_LastNumZones)
119 delete[] m_windowed_hue_hist;
120 delete[] m_most_used_hue_last;
121 delete[] m_most_used_hue;
123 delete[] m_windowed_sat_hist;
124 delete[] m_most_used_sat;
125 delete[] m_Zone_Weights;
126 delete[] m_average_v;
127 delete[] m_average_counter;
129 m_Weight = new int[AtmoSetup_NumZones * IMAGE_SIZE];
130 m_Zone_Weights = new int*[AtmoSetup_NumZones];
131 for(int i = 0; i < AtmoSetup_NumZones; i++)
132 m_Zone_Weights[i] = &m_Weight[i * IMAGE_SIZE];
134 m_hue_hist = new long int[(h_MAX+1) * AtmoSetup_NumZones];
135 m_windowed_hue_hist = new long int[(h_MAX+1) * AtmoSetup_NumZones];
137 m_most_used_hue_last = new int[AtmoSetup_NumZones];
138 m_most_used_hue = new int[AtmoSetup_NumZones];
139 memset( m_most_used_hue_last, 0, sizeof(int) * AtmoSetup_NumZones);
141 m_sat_hist = new long int[(s_MAX+1) * AtmoSetup_NumZones];
142 m_windowed_sat_hist = new long int[(s_MAX+1) * AtmoSetup_NumZones];
143 m_most_used_sat = new int[AtmoSetup_NumZones];
145 m_average_v = new long int[AtmoSetup_NumZones];
146 m_average_counter = new int[AtmoSetup_NumZones];
148 m_LastNumZones = AtmoSetup_NumZones;
152 // calculate only if setup has changed
153 if ((AtmoSetup_EdgeWeighting != m_LastEdgeWeighting) ||
154 (AtmoSetup_WidescreenMode != m_LastWidescreenMode) ||
155 (m_pAtmoConfig->getZonesTopCount() != m_LastLayout_TopCount) ||
156 (m_pAtmoConfig->getZonesBottomCount() != m_LastLayout_BottomCount) ||
157 (m_pAtmoConfig->getZonesLRCount() != m_LastLayout_LRCount) ||
158 (m_pAtmoConfig->m_UpdateEdgeWeightningFlag != 0)
162 for(i = 0 ;i < AtmoSetup_NumZones; i++) {
163 CAtmoZoneDefinition *pZoneDef = m_pAtmoConfig->getZoneDefinition(i);
166 pZoneDef->UpdateWeighting(m_Zone_Weights[i],
167 AtmoSetup_WidescreenMode,
168 AtmoSetup_EdgeWeighting);
169 #ifdef _debug_zone_weight_
171 sprintf(filename, "zone_%d_gradient_debug.bmp",i);
172 pZoneDef->SaveZoneBitmap( filename );
173 sprintf(filename, "zone_%d_weight_%d_debug.bmp",i,AtmoSetup_EdgeWeighting);
174 pZoneDef->SaveWeightBitmap(filename, m_Zone_Weights[i] );
179 m_pAtmoConfig->m_UpdateEdgeWeightningFlag = 0;
181 m_LastEdgeWeighting = AtmoSetup_EdgeWeighting;
182 m_LastWidescreenMode = AtmoSetup_WidescreenMode;
183 m_LastLayout_TopCount = m_pAtmoConfig->getZonesTopCount();
184 m_LastLayout_BottomCount = m_pAtmoConfig->getZonesBottomCount();
185 m_LastLayout_LRCount = m_pAtmoConfig->getZonesLRCount();
188 AtmoSetup_DarknessLimit = AtmoSetup_DarknessLimit * 10;
191 /***************************************************************************/
193 /***************************************************************************/
194 /*----------------------------*/
195 /* hue histogram builtup */
196 /*----------------------------*/
198 // long int hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1];
200 // average brightness (value)
201 // m_average_v m_average_counter
203 // clean histogram --> calloc
204 memset(m_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
205 memset(m_average_v, 0, sizeof(long int) * AtmoSetup_NumZones);
206 memset(m_average_counter, 0, sizeof(int) * AtmoSetup_NumZones);
210 for (int row = 0; row < CAP_HEIGHT; row++)
212 for (int column = 0; column < CAP_WIDTH; column++)
214 // forget black bars: perform calculations only if pixel has some luminosity
215 if ((*temp_Img).v > AtmoSetup_DarknessLimit)
217 // builtup histogram for the x Zones of the Display
218 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
220 // Add weight to channel
221 // Weight(zone, pixel_nummer) m_Weight[((zone) * (IMAGE_SIZE)) + (pixel_nummer)]
222 // m_hue_hist[zone*(h_MAX+1) + HSV_Img[i].h] += m_Zone_Weights[zone][i] * HSV_Img[i].v;
223 m_hue_hist[zone*(h_MAX+1) + (*temp_Img).h] += m_Zone_Weights[zone][i] * temp_Img->v;
225 if(m_Zone_Weights[zone][i] > 0) {
226 m_average_v[zone] += temp_Img->v;
227 m_average_counter[zone]++;
231 // calculate brightness average
238 /*----------------------------*/
239 /* hue histogram windowing */
240 /*----------------------------*/
241 // windowed HSV histogram
242 // long int w_hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1]; -> m_windowed_hue_hist
243 // clean windowed histogram
244 memset(m_windowed_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
245 // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
246 int hue_windowsize = m_pAtmoConfig->getLiveView_HueWinSize();
248 for (i = 0; i < h_MAX+1; i++) // walk through histogram [0;h_MAX]
250 // windowing from -hue_windowsize -> +hue_windowsize
251 for (int mywin = -hue_windowsize; mywin < hue_windowsize+1; mywin++)
253 // addressed histogram candlestick
254 int myidx = i + mywin;
256 // handle beginning of windowing -> roll back
257 if (myidx < 0) { myidx = myidx + h_MAX + 1; }
259 // handle end of windowing -> roll forward
260 if (myidx > h_MAX) { myidx = myidx - h_MAX - 1; }
262 // Apply windowing to all x zones
263 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
265 // apply lite triangular window design with gradient of 10% per discrete step
266 m_windowed_hue_hist[(zone * (h_MAX+1)) + i] += m_hue_hist[(zone * (h_MAX+1)) + myidx] * ((hue_windowsize+1)-abs(mywin)); // apply window
271 /*--------------------------------------*/
272 /* analyze histogram for most used hue */
273 /*--------------------------------------*/
274 // index of last maximum
275 // static int most_used_hue_last[CAP_MAX_NUM_ZONES] = {0, 0, 0, 0, 0}; --> m_most_used_hue_last
277 // resulting hue for each channel
278 //int most_used_hue[CAP_MAX_NUM_ZONES]; --> m_most_used_hue
280 FindMostUsed(AtmoSetup_NumZones, m_most_used_hue, m_windowed_hue_hist);
281 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
283 float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue[zone]];
284 if (percent > 0.93f) // less than 7% difference?
285 m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
287 m_most_used_hue_last[zone] = m_most_used_hue[zone];
291 memset(m_most_used_hue, 0, sizeof(int) * AtmoSetup_NumZones);
293 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
296 for (i = 0; i < h_MAX+1; i++) // walk through histogram
298 long int tmp = m_windowed_hue_hist[ (zone * (h_MAX+1)) + i ];
299 if (tmp > value) // if new value bigger then old one
301 m_most_used_hue[zone] = i; // remember index
302 value = tmp; // w_hue_hist[zone][i]; // and value
306 float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)value;
307 if (percent > 0.93f) // less than 7% difference?
309 m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
312 m_most_used_hue_last[zone] = m_most_used_hue[zone]; // save current index of most used hue
316 /***************************************************************************/
318 /***************************************************************************/
320 // long int sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; -> m_sat_hist
321 // hue of the pixel we are working at
324 memset(m_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
326 /*--------------------------------------*/
327 /* saturation histogram builtup */
328 /*--------------------------------------*/
331 for (int row = 0; row < CAP_HEIGHT; row++)
333 for (int column = 0; column < CAP_WIDTH; column++)
335 // forget black bars: perform calculations only if pixel has some luminosity
336 if ((*temp_Img).v > AtmoSetup_DarknessLimit)
338 // find histogram position for pixel
339 pixel_hue = (*temp_Img).h;
341 // TODO: brightness calculation(if we require it some time)
343 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
345 // only use pixel for histogram if hue is near most_used_hue
346 if ((pixel_hue > m_most_used_hue[zone] - hue_windowsize) &&
347 (pixel_hue < m_most_used_hue[zone] + hue_windowsize))
350 // sat_hist[channel][HSV_Img[i].s] += Weight[i].channel[channel] * HSV_Img[i].v;
351 m_sat_hist[zone * (s_MAX+1) + (*temp_Img).s ] += m_Zone_Weights[zone][i] * (*temp_Img).v;
361 /*--------------------------------------*/
362 /* saturation histogram windowing */
363 /*--------------------------------------*/
364 // windowed HSV histogram
365 // long int w_sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; --> m_windowed_sat_hist
366 // clean windowed histogram
367 memset(m_windowed_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
368 // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
369 int sat_windowsize = AtmoSetup_SatWinSize;
371 // walk through histogram [0;h_MAX]
372 for (i = 0; i < s_MAX + 1; i++)
374 // windowing from -hue_windowsize -> +hue_windowsize
375 for (int mywin = -sat_windowsize; mywin < sat_windowsize+1; mywin++)
377 // addressed histogram candlestick
378 int myidx = i + mywin;
380 // handle beginning of windowing -> roll back
381 if (myidx < 0) { myidx = myidx + s_MAX + 1; }
383 // handle end of windowing -> roll forward
384 if (myidx > h_MAX) { myidx = myidx - s_MAX - 1; }
386 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
389 apply lite triangular window design with
390 gradient of 10% per discrete step
393 w_sat_hist[channel][i] += sat_hist[channel][myidx] *
394 ((sat_windowsize+1)-abs(mywin)); // apply window
396 m_windowed_sat_hist[zone * (s_MAX+1) + i] += m_sat_hist[zone* (h_MAX+1) + myidx] *
397 ((sat_windowsize+1)-abs(mywin)); // apply window
402 /*--------------------------------------*/
403 /* analyze histogram for most used sat */
404 /*--------------------------------------*/
405 // resulting sat (most_used_hue) for each channel
406 // int most_used_sat[CAP_MAX_NUM_ZONES];->m_most_used_sat
408 FindMostUsed(AtmoSetup_NumZones, m_most_used_sat, m_windowed_sat_hist);
410 memset(m_most_used_sat, 0, sizeof(int) * AtmoSetup_NumZones);
412 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
415 // walk trough histogram
416 for (i = 0; i < s_MAX+1; i++)
418 // if new value bigger then old one
419 int tmp = m_windowed_sat_hist[zone * (s_MAX+1) + i];
420 // if (w_sat_hist[channel][i] > value)
424 m_most_used_sat[zone] = i;
433 /*----------------------------------------------------------*/
434 /* calculate average brightness within HSV image */
435 /* uniform Brightness for all channels is calculated */
436 /*----------------------------------------------------------*/
437 /* code integrated into "hue histogram builtup" to save some looping time!
439 // average brightness (value)
440 long int value_avg = 0;
442 for (int row = 0; row < CAP_HEIGHT; row++)
444 for (int column = 0; column < CAP_WIDTH; column++)
446 // find average value: only use bright pixels for luminance average
447 if (HSV_Img[i].v > AtmoSetup_DarknessLimit)
449 // build brightness average
450 value_avg += HSV_Img[i].v;
456 // calculate brightness average
457 if (l_counter > 0) { value_avg = value_avg / l_counter; }
458 else { value_avg = AtmoSetup_DarknessLimit; }
463 /*----------------------------*/
464 /* adjust and copy results */
465 /*----------------------------*/
467 // storage container for resulting RGB values
468 pColorPacket output_colors;
469 AllocColorPacket(output_colors, AtmoSetup_NumZones);
472 // int new_value = (int) ((float)value_avg * ((float)AtmoSetup_BrightCorrect / 100.0));
473 // if (new_value > 255) new_value = 255; // ensure brightness isn't set too high
474 // hsv_pixel.v = (unsigned char)new_value;
477 // calculate brightness average
478 for(int zone = 0; zone < AtmoSetup_NumZones; zone++) {
479 if(m_average_counter[zone] > 0)
480 m_average_v[zone] = m_average_v[zone] / m_average_counter[zone]
482 m_average_v[zone] = AtmoSetup_DarknessLimit;
487 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
489 if(m_average_counter[zone] > 0)
490 m_average_v[zone] = m_average_v[zone] / m_average_counter[zone];
492 m_average_v[zone] = AtmoSetup_DarknessLimit;
494 m_average_v[zone] = (int)((float)m_average_v[zone] * ((float)AtmoSetup_BrightCorrect / 100.0));
496 hsv_pixel.v = (unsigned char)ATMO_MAX(ATMO_MIN(m_average_v[zone],255),0);
497 hsv_pixel.h = m_most_used_hue[zone];
498 hsv_pixel.s = m_most_used_sat[zone];
500 // convert back to rgb
501 output_colors->zone[zone] = HSV2RGB(hsv_pixel);
505 return output_colors;
508 tHSVColor RGB2HSV(tRGBColor color)
519 min = ATMO_MIN(ATMO_MIN(r, g), b);
520 max = ATMO_MAX(ATMO_MAX(r, g), b);
524 hsv.v = (unsigned char) POS_DIV( max*v_MAX, 255 );
526 if (delta == 0) // This is a gray, no chroma...
528 h = 0; // HSV results = 0 / 1
531 else // Chromatic data...
533 hsv.s = (unsigned char) POS_DIV( (delta*s_MAX) , max );
535 int dr = (max - r) + 3*delta;
536 int dg = (max - g) + 3*delta;
537 int db = (max - b) + 3*delta;
538 int divisor = 6*delta;
542 h = POS_DIV(( (db - dg) * h_MAX ) , divisor);
546 h = POS_DIV( ((dr - db) * h_MAX) , divisor) + (h_MAX/3);
550 h = POS_DIV(( (dg - dr) * h_MAX) , divisor) + (h_MAX/3)*2;
553 if ( h < 0 ) { h += h_MAX; }
554 if ( h > h_MAX ) { h -= h_MAX; }
556 hsv.h = (unsigned char)h;
561 tRGBColor HSV2RGB(tHSVColor color)
563 tRGBColor rgb = {0, 0, 0};
565 float h = (float)color.h/(float)h_MAX;
566 float s = (float)color.s/(float)s_MAX;
567 float v = (float)color.v/(float)v_MAX;
571 rgb.r = (int)((v*255.0)+0.5);
578 if (h == 6.0) { h = 0.0; }
582 float p = v*(1.0f-s);
583 float q = v*(1.0f-(s*f));
584 float t = v*(1.0f-(s*(1.0f-f)));
588 rgb.r = (int)((v*255.0)+0.5);
589 rgb.g = (int)((t*255.0)+0.5);
590 rgb.b = (int)((p*255.0)+0.5);
594 rgb.r = (int)((q*255.0)+0.5);
595 rgb.g = (int)((v*255.0)+0.5);
596 rgb.b = (int)((p*255.0)+0.5);
600 rgb.r = (int)((p*255.0)+0.5);
601 rgb.g = (int)((v*255.0)+0.5);
602 rgb.b = (int)((t*255.0)+0.5);
606 rgb.r = (int)((p*255.0)+0.5);
607 rgb.g = (int)((q*255.0)+0.5);
608 rgb.b = (int)((v*255.0)+0.5);
612 rgb.r = (int)((t*255.0)+0.5);
613 rgb.g = (int)((p*255.0)+0.5);
614 rgb.b = (int)((v*255.0)+0.5);
618 rgb.r = (int)((v*255.0)+0.5);
619 rgb.g = (int)((p*255.0)+0.5);
620 rgb.b = (int)((q*255.0)+0.5);