AtmoOutputFilter.cpp 6.22 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * AtmoOutputFilter.cpp: Post Processor for the color data retrieved from
 * a CAtmoInput
 *
 * mostly 1:1 from vdr-linux-src "filter.c" copied
 *
 * See the README.txt file for copyright information and how to reach the author(s).
 *
 * $Id$
 */

#include <string.h>
#include "AtmoOutputFilter.h"


16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
CAtmoOutputFilter::CAtmoOutputFilter(CAtmoConfig *atmoConfig)
{
   this->m_pAtmoConfig = atmoConfig;
   ResetFilter();
}

CAtmoOutputFilter::~CAtmoOutputFilter(void)
{
}

void CAtmoOutputFilter::ResetFilter(void)
{
  // reset filter values
  MeanFilter(true);
  PercentFilter(true);
}

tColorPacket CAtmoOutputFilter::Filtering(tColorPacket ColorPacket)
{
  filter_input = ColorPacket;

  switch (m_pAtmoConfig->getLiveViewFilterMode())
  {
    case afmNoFilter:
         filter_output = filter_input;
    break;

    case afmCombined:
         MeanFilter(false);
    break;

    case afmPercent:
         PercentFilter(false);
    break;

    default:
         filter_output = filter_input;
    break;
  }

  return filter_output;
}

void CAtmoOutputFilter::PercentFilter(ATMO_BOOL init)
{
  // last values needed for the percentage filter
  static tColorPacket filter_output_old;

  if (init) // Initialization
  {
    memset(&filter_output_old, 0, sizeof(filter_output_old));
    return;
  }

  int percentNew = this->m_pAtmoConfig->getLiveViewFilter_PercentNew();

  for (int ch = 0; ch < ATMO_NUM_CHANNELS; ch++)
  {
	filter_output.channel[ch].r = (filter_input.channel[ch].r *
         (100-percentNew) + filter_output_old.channel[ch].r * percentNew) / 100;
	
    filter_output.channel[ch].g = (filter_input.channel[ch].g *
         (100-percentNew) + filter_output_old.channel[ch].g * percentNew) / 100;

	filter_output.channel[ch].b = (filter_input.channel[ch].b *
         (100-percentNew) + filter_output_old.channel[ch].b * percentNew) / 100;
  }

  filter_output_old = filter_output;
}

void CAtmoOutputFilter::MeanFilter(ATMO_BOOL init)
{
  // needed vor the running mean value filter
  static tColorPacketLongInt mean_sums;
  static tColorPacket mean_values;
  // needed for the percentage filter
  static tColorPacket filter_output_old;
  static int filter_length_old;
  char reinitialize = 0;
97
  long int tmp;
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

  if (init) // Initialization
  {
    memset(&filter_output_old, 0, sizeof(filter_output_old));
    memset(&mean_sums, 0, sizeof(mean_sums));
    memset(&mean_values, 0, sizeof(mean_values));
    return;
  }
  int AtmoSetup_Filter_MeanLength = m_pAtmoConfig->getLiveViewFilter_MeanLength();
  int AtmoSetup_Filter_PercentNew = m_pAtmoConfig->getLiveViewFilter_PercentNew();
  int AtmoSetup_Filter_MeanThreshold = m_pAtmoConfig->getLiveViewFilter_MeanThreshold();

  // if filter_length has changed
  if (filter_length_old != AtmoSetup_Filter_MeanLength)
  {
    // force reinitialization of the filter
    reinitialize = 1;
  }
  filter_length_old = AtmoSetup_Filter_MeanLength;

  if (filter_length_old < 20) filter_length_old = 20; // avoid division by 0

  for (int ch = 0; ch < ATMO_NUM_CHANNELS; ch++)
  {
    // calculate the mean-value filters
    mean_sums.channel[ch].r +=
         (long int)(filter_input.channel[ch].r - mean_values.channel[ch].r); // red
125
126
127
    tmp = mean_sums.channel[ch].r / ((long int)filter_length_old / 20);
    if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
    mean_values.channel[ch].r = (unsigned char)tmp;
128
129
130

    mean_sums.channel[ch].g +=
        (long int)(filter_input.channel[ch].g - mean_values.channel[ch].g); // green
131
132
133
    tmp = mean_sums.channel[ch].g / ((long int)filter_length_old / 20);
    if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
    mean_values.channel[ch].g = (unsigned char)tmp;
134
135
136

    mean_sums.channel[ch].b +=
        (long int)(filter_input.channel[ch].b - mean_values.channel[ch].b); // blue
137
138
139
    tmp = mean_sums.channel[ch].b / ((long int)filter_length_old / 20);
    if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
    mean_values.channel[ch].b = (unsigned char)tmp;
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

    // check, if there is a jump -> check if differences between actual values and filter values are too big

    long int dist; // distance between the two colors in the 3D RGB space
    dist = (mean_values.channel[ch].r - filter_input.channel[ch].r) *
           (mean_values.channel[ch].r - filter_input.channel[ch].r) +
           (mean_values.channel[ch].g - filter_input.channel[ch].g) *
           (mean_values.channel[ch].g - filter_input.channel[ch].g) +
           (mean_values.channel[ch].b - filter_input.channel[ch].b) *
           (mean_values.channel[ch].b - filter_input.channel[ch].b);

    /*
       if (dist > 0) { dist = (long int)sqrt((double)dist); }
       avoid sqrt(0) (TODO: necessary?)
       I think its cheaper to calculate the square of something ..? insteas geting the square root?
    */
    double distMean = ((double)AtmoSetup_Filter_MeanThreshold * 3.6f);
    distMean = distMean * distMean;

    /*
      compare calculated distance with the filter threshold
  	  if ((dist > (long int)((double)AtmoSetup.Filter_MeanThreshold * 3.6f)) || ( reinitialize == 1))
   */

	if ((dist > distMean) || ( reinitialize == 1))
    {
      // filter jump detected -> set the long filters to the result of the short filters
      filter_output.channel[ch] = mean_values.channel[ch] = filter_input.channel[ch];

      mean_sums.channel[ch].r = filter_input.channel[ch].r *
                                (filter_length_old / 20);
      mean_sums.channel[ch].g = filter_input.channel[ch].g *
                                (filter_length_old / 20);
      mean_sums.channel[ch].b = filter_input.channel[ch].b *
                                (filter_length_old / 20);
    }
    else
    {
      // apply an additional percent filter and return calculated values

	  filter_output.channel[ch].r = (mean_values.channel[ch].r *
          (100-AtmoSetup_Filter_PercentNew) +
          filter_output_old.channel[ch].r * AtmoSetup_Filter_PercentNew) / 100;

	  filter_output.channel[ch].g = (mean_values.channel[ch].g *
          (100-AtmoSetup_Filter_PercentNew) +
          filter_output_old.channel[ch].g * AtmoSetup_Filter_PercentNew) / 100;

	  filter_output.channel[ch].b = (mean_values.channel[ch].b *
          (100-AtmoSetup_Filter_PercentNew) +
          filter_output_old.channel[ch].b * AtmoSetup_Filter_PercentNew) / 100;
    }
  }
  filter_output_old = filter_output;
}