2 * calculations.c: calculations needed by the input devices
4 * See the README file for copyright information and how to reach the author.
23 #include "AtmoCalculations.h"
24 #include "AtmoConfig.h"
25 #include "AtmoZoneDefinition.h"
28 // set accuracy of color calculation
34 #define POS_DIV(a, b) ( (a)/(b) + ( ((a)%(b) >= (b)/2 ) ? 1 : 0) )
37 CAtmoColorCalculator::CAtmoColorCalculator(CAtmoConfig *pAtmoConfig)
39 m_pAtmoConfig = pAtmoConfig;
42 m_windowed_hue_hist = NULL;
43 m_most_used_hue_last = NULL;
44 m_most_used_hue = NULL;
46 m_windowed_sat_hist = NULL;
47 m_most_used_sat = NULL;
48 m_Zone_Weights = NULL;
50 m_average_counter = NULL;
52 m_LastEdgeWeighting = -1;
53 m_LastWidescreenMode = -1;
54 m_LastLayout_TopCount = -1;
55 m_LastLayout_BottomCount = -1;
56 m_LastLayout_LRCount = -1;
60 CAtmoColorCalculator::~CAtmoColorCalculator(void)
64 delete[] m_windowed_hue_hist;
65 delete[] m_most_used_hue_last;
66 delete[] m_most_used_hue;
68 delete[] m_windowed_sat_hist;
69 delete[] m_most_used_sat;
70 delete[] m_Zone_Weights;
72 delete[] m_average_counter;
75 void CAtmoColorCalculator::UpdateParameters()
77 // Zonen Definition neu laden
78 // diverse Vorberechnungen neu ausführen
79 // Speicherbuffer neu allokieren!
82 void CAtmoColorCalculator::FindMostUsed(int AtmoSetup_NumZones,int *most_used,long int *windowed_hist)
84 memset(most_used, 0, sizeof(int) * AtmoSetup_NumZones);
87 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
90 // walk trough histogram
91 for (int i = 0; i < s_MAX+1; i++) // assume s_MAX = h_MAX = v_Max
93 // if new value bigger then old one
94 int tmp = *windowed_hist; // windowed_hist[zone * (s_MAX+1) + i];
95 // if (w_sat_hist[channel][i] > value)
108 pColorPacket CAtmoColorCalculator::AnalyzeHSV(tHSVColor *HSV_Img)
112 int AtmoSetup_EdgeWeighting = m_pAtmoConfig->getLiveView_EdgeWeighting();
113 int AtmoSetup_WidescreenMode = m_pAtmoConfig->getLiveView_WidescreenMode();
114 int AtmoSetup_DarknessLimit = m_pAtmoConfig->getLiveView_DarknessLimit();
115 int AtmoSetup_BrightCorrect = m_pAtmoConfig->getLiveView_BrightCorrect();
116 int AtmoSetup_SatWinSize = m_pAtmoConfig->getLiveView_SatWinSize();
117 int AtmoSetup_NumZones = m_pAtmoConfig->getZoneCount();
120 if(AtmoSetup_NumZones != m_LastNumZones)
124 delete[] m_windowed_hue_hist;
125 delete[] m_most_used_hue_last;
126 delete[] m_most_used_hue;
128 delete[] m_windowed_sat_hist;
129 delete[] m_most_used_sat;
130 delete[] m_Zone_Weights;
131 delete[] m_average_v;
132 delete[] m_average_counter;
134 m_Weight = new int[AtmoSetup_NumZones * IMAGE_SIZE];
135 m_Zone_Weights = new int*[AtmoSetup_NumZones];
136 for(int i = 0; i < AtmoSetup_NumZones; i++)
137 m_Zone_Weights[i] = &m_Weight[i * IMAGE_SIZE];
139 m_hue_hist = new long int[(h_MAX+1) * AtmoSetup_NumZones];
140 m_windowed_hue_hist = new long int[(h_MAX+1) * AtmoSetup_NumZones];
142 m_most_used_hue_last = new int[AtmoSetup_NumZones];
143 m_most_used_hue = new int[AtmoSetup_NumZones];
144 memset( m_most_used_hue_last, 0, sizeof(int) * AtmoSetup_NumZones);
146 m_sat_hist = new long int[(s_MAX+1) * AtmoSetup_NumZones];
147 m_windowed_sat_hist = new long int[(s_MAX+1) * AtmoSetup_NumZones];
148 m_most_used_sat = new int[AtmoSetup_NumZones];
150 m_average_v = new long int[AtmoSetup_NumZones];
151 m_average_counter = new int[AtmoSetup_NumZones];
153 m_LastNumZones = AtmoSetup_NumZones;
157 // calculate only if setup has changed
158 if ((AtmoSetup_EdgeWeighting != m_LastEdgeWeighting) ||
159 (AtmoSetup_WidescreenMode != m_LastWidescreenMode) ||
160 (m_pAtmoConfig->getZonesTopCount() != m_LastLayout_TopCount) ||
161 (m_pAtmoConfig->getZonesBottomCount() != m_LastLayout_BottomCount) ||
162 (m_pAtmoConfig->getZonesLRCount() != m_LastLayout_LRCount) ||
163 (m_pAtmoConfig->m_UpdateEdgeWeightningFlag != 0)
167 for(i = 0 ;i < AtmoSetup_NumZones; i++) {
168 CAtmoZoneDefinition *pZoneDef = m_pAtmoConfig->getZoneDefinition(i);
171 pZoneDef->UpdateWeighting(m_Zone_Weights[i],
172 AtmoSetup_WidescreenMode,
173 AtmoSetup_EdgeWeighting);
174 #ifdef _debug_zone_weight_
176 sprintf(filename, "zone_%d_gradient_debug.bmp",i);
177 pZoneDef->SaveZoneBitmap( filename );
178 sprintf(filename, "zone_%d_weight_%d_debug.bmp",i,AtmoSetup_EdgeWeighting);
179 pZoneDef->SaveWeightBitmap(filename, m_Zone_Weights[i] );
184 m_pAtmoConfig->m_UpdateEdgeWeightningFlag = 0;
186 m_LastEdgeWeighting = AtmoSetup_EdgeWeighting;
187 m_LastWidescreenMode = AtmoSetup_WidescreenMode;
188 m_LastLayout_TopCount = m_pAtmoConfig->getZonesTopCount();
189 m_LastLayout_BottomCount = m_pAtmoConfig->getZonesBottomCount();
190 m_LastLayout_LRCount = m_pAtmoConfig->getZonesLRCount();
193 AtmoSetup_DarknessLimit = AtmoSetup_DarknessLimit * 10;
196 /***************************************************************************/
198 /***************************************************************************/
199 /*----------------------------*/
200 /* hue histogram builtup */
201 /*----------------------------*/
203 // long int hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1];
205 // average brightness (value)
206 // m_average_v m_average_counter
208 // clean histogram --> calloc
209 memset(m_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
210 memset(m_average_v, 0, sizeof(long int) * AtmoSetup_NumZones);
211 memset(m_average_counter, 0, sizeof(int) * AtmoSetup_NumZones);
215 for (int row = 0; row < CAP_HEIGHT; row++)
217 for (int column = 0; column < CAP_WIDTH; column++)
219 // forget black bars: perform calculations only if pixel has some luminosity
220 if ((*temp_Img).v > AtmoSetup_DarknessLimit)
222 // builtup histogram for the x Zones of the Display
223 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
225 // Add weight to channel
226 // Weight(zone, pixel_nummer) m_Weight[((zone) * (IMAGE_SIZE)) + (pixel_nummer)]
227 // m_hue_hist[zone*(h_MAX+1) + HSV_Img[i].h] += m_Zone_Weights[zone][i] * HSV_Img[i].v;
228 m_hue_hist[zone*(h_MAX+1) + (*temp_Img).h] += m_Zone_Weights[zone][i] * temp_Img->v;
230 if(m_Zone_Weights[zone][i] > 0) {
231 m_average_v[zone] += temp_Img->v;
232 m_average_counter[zone]++;
236 // calculate brightness average
243 /*----------------------------*/
244 /* hue histogram windowing */
245 /*----------------------------*/
246 // windowed HSV histogram
247 // long int w_hue_hist[CAP_MAX_NUM_ZONES][h_MAX+1]; -> m_windowed_hue_hist
248 // clean windowed histogram
249 memset(m_windowed_hue_hist, 0, sizeof(long int) * (h_MAX+1) * AtmoSetup_NumZones);
250 // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
251 int hue_windowsize = m_pAtmoConfig->getLiveView_HueWinSize();
253 for (i = 0; i < h_MAX+1; i++) // walk through histogram [0;h_MAX]
255 // windowing from -hue_windowsize -> +hue_windowsize
256 for (int mywin = -hue_windowsize; mywin < hue_windowsize+1; mywin++)
258 // addressed histogram candlestick
259 int myidx = i + mywin;
261 // handle beginning of windowing -> roll back
262 if (myidx < 0) { myidx = myidx + h_MAX + 1; }
264 // handle end of windowing -> roll forward
265 if (myidx > h_MAX) { myidx = myidx - h_MAX - 1; }
267 // Apply windowing to all x zones
268 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
270 // apply lite triangular window design with gradient of 10% per discrete step
271 m_windowed_hue_hist[(zone * (h_MAX+1)) + i] += m_hue_hist[(zone * (h_MAX+1)) + myidx] * ((hue_windowsize+1)-abs(mywin)); // apply window
276 /*--------------------------------------*/
277 /* analyze histogram for most used hue */
278 /*--------------------------------------*/
279 // index of last maximum
280 // static int most_used_hue_last[CAP_MAX_NUM_ZONES] = {0, 0, 0, 0, 0}; --> m_most_used_hue_last
282 // resulting hue for each channel
283 //int most_used_hue[CAP_MAX_NUM_ZONES]; --> m_most_used_hue
285 FindMostUsed(AtmoSetup_NumZones, m_most_used_hue, m_windowed_hue_hist);
286 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
288 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]];
289 if (percent > 0.93f) // less than 7% difference?
290 m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
292 m_most_used_hue_last[zone] = m_most_used_hue[zone];
296 memset(m_most_used_hue, 0, sizeof(int) * AtmoSetup_NumZones);
298 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
301 for (i = 0; i < h_MAX+1; i++) // walk through histogram
303 long int tmp = m_windowed_hue_hist[ (zone * (h_MAX+1)) + i ];
304 if (tmp > value) // if new value bigger then old one
306 m_most_used_hue[zone] = i; // remember index
307 value = tmp; // w_hue_hist[zone][i]; // and value
311 float percent = (float)m_windowed_hue_hist[zone * (h_MAX+1) + m_most_used_hue_last[zone]] / (float)value;
312 if (percent > 0.93f) // less than 7% difference?
314 m_most_used_hue[zone] = m_most_used_hue_last[zone]; // use last index
317 m_most_used_hue_last[zone] = m_most_used_hue[zone]; // save current index of most used hue
321 /***************************************************************************/
323 /***************************************************************************/
325 // long int sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; -> m_sat_hist
326 // hue of the pixel we are working at
329 memset(m_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
331 /*--------------------------------------*/
332 /* saturation histogram builtup */
333 /*--------------------------------------*/
336 for (int row = 0; row < CAP_HEIGHT; row++)
338 for (int column = 0; column < CAP_WIDTH; column++)
340 // forget black bars: perform calculations only if pixel has some luminosity
341 if ((*temp_Img).v > AtmoSetup_DarknessLimit)
343 // find histogram position for pixel
344 pixel_hue = (*temp_Img).h;
346 // TODO: brightness calculation(if we require it some time)
348 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
350 // only use pixel for histogram if hue is near most_used_hue
351 if ((pixel_hue > m_most_used_hue[zone] - hue_windowsize) &&
352 (pixel_hue < m_most_used_hue[zone] + hue_windowsize))
355 // sat_hist[channel][HSV_Img[i].s] += Weight[i].channel[channel] * HSV_Img[i].v;
356 m_sat_hist[zone * (s_MAX+1) + (*temp_Img).s ] += m_Zone_Weights[zone][i] * (*temp_Img).v;
366 /*--------------------------------------*/
367 /* saturation histogram windowing */
368 /*--------------------------------------*/
369 // windowed HSV histogram
370 // long int w_sat_hist[CAP_MAX_NUM_ZONES][s_MAX+1]; --> m_windowed_sat_hist
371 // clean windowed histogram
372 memset(m_windowed_sat_hist, 0, sizeof(long int) * (s_MAX+1) * AtmoSetup_NumZones);
373 // steps in each direction; eg. 2 => -2 -1 0 1 2 windowing
374 int sat_windowsize = AtmoSetup_SatWinSize;
376 // walk through histogram [0;h_MAX]
377 for (i = 0; i < s_MAX + 1; i++)
379 // windowing from -hue_windowsize -> +hue_windowsize
380 for (int mywin = -sat_windowsize; mywin < sat_windowsize+1; mywin++)
382 // addressed histogram candlestick
383 int myidx = i + mywin;
385 // handle beginning of windowing -> roll back
386 if (myidx < 0) { myidx = myidx + s_MAX + 1; }
388 // handle end of windowing -> roll forward
389 if (myidx > h_MAX) { myidx = myidx - s_MAX - 1; }
391 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
394 apply lite triangular window design with
395 gradient of 10% per discrete step
398 w_sat_hist[channel][i] += sat_hist[channel][myidx] *
399 ((sat_windowsize+1)-abs(mywin)); // apply window
401 m_windowed_sat_hist[zone * (s_MAX+1) + i] += m_sat_hist[zone* (h_MAX+1) + myidx] *
402 ((sat_windowsize+1)-abs(mywin)); // apply window
407 /*--------------------------------------*/
408 /* analyze histogram for most used sat */
409 /*--------------------------------------*/
410 // resulting sat (most_used_hue) for each channel
411 // int most_used_sat[CAP_MAX_NUM_ZONES];->m_most_used_sat
413 FindMostUsed(AtmoSetup_NumZones, m_most_used_sat, m_windowed_sat_hist);
415 memset(m_most_used_sat, 0, sizeof(int) * AtmoSetup_NumZones);
417 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
420 // walk trough histogram
421 for (i = 0; i < s_MAX+1; i++)
423 // if new value bigger then old one
424 int tmp = m_windowed_sat_hist[zone * (s_MAX+1) + i];
425 // if (w_sat_hist[channel][i] > value)
429 m_most_used_sat[zone] = i;
438 /*----------------------------------------------------------*/
439 /* calculate average brightness within HSV image */
440 /* uniform Brightness for all channels is calculated */
441 /*----------------------------------------------------------*/
442 /* code integrated into "hue histogram builtup" to save some looping time!
444 // average brightness (value)
445 long int value_avg = 0;
447 for (int row = 0; row < CAP_HEIGHT; row++)
449 for (int column = 0; column < CAP_WIDTH; column++)
451 // find average value: only use bright pixels for luminance average
452 if (HSV_Img[i].v > AtmoSetup_DarknessLimit)
454 // build brightness average
455 value_avg += HSV_Img[i].v;
461 // calculate brightness average
462 if (l_counter > 0) { value_avg = value_avg / l_counter; }
463 else { value_avg = AtmoSetup_DarknessLimit; }
468 /*----------------------------*/
469 /* adjust and copy results */
470 /*----------------------------*/
472 // storage container for resulting RGB values
473 pColorPacket output_colors;
474 AllocColorPacket(output_colors, AtmoSetup_NumZones);
477 // int new_value = (int) ((float)value_avg * ((float)AtmoSetup_BrightCorrect / 100.0));
478 // if (new_value > 255) new_value = 255; // ensure brightness isn't set too high
479 // hsv_pixel.v = (unsigned char)new_value;
482 // calculate brightness average
483 for(int zone = 0; zone < AtmoSetup_NumZones; zone++) {
484 if(m_average_counter[zone] > 0)
485 m_average_v[zone] = m_average_v[zone] / m_average_counter[zone]
487 m_average_v[zone] = AtmoSetup_DarknessLimit;
492 for (int zone = 0; zone < AtmoSetup_NumZones; zone++)
494 if(m_average_counter[zone] > 0)
495 m_average_v[zone] = m_average_v[zone] / m_average_counter[zone];
497 m_average_v[zone] = AtmoSetup_DarknessLimit;
499 m_average_v[zone] = (int)((float)m_average_v[zone] * ((float)AtmoSetup_BrightCorrect / 100.0));
501 hsv_pixel.v = (unsigned char)ATMO_MAX(ATMO_MIN(m_average_v[zone],255),0);
502 hsv_pixel.h = m_most_used_hue[zone];
503 hsv_pixel.s = m_most_used_sat[zone];
505 // convert back to rgb
506 output_colors->zone[zone] = HSV2RGB(hsv_pixel);
510 return output_colors;
513 tHSVColor RGB2HSV(tRGBColor color)
524 min = ATMO_MIN(ATMO_MIN(r, g), b);
525 max = ATMO_MAX(ATMO_MAX(r, g), b);
529 hsv.v = (unsigned char) POS_DIV( max*v_MAX, 255 );
531 if (delta == 0) // This is a gray, no chroma...
533 h = 0; // HSV results = 0 / 1
536 else // Chromatic data...
538 hsv.s = (unsigned char) POS_DIV( (delta*s_MAX) , max );
540 int dr = (max - r) + 3*delta;
541 int dg = (max - g) + 3*delta;
542 int db = (max - b) + 3*delta;
543 int divisor = 6*delta;
547 h = POS_DIV(( (db - dg) * h_MAX ) , divisor);
551 h = POS_DIV( ((dr - db) * h_MAX) , divisor) + (h_MAX/3);
555 h = POS_DIV(( (dg - dr) * h_MAX) , divisor) + (h_MAX/3)*2;
558 if ( h < 0 ) { h += h_MAX; }
559 if ( h > h_MAX ) { h -= h_MAX; }
561 hsv.h = (unsigned char)h;
566 tRGBColor HSV2RGB(tHSVColor color)
568 tRGBColor rgb = {0, 0, 0};
570 float h = (float)color.h/(float)h_MAX;
571 float s = (float)color.s/(float)s_MAX;
572 float v = (float)color.v/(float)v_MAX;
576 rgb.r = (int)((v*255.0)+0.5);
583 if (h == 6.0) { h = 0.0; }
587 float p = v*(1.0f-s);
588 float q = v*(1.0f-(s*f));
589 float t = v*(1.0f-(s*(1.0f-f)));
593 rgb.r = (int)((v*255.0)+0.5);
594 rgb.g = (int)((t*255.0)+0.5);
595 rgb.b = (int)((p*255.0)+0.5);
599 rgb.r = (int)((q*255.0)+0.5);
600 rgb.g = (int)((v*255.0)+0.5);
601 rgb.b = (int)((p*255.0)+0.5);
605 rgb.r = (int)((p*255.0)+0.5);
606 rgb.g = (int)((v*255.0)+0.5);
607 rgb.b = (int)((t*255.0)+0.5);
611 rgb.r = (int)((p*255.0)+0.5);
612 rgb.g = (int)((q*255.0)+0.5);
613 rgb.b = (int)((v*255.0)+0.5);
617 rgb.r = (int)((t*255.0)+0.5);
618 rgb.g = (int)((p*255.0)+0.5);
619 rgb.b = (int)((v*255.0)+0.5);
623 rgb.r = (int)((v*255.0)+0.5);
624 rgb.g = (int)((p*255.0)+0.5);
625 rgb.b = (int)((q*255.0)+0.5);