source: trunk/third/gst-plugins/sys/qcam/exposure.c @ 21011

Revision 21011, 7.4 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21010, which included commits to RCS files with non-trunk default branches.
Line 
1/* exposure.c
2 *
3 * Time-stamp: <02 Sep 96 11:52:21 HST edo@eosys.com>
4 *
5 * Version 0.2
6 */
7
8
9/******************************************************************
10
11Copyright (C) 1996 by Ed Orcutt Systems
12
13Permission is hereby granted, free of charge, to any person
14obtaining a copy of this software and associated documentation
15files (the "Software"), to deal in the Software without
16restriction, including without limitation the rights to use,
17copy, modify, merge, publish, and/or distribute copies of the
18Software, and to permit persons to whom the Software is
19furnished to do so, subject to the following conditions:
20
211. The above copyright notice and this permission notice shall
22   be included in all copies or substantial portions of the
23   Software.
24
252. Redistribution for profit requires the express, written
26   permission of the author.
27
28THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
30OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31NONINFRINGEMENT.  IN NO EVENT SHALL ED ORCUTT SYSTEMS BE LIABLE
32FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35SOFTWARE.
36
37******************************************************************/
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43#include <stdio.h>
44#include "qcam.h"
45#include "qcamip.h"
46
47/* Prototypes for private (static) functions used by the routines
48 * within this file.  Externally visible functions should be
49 * prototyped in qcamip.h
50 */
51
52static int qcip_pixel_average (struct qcam *q, scanbuf * scan);
53static int qcip_luminance_std (struct qcam *q, scanbuf * scan, int avg);
54
55/* Private data used by the auto exposure routine */
56
57static int luminance_target = -1;
58static int luminance_tolerance = 0;
59static int luminance_std_target = -1;
60static int luminance_std_tolerance = 0;
61static int ae_mode = AE_ALL_AVG;
62
63/* Calculate average pixel value for entire image */
64
65static int
66qcip_pixel_average (struct qcam *q, scanbuf * scan)
67{
68  int count = 0;
69  int sum = 0;
70  int pixels;
71  int i;
72
73  pixels = q->height / q->transfer_scale;
74  pixels *= q->width / q->transfer_scale;
75
76  for (i = 0; i < pixels; i++) {
77    sum += scan[i];
78    count++;
79  }
80  return (sum / count);
81}
82
83/* Calculate average pixel value for center of image */
84
85static int
86qcip_pixel_average_center (struct qcam *q, scanbuf * scan)
87{
88  int count = 0;
89  int sum = 0;
90  int height, width;
91  int maxrow, maxcol;
92  int i, j;
93
94  /* actual image width & height after scaling */
95  width = q->width / q->transfer_scale;
96  height = q->height / q->transfer_scale;
97
98  maxcol = width * 2 / 3;
99  maxrow = height * 2 / 3;
100
101  for (i = width / 3; i < maxcol; i++) {
102    for (j = height / 3; j < maxrow; j++) {
103      sum += scan[j * width + i];
104      count++;
105    }
106  }
107  return (sum / count);
108}
109
110int
111qcip_set_luminance_target (struct qcam *q, int val)
112{
113  const int max_pixel_val = q->bpp == 6 ? 63 : 15;
114
115  if ((val - luminance_tolerance) >= 0 &&
116      (val + luminance_tolerance) <= max_pixel_val) {
117    luminance_target = val;
118    return QCIP_XPSR_OK;
119  }
120  return QCIP_XPSR_LUM_INVLD;
121}
122
123int
124qcip_set_luminance_tolerance (struct qcam *q, int val)
125{
126  const int max_pixel_val = q->bpp == 6 ? 63 : 15;
127
128  /* set target if it has not been explicitly set */
129  if (luminance_target == -1) {
130    luminance_target = q->bpp == 6 ? 32 : 8;
131  }
132
133  if ((luminance_target - val) >= 0 &&
134      (luminance_target + val) <= max_pixel_val) {
135    luminance_tolerance = val;
136    return QCIP_XPSR_OK;
137  }
138  return QCIP_XPSR_LUM_INVLD;
139}
140
141int
142qcip_set_luminance_std_target (struct qcam *q, int val)
143{
144  luminance_std_target = val;
145  return QCIP_XPSR_OK;
146}
147
148int
149qcip_set_luminance_std_tolerance (struct qcam *q, int val)
150{
151  luminance_std_tolerance = val;
152  return QCIP_XPSR_OK;
153}
154
155int
156qcip_set_autoexposure_mode (int val)
157{
158  ae_mode = val;
159  return 0;
160}
161
162/* Calculate standard deviation of pixel value for entire image */
163
164static int
165qcip_luminance_std (struct qcam *q, scanbuf * scan, int avg)
166{
167  int count = 0;
168  int sum = 0;
169  int pixels;
170  int i;
171
172  pixels = q->height / q->transfer_scale;
173  pixels *= q->width / q->transfer_scale;
174
175  for (i = 0; i < pixels; i++) {
176    if (scan[i] < avg) {
177      sum += avg - scan[i];
178    } else {
179      sum += scan[i] - avg;
180    }
181    count++;
182  }
183  return (sum / count);
184}
185
186
187/* If necessary adjust the brightness in an attempt to achieve
188 * a target average pixel value: 32 for 6 bpp, 8 for 4bpp.
189 * This routine *will* modify the brightness value in preparation
190 * for another scan unless the target average pixel values has
191 * been reached. If the exposure is correct (yes, I realize that
192 * this is subjective) QCIP_XPSR_OK will be returned, otherwise
193 * return QCIP_XPSR_RSCN after adjusting the exposure.
194 *
195 * Caveat: If the new calculated brightness value is invalid,
196 *         QCIP_XPSR_ERR will be returned.
197 */
198
199int
200qcip_autoexposure (struct qcam *q, scanbuf * scan)
201{
202  int luminance_dif;
203  int luminance_avg;
204  int brightness_adj;
205  int lum_min, lum_max;
206  int lum_std, lum_std_min, lum_std_max;
207  int ret = QCIP_XPSR_OK;
208
209#ifdef DEBUG
210  fprintf (stderr, "Brightness: %d  Contrast: %d\n",
211      qc_getbrightness (q), qc_getcontrast (q));
212#endif
213
214  switch (ae_mode) {
215    case AE_CTR_AVG:
216      luminance_avg = qcip_pixel_average_center (q, scan);
217      break;
218    case AE_STD_AVG:
219      luminance_avg = qcip_pixel_average (q, scan);
220      lum_std = qcip_luminance_std (q, scan, luminance_avg);
221
222      /* ==>> Contrast adjustment <<== */
223
224      /* set target if it has not been explicitly set */
225      if (luminance_std_target == -1) {
226        luminance_std_target = q->bpp == 6 ? 10 : 2;
227      }
228
229      /* Adjust contrast to reach target luminance standard deviation */
230      lum_std_min = luminance_std_target - luminance_std_tolerance;
231      lum_std_max = luminance_std_target + luminance_std_tolerance;
232
233      if (lum_std < lum_std_min || lum_std > lum_std_max) {
234        ret = QCIP_XPSR_RSCN;
235        if (qc_setcontrast (q,
236                luminance_std_target - lum_std + qc_getcontrast (q))) {
237          return QCIP_XPSR_ERR;
238        }
239      }
240#ifdef DEBUG
241      fprintf (stderr, "Luminance std/target/tolerance: %d/%d/%d\n",
242          lum_std, luminance_std_target, luminance_std_tolerance);
243#endif
244
245      break;
246    case AE_ALL_AVG:
247    default:
248      luminance_avg = qcip_pixel_average (q, scan);
249      break;
250  }
251
252  /* ==>> Brightness adjustment <<== */
253
254  /* set target if it has not been explicitly set */
255  if (luminance_target == -1) {
256    luminance_target = q->bpp == 6 ? 32 : 8;
257  }
258
259  lum_min = luminance_target - luminance_tolerance;
260  lum_max = luminance_target + luminance_tolerance;
261
262#ifdef DEBUG
263  fprintf (stderr, "Luminance avg/target/tolerance: %d/%d/%d\n",
264      luminance_avg, luminance_target, luminance_tolerance);
265#endif
266
267  /* check for luminance within target range */
268  if (luminance_avg < lum_min || luminance_avg > lum_max) {
269    ret = QCIP_XPSR_RSCN;
270    /* we need to adjust the brighness, which way? */
271    luminance_dif = luminance_target - luminance_avg;
272    if (luminance_dif > 0) {
273      brightness_adj = luminance_dif / 2 + 1;
274    } else {
275      brightness_adj = luminance_dif / 2 - 1;
276    }
277
278    /* Adjusted brightness is out of range ..
279     * throw in the towel ... auto-exposure has failed!
280     */
281    if (qc_setbrightness (q, brightness_adj + qc_getbrightness (q))) {
282      return QCIP_XPSR_ERR;
283    }
284  }
285
286  return ret;
287}
Note: See TracBrowser for help on using the repository browser.