1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 - This software is distributed in the hope that it will be
4 - useful, but with NO WARRANTY OF ANY KIND.
5 - No author or distributor accepts responsibility to anyone for the
6 - consequences of using this software, or for whether it serves any
7 - particular purpose or works at all, unless he or she says so in
8 - writing. Everyone is granted permission to copy, modify and
9 - redistribute this source code, for commercial or non-commercial
10 - purposes, with the following restrictions: (1) the origin of this
11 - source code must not be misrepresented; (2) modified versions must
12 - be plainly marked as such; and (3) this notice may not be removed
13 - or altered from any source or modified source distribution.
14 *====================================================================*/
15
16
17 /*
18 * arithlow.c
19 *
20 * One image grayscale arithmetic (8, 16 or 32 bpp)
21 * void addConstantGrayLow()
22 * void multConstantGrayLow()
23 *
24 * Two image grayscale arithmetic (8, 16 or 32 bpp)
25 * void addGrayLow()
26 * void subtractGrayLow()
27 *
28 * Grayscale threshold operation (8, 16 or 32 bpp)
29 * void thresholdToValueLow()
30 *
31 * Image accumulator arithmetic operations (8, 16, 32 bpp)
32 * void finalAccumulateLow()
33 * void finalAccumulateThreshLow()
34 * void accumulateLow()
35 * void multConstAccumulateLow()
36 *
37 * Absolute value of difference, component-wise.
38 * void absDifferenceLow()
39 */
40
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <math.h>
46 #include "allheaders.h"
47
48
49 /*------------------------------------------------------------------*
50 * One image grayscale arithmetic (8, 16 or 32 bpp) *
51 *------------------------------------------------------------------*/
52 /*!
53 * addConstantGrayLow()
54 */
55 void
addConstantGrayLow(l_uint32 * data,l_int32 w,l_int32 h,l_int32 d,l_int32 wpl,l_int32 val)56 addConstantGrayLow(l_uint32 *data,
57 l_int32 w,
58 l_int32 h,
59 l_int32 d,
60 l_int32 wpl,
61 l_int32 val)
62 {
63 l_int32 i, j, pval;
64 l_uint32 *line;
65
66 for (i = 0; i < h; i++) {
67 line = data + i * wpl;
68 if (d == 8) {
69 if (val < 0) {
70 for (j = 0; j < w; j++) {
71 pval = GET_DATA_BYTE(line, j);
72 pval = L_MAX(0, pval + val);
73 SET_DATA_BYTE(line, j, pval);
74 }
75 }
76 else { /* val >= 0 */
77 for (j = 0; j < w; j++) {
78 pval = GET_DATA_BYTE(line, j);
79 pval = L_MIN(255, pval + val);
80 SET_DATA_BYTE(line, j, pval);
81 }
82 }
83 }
84 else if (d == 16) {
85 if (val < 0) {
86 for (j = 0; j < w; j++) {
87 pval = GET_DATA_TWO_BYTES(line, j);
88 pval = L_MAX(0, pval + val);
89 SET_DATA_TWO_BYTES(line, j, pval);
90 }
91 }
92 else { /* val >= 0 */
93 for (j = 0; j < w; j++) {
94 pval = GET_DATA_TWO_BYTES(line, j);
95 pval = L_MIN(0xffff, pval + val);
96 SET_DATA_TWO_BYTES(line, j, pval);
97 }
98 }
99 }
100 else { /* d == 32; no check for overflow (< 0 or > 0xffffffff) */
101 for (j = 0; j < w; j++)
102 *(line + j) += val;
103 }
104 }
105 return;
106 }
107
108
109 /*!
110 * multConstantGrayLow()
111 */
112 void
multConstantGrayLow(l_uint32 * data,l_int32 w,l_int32 h,l_int32 d,l_int32 wpl,l_float32 val)113 multConstantGrayLow(l_uint32 *data,
114 l_int32 w,
115 l_int32 h,
116 l_int32 d,
117 l_int32 wpl,
118 l_float32 val)
119 {
120 l_int32 i, j, pval;
121 l_uint32 upval;
122 l_uint32 *line;
123
124 for (i = 0; i < h; i++) {
125 line = data + i * wpl;
126 if (d == 8) {
127 for (j = 0; j < w; j++) {
128 pval = GET_DATA_BYTE(line, j);
129 pval = (l_int32)(val * pval);
130 pval = L_MIN(255, pval);
131 SET_DATA_BYTE(line, j, pval);
132 }
133 }
134 else if (d == 16) {
135 for (j = 0; j < w; j++) {
136 pval = GET_DATA_TWO_BYTES(line, j);
137 pval = (l_int32)(val * pval);
138 pval = L_MIN(0xffff, pval);
139 SET_DATA_TWO_BYTES(line, j, pval);
140 }
141 }
142 else { /* d == 32; no clipping */
143 for (j = 0; j < w; j++) {
144 upval = *(line + j);
145 upval = (l_uint32)(val * upval);
146 *(line + j) = upval;
147 }
148 }
149 }
150 return;
151 }
152
153
154 /*------------------------------------------------------------------*
155 * Two image grayscale arithmetic (8, 16 or 32 bpp) *
156 *------------------------------------------------------------------*/
157 /*!
158 * addGrayLow()
159 */
160 void
addGrayLow(l_uint32 * datad,l_int32 w,l_int32 h,l_int32 d,l_int32 wpld,l_uint32 * datas,l_int32 wpls)161 addGrayLow(l_uint32 *datad,
162 l_int32 w,
163 l_int32 h,
164 l_int32 d,
165 l_int32 wpld,
166 l_uint32 *datas,
167 l_int32 wpls)
168 {
169 l_int32 i, j, val, sum;
170 l_uint32 *lines, *lined;
171
172
173 for (i = 0; i < h; i++) {
174 lined = datad + i * wpld;
175 lines = datas + i * wpls;
176 if (d == 8) {
177 for (j = 0; j < w; j++) {
178 sum = GET_DATA_BYTE(lines, j) + GET_DATA_BYTE(lined, j);
179 val = L_MIN(sum, 255);
180 SET_DATA_BYTE(lined, j, val);
181 }
182 }
183 else if (d == 16) {
184 for (j = 0; j < w; j++) {
185 sum = GET_DATA_TWO_BYTES(lines, j)
186 + GET_DATA_TWO_BYTES(lined, j);
187 val = L_MIN(sum, 0xffff);
188 SET_DATA_TWO_BYTES(lined, j, val);
189 }
190 }
191 else { /* d == 32; no clipping */
192 for (j = 0; j < w; j++)
193 *(lined + j) += *(lines + j);
194 }
195 }
196
197 return;
198 }
199
200
201 /*!
202 * subtractGrayLow()
203 */
204 void
subtractGrayLow(l_uint32 * datad,l_int32 w,l_int32 h,l_int32 d,l_int32 wpld,l_uint32 * datas,l_int32 wpls)205 subtractGrayLow(l_uint32 *datad,
206 l_int32 w,
207 l_int32 h,
208 l_int32 d,
209 l_int32 wpld,
210 l_uint32 *datas,
211 l_int32 wpls)
212 {
213 l_int32 i, j, val, diff;
214 l_uint32 *lines, *lined;
215
216 for (i = 0; i < h; i++) {
217 lined = datad + i * wpld;
218 lines = datas + i * wpls;
219 if (d == 8) {
220 for (j = 0; j < w; j++) {
221 diff = GET_DATA_BYTE(lined, j) - GET_DATA_BYTE(lines, j);
222 val = L_MAX(diff, 0);
223 SET_DATA_BYTE(lined, j, val);
224 }
225 }
226 else if (d == 16) {
227 for (j = 0; j < w; j++) {
228 diff = GET_DATA_TWO_BYTES(lined, j)
229 - GET_DATA_TWO_BYTES(lines, j);
230 val = L_MAX(diff, 0);
231 SET_DATA_TWO_BYTES(lined, j, val);
232 }
233 }
234 else { /* d == 32; no clipping */
235 for (j = 0; j < w; j++)
236 *(lined + j) -= *(lines + j);
237 }
238 }
239
240 return;
241 }
242
243
244 /*-------------------------------------------------------------*
245 * Grayscale threshold operation *
246 *-------------------------------------------------------------*/
247 /*!
248 * thresholdToValueLow()
249 */
250 void
thresholdToValueLow(l_uint32 * datad,l_int32 w,l_int32 h,l_int32 d,l_int32 wpld,l_int32 threshval,l_int32 setval)251 thresholdToValueLow(l_uint32 *datad,
252 l_int32 w,
253 l_int32 h,
254 l_int32 d,
255 l_int32 wpld,
256 l_int32 threshval,
257 l_int32 setval)
258 {
259 l_int32 i, j, setabove;
260 l_uint32 *lined;
261
262 if (setval > threshval)
263 setabove = TRUE;
264 else
265 setabove = FALSE;
266
267 for (i = 0; i < h; i++) {
268 lined = datad + i * wpld;
269 if (setabove == TRUE) {
270 if (d == 8) {
271 for (j = 0; j < w; j++) {
272 if (GET_DATA_BYTE(lined, j) - threshval >= 0)
273 SET_DATA_BYTE(lined, j, setval);
274 }
275 }
276 else if (d == 16) {
277 for (j = 0; j < w; j++) {
278 if (GET_DATA_TWO_BYTES(lined, j) - threshval >= 0)
279 SET_DATA_TWO_BYTES(lined, j, setval);
280 }
281 }
282 else { /* d == 32 */
283 for (j = 0; j < w; j++) {
284 if (*(lined + j) - threshval >= 0)
285 *(lined + j) = setval;
286 }
287 }
288 }
289 else { /* set if below or at threshold */
290 if (d == 8) {
291 for (j = 0; j < w; j++) {
292 if (GET_DATA_BYTE(lined, j) - threshval <= 0)
293 SET_DATA_BYTE(lined, j, setval);
294 }
295 }
296 else if (d == 16) {
297 for (j = 0; j < w; j++) {
298 if (GET_DATA_TWO_BYTES(lined, j) - threshval <= 0)
299 SET_DATA_TWO_BYTES(lined, j, setval);
300 }
301 }
302 else { /* d == 32 */
303 for (j = 0; j < w; j++) {
304 if (*(lined + j) - threshval <= 0)
305 *(lined + j) = setval;
306 }
307 }
308 }
309 }
310 return;
311 }
312
313
314
315 /*-------------------------------------------------------------*
316 * Image accumulator arithmetic operations *
317 *-------------------------------------------------------------*/
318 /*!
319 * finalAccumulateLow()
320 */
321 void
finalAccumulateLow(l_uint32 * datad,l_int32 w,l_int32 h,l_int32 d,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_uint32 offset)322 finalAccumulateLow(l_uint32 *datad,
323 l_int32 w,
324 l_int32 h,
325 l_int32 d,
326 l_int32 wpld,
327 l_uint32 *datas,
328 l_int32 wpls,
329 l_uint32 offset)
330 {
331 l_int32 i, j;
332 l_int32 val;
333 l_uint32 *lines, *lined;
334
335 switch (d)
336 {
337 case 8:
338 for (i = 0; i < h; i++) {
339 lines = datas + i * wpls;
340 lined = datad + i * wpld;
341 for (j = 0; j < w; j++) {
342 val = lines[j] - offset;
343 val = L_MAX(0, val);
344 val = L_MIN(255, val);
345 SET_DATA_BYTE(lined, j, (l_uint8)val);
346 }
347 }
348 break;
349 case 16:
350 for (i = 0; i < h; i++) {
351 lines = datas + i * wpls;
352 lined = datad + i * wpld;
353 for (j = 0; j < w; j++) {
354 val = lines[j] - offset;
355 val = L_MAX(0, val);
356 val = L_MIN(0xffff, val);
357 SET_DATA_TWO_BYTES(lined, j, (l_uint16)val);
358 }
359 }
360 break;
361 case 32:
362 for (i = 0; i < h; i++) {
363 lines = datas + i * wpls;
364 lined = datad + i * wpld;
365 for (j = 0; j < w; j++)
366 lined[j] = lines[j] - offset;
367 }
368 break;
369 }
370 return;
371 }
372
373
374 void
finalAccumulateThreshLow(l_uint32 * datad,l_int32 w,l_int32 h,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_uint32 offset,l_uint32 threshold)375 finalAccumulateThreshLow(l_uint32 *datad,
376 l_int32 w,
377 l_int32 h,
378 l_int32 wpld,
379 l_uint32 *datas,
380 l_int32 wpls,
381 l_uint32 offset,
382 l_uint32 threshold)
383 {
384 l_int32 i, j;
385 l_int32 val;
386 l_uint32 *lines, *lined;
387
388 for (i = 0; i < h; i++) {
389 lines = datas + i * wpls;
390 lined = datad + i * wpld;
391
392 for (j = 0; j < w; j++) {
393 val = lines[j] - offset;
394 if (val >= threshold) {
395 SET_DATA_BIT(lined, j);
396 }
397 }
398 }
399 }
400
401
402 /*!
403 * accumulateLow()
404 */
405 void
accumulateLow(l_uint32 * datad,l_int32 w,l_int32 h,l_int32 wpld,l_uint32 * datas,l_int32 d,l_int32 wpls,l_int32 op)406 accumulateLow(l_uint32 *datad,
407 l_int32 w,
408 l_int32 h,
409 l_int32 wpld,
410 l_uint32 *datas,
411 l_int32 d,
412 l_int32 wpls,
413 l_int32 op)
414 {
415 l_int32 i, j;
416 l_uint32 *lines, *lined;
417
418 switch (d)
419 {
420 case 1:
421 for (i = 0; i < h; i++) {
422 lines = datas + i * wpls;
423 lined = datad + i * wpld;
424 if (op == L_ARITH_ADD) {
425 for (j = 0; j < w; j++)
426 lined[j] += GET_DATA_BIT(lines, j);
427 }
428 else { /* op == L_ARITH_SUBTRACT */
429 for (j = 0; j < w; j++)
430 lined[j] -= GET_DATA_BIT(lines, j);
431 }
432 }
433 break;
434 case 8:
435 for (i = 0; i < h; i++) {
436 lines = datas + i * wpls;
437 lined = datad + i * wpld;
438 if (op == L_ARITH_ADD) {
439 for (j = 0; j < w; j++)
440 lined[j] += GET_DATA_BYTE(lines, j);
441 }
442 else { /* op == L_ARITH_SUBTRACT */
443 for (j = 0; j < w; j++)
444 lined[j] -= GET_DATA_BYTE(lines, j);
445 }
446 }
447 break;
448 case 16:
449 for (i = 0; i < h; i++) {
450 lines = datas + i * wpls;
451 lined = datad + i * wpld;
452 if (op == L_ARITH_ADD) {
453 for (j = 0; j < w; j++)
454 lined[j] += GET_DATA_TWO_BYTES(lines, j);
455 }
456 else { /* op == L_ARITH_SUBTRACT */
457 for (j = 0; j < w; j++)
458 lined[j] -= GET_DATA_TWO_BYTES(lines, j);
459 }
460 }
461 break;
462 case 32:
463 for (i = 0; i < h; i++) {
464 lines = datas + i * wpls;
465 lined = datad + i * wpld;
466 if (op == L_ARITH_ADD) {
467 for (j = 0; j < w; j++)
468 lined[j] += lines[j];
469 }
470 else { /* op == L_ARITH_SUBTRACT */
471 for (j = 0; j < w; j++)
472 lined[j] -= lines[j];
473 }
474 }
475 break;
476 }
477 return;
478 }
479
480
481 /*!
482 * multConstAccumulateLow()
483 */
484 void
multConstAccumulateLow(l_uint32 * data,l_int32 w,l_int32 h,l_int32 wpl,l_float32 factor,l_uint32 offset)485 multConstAccumulateLow(l_uint32 *data,
486 l_int32 w,
487 l_int32 h,
488 l_int32 wpl,
489 l_float32 factor,
490 l_uint32 offset)
491 {
492 l_int32 i, j;
493 l_int32 val;
494 l_uint32 *line;
495
496 for (i = 0; i < h; i++) {
497 line = data + i * wpl;
498 for (j = 0; j < w; j++) {
499 val = line[j] - offset;
500 val = (l_int32)(val * factor);
501 val += offset;
502 line[j] = (l_uint32)val;
503 }
504 }
505 return;
506 }
507
508
509 /*-----------------------------------------------------------------------*
510 * Absolute value of difference, component-wise *
511 *-----------------------------------------------------------------------*/
512 /*!
513 * absDifferenceLow()
514 *
515 * Finds the absolute value of the difference of each pixel,
516 * for 8 and 16 bpp gray and for 32 bpp rgb. For 32 bpp, the
517 * differences are found for each of the RGB components
518 * separately, and the LSB component is ignored.
519 * The results are written into datad.
520 */
521 void
absDifferenceLow(l_uint32 * datad,l_int32 w,l_int32 h,l_int32 wpld,l_uint32 * datas1,l_uint32 * datas2,l_int32 d,l_int32 wpls)522 absDifferenceLow(l_uint32 *datad,
523 l_int32 w,
524 l_int32 h,
525 l_int32 wpld,
526 l_uint32 *datas1,
527 l_uint32 *datas2,
528 l_int32 d,
529 l_int32 wpls)
530 {
531 l_int32 i, j, val1, val2, diff;
532 l_uint32 word1, word2;
533 l_uint32 *lines1, *lines2, *lined, *pdword;
534
535 PROCNAME("absDifferenceLow");
536
537 switch (d)
538 {
539 case 8:
540 for (i = 0; i < h; i++) {
541 lines1 = datas1 + i * wpls;
542 lines2 = datas2 + i * wpls;
543 lined = datad + i * wpld;
544 for (j = 0; j < w; j++) {
545 val1 = GET_DATA_BYTE(lines1, j);
546 val2 = GET_DATA_BYTE(lines2, j);
547 diff = L_ABS(val1 - val2);
548 SET_DATA_BYTE(lined, j, diff);
549 }
550 }
551 break;
552 case 16:
553 for (i = 0; i < h; i++) {
554 lines1 = datas1 + i * wpls;
555 lines2 = datas2 + i * wpls;
556 lined = datad + i * wpld;
557 for (j = 0; j < w; j++) {
558 val1 = GET_DATA_TWO_BYTES(lines1, j);
559 val2 = GET_DATA_TWO_BYTES(lines2, j);
560 diff = L_ABS(val1 - val2);
561 SET_DATA_TWO_BYTES(lined, j, diff);
562 }
563 }
564 break;
565 case 32:
566 for (i = 0; i < h; i++) {
567 lines1 = datas1 + i * wpls;
568 lines2 = datas2 + i * wpls;
569 lined = datad + i * wpld;
570 for (j = 0; j < w; j++) {
571 word1 = lines1[j];
572 word2 = lines2[j];
573 pdword = lined + j;
574 val1 = GET_DATA_BYTE(&word1, COLOR_RED);
575 val2 = GET_DATA_BYTE(&word2, COLOR_RED);
576 diff = L_ABS(val1 - val2);
577 SET_DATA_BYTE(pdword, COLOR_RED, diff);
578 val1 = GET_DATA_BYTE(&word1, COLOR_GREEN);
579 val2 = GET_DATA_BYTE(&word2, COLOR_GREEN);
580 diff = L_ABS(val1 - val2);
581 SET_DATA_BYTE(pdword, COLOR_GREEN, diff);
582 val1 = GET_DATA_BYTE(&word1, COLOR_BLUE);
583 val2 = GET_DATA_BYTE(&word2, COLOR_BLUE);
584 diff = L_ABS(val1 - val2);
585 SET_DATA_BYTE(pdword, COLOR_BLUE, diff);
586 }
587 }
588 break;
589 default:
590 ERROR_VOID("source depth must be 8, 16 or 32 bpp", procName);
591 break;
592 }
593
594 return;
595 }
596
597