]> git.sesse.net Git - vlc/blob - modules/video_filter/atmo/AtmoOutputFilter.cpp
enhanced & corrected AtmoLight filter module
[vlc] / modules / video_filter / atmo / AtmoOutputFilter.cpp
1 /*
2  * AtmoOutputFilter.cpp: Post Processor for the color data retrieved from
3  * a CAtmoInput
4  *
5  * mostly 1:1 from vdr-linux-src "filter.c" copied
6  *
7  * See the README.txt file for copyright information and how to reach the author(s).
8  *
9  * $Id$
10  */
11
12 #include <string.h>
13 #include "AtmoOutputFilter.h"
14
15
16
17 CAtmoOutputFilter::CAtmoOutputFilter(CAtmoConfig *atmoConfig )
18 {
19    this->m_pAtmoConfig = atmoConfig;
20    this->m_percent_filter_output_old = NULL;
21    this->m_mean_filter_output_old = NULL;
22    this->m_mean_values = NULL;
23    this->m_mean_sums = NULL;
24    ResetFilter();
25 }
26
27 CAtmoOutputFilter::~CAtmoOutputFilter(void)
28 {
29   if(m_percent_filter_output_old)
30      delete (char *)m_percent_filter_output_old;
31
32   if(m_mean_filter_output_old)
33      delete (char *)m_mean_filter_output_old;
34
35   if(m_mean_values)
36      delete (char *)m_mean_values;
37
38   if(m_mean_sums)
39      delete (char *)m_mean_sums;
40 }
41
42 void CAtmoOutputFilter::ResetFilter(void)
43 {
44   // reset filter values
45   MeanFilter(NULL, true);
46   PercentFilter(NULL, true);
47 }
48
49 pColorPacket CAtmoOutputFilter::Filtering(pColorPacket ColorPacket)
50 {
51   switch (m_pAtmoConfig->getLiveViewFilterMode())
52   {
53     case afmNoFilter:
54          return ColorPacket;
55     break;
56
57     case afmCombined:
58          return MeanFilter(ColorPacket, false);
59     break;
60
61     case afmPercent:
62          return PercentFilter(ColorPacket, false);
63     break;
64   }
65
66   return ColorPacket;
67 }
68
69 pColorPacket CAtmoOutputFilter::PercentFilter(pColorPacket filter_input, ATMO_BOOL init)
70 {
71   // last values needed for the percentage filter
72   if (init) // Initialization
73   {
74     if(m_percent_filter_output_old)
75        delete (char *)m_percent_filter_output_old;
76     m_percent_filter_output_old = NULL;
77     return(NULL);
78   }
79
80   if(!m_percent_filter_output_old || (m_percent_filter_output_old->numColors!=filter_input->numColors)) {
81      delete m_percent_filter_output_old;
82      AllocColorPacket(m_percent_filter_output_old, filter_input->numColors);
83      ZeroColorPacket(m_percent_filter_output_old);
84   }
85
86   int percentNew = this->m_pAtmoConfig->getLiveViewFilter_PercentNew();
87
88   pColorPacket filter_output;
89   AllocColorPacket(filter_output, filter_input->numColors);
90
91   for (int zone = 0; zone < filter_input->numColors; zone++)
92   {
93         filter_output->zone[zone].r = (filter_input->zone[zone].r *
94          (100-percentNew) + m_percent_filter_output_old->zone[zone].r * percentNew) / 100;
95         
96     filter_output->zone[zone].g = (filter_input->zone[zone].g *
97          (100-percentNew) + m_percent_filter_output_old->zone[zone].g * percentNew) / 100;
98
99         filter_output->zone[zone].b = (filter_input->zone[zone].b *
100          (100-percentNew) + m_percent_filter_output_old->zone[zone].b * percentNew) / 100;
101   }
102
103   CopyColorPacket( filter_output, m_percent_filter_output_old );
104
105   delete (char *)filter_input;
106
107   return filter_output;
108 }
109
110 pColorPacket CAtmoOutputFilter::MeanFilter(pColorPacket filter_input, ATMO_BOOL init)
111 {
112   // needed vor the running mean value filter
113
114   // needed for the percentage filter
115   static int filter_length_old;
116   char reinitialize = 0;
117   long int tmp;
118   pColorPacket filter_output;
119
120   if (init) // Initialization
121   {
122     if(m_mean_filter_output_old)
123        delete (char *)m_mean_filter_output_old;
124     m_mean_filter_output_old = NULL;
125
126     if(m_mean_values)
127        delete (char *)m_mean_values;
128     m_mean_values = NULL;
129
130     if(m_mean_sums)
131        delete (char *)m_mean_sums;
132     m_mean_sums = NULL;
133     return (NULL);
134   }
135
136   if(!m_mean_filter_output_old || (m_mean_filter_output_old->numColors!=filter_input->numColors)) {
137         delete m_mean_filter_output_old;
138         AllocColorPacket(m_mean_filter_output_old, filter_input->numColors);
139         ZeroColorPacket(m_mean_filter_output_old);
140   }
141
142   if(!m_mean_values || (m_mean_values->numColors!=filter_input->numColors)) {
143         delete m_mean_values;
144         AllocColorPacket(m_mean_values, filter_input->numColors);
145         ZeroColorPacket(m_mean_values);
146   }
147
148   if(!m_mean_sums || (m_mean_sums->numColors!=filter_input->numColors)) {
149         delete m_mean_sums;
150         AllocLongColorPacket(m_mean_sums, filter_input->numColors);
151         ZeroLongColorPacket(m_mean_sums);
152   }
153
154   AllocColorPacket(filter_output, filter_input->numColors);
155
156
157   int AtmoSetup_Filter_MeanLength = m_pAtmoConfig->getLiveViewFilter_MeanLength();
158   int AtmoSetup_Filter_PercentNew = m_pAtmoConfig->getLiveViewFilter_PercentNew();
159   int AtmoSetup_Filter_MeanThreshold = m_pAtmoConfig->getLiveViewFilter_MeanThreshold();
160
161   // if filter_length has changed
162   if (filter_length_old != AtmoSetup_Filter_MeanLength)
163   {
164     // force reinitialization of the filter
165     reinitialize = 1;
166   }
167   filter_length_old = AtmoSetup_Filter_MeanLength;
168
169   if (filter_length_old < 20) filter_length_old = 20; // avoid division by 0
170
171   for (int zone = 0; zone < filter_input->numColors; zone++)
172   {
173     // calculate the mean-value filters
174       m_mean_sums->longZone[zone].r +=
175         (long int)(filter_input->zone[zone].r - m_mean_values->zone[zone].r); // red
176     tmp = m_mean_sums->longZone[zone].r / ((long int)filter_length_old / 20);
177     if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
178     m_mean_values->zone[zone].r = (unsigned char)tmp;
179
180     m_mean_sums->longZone[zone].g +=
181         (long int)(filter_input->zone[zone].g - m_mean_values->zone[zone].g); // green
182     tmp = m_mean_sums->longZone[zone].g / ((long int)filter_length_old / 20);
183     if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
184     m_mean_values->zone[zone].g = (unsigned char)tmp;
185
186     m_mean_sums->longZone[zone].b +=
187         (long int)(filter_input->zone[zone].b - m_mean_values->zone[zone].b); // blue
188     tmp = m_mean_sums->longZone[zone].b / ((long int)filter_length_old / 20);
189     if(tmp<0) tmp = 0; else { if(tmp>255) tmp = 255; }
190     m_mean_values->zone[zone].b = (unsigned char)tmp;
191
192     // check, if there is a jump -> check if differences between actual values and filter values are too big
193
194     long int dist; // distance between the two colors in the 3D RGB space
195     dist = (m_mean_values->zone[zone].r - filter_input->zone[zone].r) *
196            (m_mean_values->zone[zone].r - filter_input->zone[zone].r) +
197            (m_mean_values->zone[zone].g - filter_input->zone[zone].g) *
198            (m_mean_values->zone[zone].g - filter_input->zone[zone].g) +
199            (m_mean_values->zone[zone].b - filter_input->zone[zone].b) *
200            (m_mean_values->zone[zone].b - filter_input->zone[zone].b);
201
202     /*
203        if (dist > 0) { dist = (long int)sqrt((double)dist); }
204        avoid sqrt(0) (TODO: necessary?)
205        I think its cheaper to calculate the square of something ..? insteas geting the square root?
206     */
207     double distMean = ((double)AtmoSetup_Filter_MeanThreshold * 3.6f);
208     distMean = distMean * distMean;
209
210     /*
211       compare calculated distance with the filter threshold
212           if ((dist > (long int)((double)AtmoSetup.Filter_MeanThreshold * 3.6f)) || ( reinitialize == 1))
213    */
214
215         if ((dist > distMean) || ( reinitialize == 1))
216     {
217       // filter jump detected -> set the long filters to the result of the short filters
218       filter_output->zone[zone] = m_mean_values->zone[zone] = filter_input->zone[zone];
219
220       m_mean_sums->longZone[zone].r = filter_input->zone[zone].r *
221                                 (filter_length_old / 20);
222       m_mean_sums->longZone[zone].g = filter_input->zone[zone].g *
223                                 (filter_length_old / 20);
224       m_mean_sums->longZone[zone].b = filter_input->zone[zone].b *
225                                 (filter_length_old / 20);
226     }
227     else
228     {
229       // apply an additional percent filter and return calculated values
230
231           filter_output->zone[zone].r = (m_mean_values->zone[zone].r *
232           (100-AtmoSetup_Filter_PercentNew) +
233           m_mean_filter_output_old->zone[zone].r * AtmoSetup_Filter_PercentNew) / 100;
234
235           filter_output->zone[zone].g = (m_mean_values->zone[zone].g *
236           (100-AtmoSetup_Filter_PercentNew) +
237           m_mean_filter_output_old->zone[zone].g * AtmoSetup_Filter_PercentNew) / 100;
238
239           filter_output->zone[zone].b = (m_mean_values->zone[zone].b *
240           (100-AtmoSetup_Filter_PercentNew) +
241           m_mean_filter_output_old->zone[zone].b * AtmoSetup_Filter_PercentNew) / 100;
242     }
243   }
244
245   CopyColorPacket(filter_output, m_mean_filter_output_old);
246
247   delete (char *)filter_input;
248
249   return(filter_output);
250 }