| /*====================================================================* |
| - Copyright (C) 2001 Leptonica. All rights reserved. |
| - This software is distributed in the hope that it will be |
| - useful, but with NO WARRANTY OF ANY KIND. |
| - No author or distributor accepts responsibility to anyone for the |
| - consequences of using this software, or for whether it serves any |
| - particular purpose or works at all, unless he or she says so in |
| - writing. Everyone is granted permission to copy, modify and |
| - redistribute this source code, for commercial or non-commercial |
| - purposes, with the following restrictions: (1) the origin of this |
| - source code must not be misrepresented; (2) modified versions must |
| - be plainly marked as such; and (3) this notice may not be removed |
| - or altered from any source or modified source distribution. |
| *====================================================================*/ |
| |
| |
| /* |
| * arithlow.c |
| * |
| * One image grayscale arithmetic (8, 16 or 32 bpp) |
| * void addConstantGrayLow() |
| * void multConstantGrayLow() |
| * |
| * Two image grayscale arithmetic (8, 16 or 32 bpp) |
| * void addGrayLow() |
| * void subtractGrayLow() |
| * |
| * Grayscale threshold operation (8, 16 or 32 bpp) |
| * void thresholdToValueLow() |
| * |
| * Image accumulator arithmetic operations (8, 16, 32 bpp) |
| * void finalAccumulateLow() |
| * void finalAccumulateThreshLow() |
| * void accumulateLow() |
| * void multConstAccumulateLow() |
| * |
| * Absolute value of difference, component-wise. |
| * void absDifferenceLow() |
| */ |
| |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <math.h> |
| #include "allheaders.h" |
| |
| |
| /*------------------------------------------------------------------* |
| * One image grayscale arithmetic (8, 16 or 32 bpp) * |
| *------------------------------------------------------------------*/ |
| /*! |
| * addConstantGrayLow() |
| */ |
| void |
| addConstantGrayLow(l_uint32 *data, |
| l_int32 w, |
| l_int32 h, |
| l_int32 d, |
| l_int32 wpl, |
| l_int32 val) |
| { |
| l_int32 i, j, pval; |
| l_uint32 *line; |
| |
| for (i = 0; i < h; i++) { |
| line = data + i * wpl; |
| if (d == 8) { |
| if (val < 0) { |
| for (j = 0; j < w; j++) { |
| pval = GET_DATA_BYTE(line, j); |
| pval = L_MAX(0, pval + val); |
| SET_DATA_BYTE(line, j, pval); |
| } |
| } |
| else { /* val >= 0 */ |
| for (j = 0; j < w; j++) { |
| pval = GET_DATA_BYTE(line, j); |
| pval = L_MIN(255, pval + val); |
| SET_DATA_BYTE(line, j, pval); |
| } |
| } |
| } |
| else if (d == 16) { |
| if (val < 0) { |
| for (j = 0; j < w; j++) { |
| pval = GET_DATA_TWO_BYTES(line, j); |
| pval = L_MAX(0, pval + val); |
| SET_DATA_TWO_BYTES(line, j, pval); |
| } |
| } |
| else { /* val >= 0 */ |
| for (j = 0; j < w; j++) { |
| pval = GET_DATA_TWO_BYTES(line, j); |
| pval = L_MIN(0xffff, pval + val); |
| SET_DATA_TWO_BYTES(line, j, pval); |
| } |
| } |
| } |
| else { /* d == 32; no check for overflow (< 0 or > 0xffffffff) */ |
| for (j = 0; j < w; j++) |
| *(line + j) += val; |
| } |
| } |
| return; |
| } |
| |
| |
| /*! |
| * multConstantGrayLow() |
| */ |
| void |
| multConstantGrayLow(l_uint32 *data, |
| l_int32 w, |
| l_int32 h, |
| l_int32 d, |
| l_int32 wpl, |
| l_float32 val) |
| { |
| l_int32 i, j, pval; |
| l_uint32 upval; |
| l_uint32 *line; |
| |
| for (i = 0; i < h; i++) { |
| line = data + i * wpl; |
| if (d == 8) { |
| for (j = 0; j < w; j++) { |
| pval = GET_DATA_BYTE(line, j); |
| pval = (l_int32)(val * pval); |
| pval = L_MIN(255, pval); |
| SET_DATA_BYTE(line, j, pval); |
| } |
| } |
| else if (d == 16) { |
| for (j = 0; j < w; j++) { |
| pval = GET_DATA_TWO_BYTES(line, j); |
| pval = (l_int32)(val * pval); |
| pval = L_MIN(0xffff, pval); |
| SET_DATA_TWO_BYTES(line, j, pval); |
| } |
| } |
| else { /* d == 32; no clipping */ |
| for (j = 0; j < w; j++) { |
| upval = *(line + j); |
| upval = (l_uint32)(val * upval); |
| *(line + j) = upval; |
| } |
| } |
| } |
| return; |
| } |
| |
| |
| /*------------------------------------------------------------------* |
| * Two image grayscale arithmetic (8, 16 or 32 bpp) * |
| *------------------------------------------------------------------*/ |
| /*! |
| * addGrayLow() |
| */ |
| void |
| addGrayLow(l_uint32 *datad, |
| l_int32 w, |
| l_int32 h, |
| l_int32 d, |
| l_int32 wpld, |
| l_uint32 *datas, |
| l_int32 wpls) |
| { |
| l_int32 i, j, val, sum; |
| l_uint32 *lines, *lined; |
| |
| |
| for (i = 0; i < h; i++) { |
| lined = datad + i * wpld; |
| lines = datas + i * wpls; |
| if (d == 8) { |
| for (j = 0; j < w; j++) { |
| sum = GET_DATA_BYTE(lines, j) + GET_DATA_BYTE(lined, j); |
| val = L_MIN(sum, 255); |
| SET_DATA_BYTE(lined, j, val); |
| } |
| } |
| else if (d == 16) { |
| for (j = 0; j < w; j++) { |
| sum = GET_DATA_TWO_BYTES(lines, j) |
| + GET_DATA_TWO_BYTES(lined, j); |
| val = L_MIN(sum, 0xffff); |
| SET_DATA_TWO_BYTES(lined, j, val); |
| } |
| } |
| else { /* d == 32; no clipping */ |
| for (j = 0; j < w; j++) |
| *(lined + j) += *(lines + j); |
| } |
| } |
| |
| return; |
| } |
| |
| |
| /*! |
| * subtractGrayLow() |
| */ |
| void |
| subtractGrayLow(l_uint32 *datad, |
| l_int32 w, |
| l_int32 h, |
| l_int32 d, |
| l_int32 wpld, |
| l_uint32 *datas, |
| l_int32 wpls) |
| { |
| l_int32 i, j, val, diff; |
| l_uint32 *lines, *lined; |
| |
| for (i = 0; i < h; i++) { |
| lined = datad + i * wpld; |
| lines = datas + i * wpls; |
| if (d == 8) { |
| for (j = 0; j < w; j++) { |
| diff = GET_DATA_BYTE(lined, j) - GET_DATA_BYTE(lines, j); |
| val = L_MAX(diff, 0); |
| SET_DATA_BYTE(lined, j, val); |
| } |
| } |
| else if (d == 16) { |
| for (j = 0; j < w; j++) { |
| diff = GET_DATA_TWO_BYTES(lined, j) |
| - GET_DATA_TWO_BYTES(lines, j); |
| val = L_MAX(diff, 0); |
| SET_DATA_TWO_BYTES(lined, j, val); |
| } |
| } |
| else { /* d == 32; no clipping */ |
| for (j = 0; j < w; j++) |
| *(lined + j) -= *(lines + j); |
| } |
| } |
| |
| return; |
| } |
| |
| |
| /*-------------------------------------------------------------* |
| * Grayscale threshold operation * |
| *-------------------------------------------------------------*/ |
| /*! |
| * thresholdToValueLow() |
| */ |
| void |
| thresholdToValueLow(l_uint32 *datad, |
| l_int32 w, |
| l_int32 h, |
| l_int32 d, |
| l_int32 wpld, |
| l_int32 threshval, |
| l_int32 setval) |
| { |
| l_int32 i, j, setabove; |
| l_uint32 *lined; |
| |
| if (setval > threshval) |
| setabove = TRUE; |
| else |
| setabove = FALSE; |
| |
| for (i = 0; i < h; i++) { |
| lined = datad + i * wpld; |
| if (setabove == TRUE) { |
| if (d == 8) { |
| for (j = 0; j < w; j++) { |
| if (GET_DATA_BYTE(lined, j) - threshval >= 0) |
| SET_DATA_BYTE(lined, j, setval); |
| } |
| } |
| else if (d == 16) { |
| for (j = 0; j < w; j++) { |
| if (GET_DATA_TWO_BYTES(lined, j) - threshval >= 0) |
| SET_DATA_TWO_BYTES(lined, j, setval); |
| } |
| } |
| else { /* d == 32 */ |
| for (j = 0; j < w; j++) { |
| if (*(lined + j) - threshval >= 0) |
| *(lined + j) = setval; |
| } |
| } |
| } |
| else { /* set if below or at threshold */ |
| if (d == 8) { |
| for (j = 0; j < w; j++) { |
| if (GET_DATA_BYTE(lined, j) - threshval <= 0) |
| SET_DATA_BYTE(lined, j, setval); |
| } |
| } |
| else if (d == 16) { |
| for (j = 0; j < w; j++) { |
| if (GET_DATA_TWO_BYTES(lined, j) - threshval <= 0) |
| SET_DATA_TWO_BYTES(lined, j, setval); |
| } |
| } |
| else { /* d == 32 */ |
| for (j = 0; j < w; j++) { |
| if (*(lined + j) - threshval <= 0) |
| *(lined + j) = setval; |
| } |
| } |
| } |
| } |
| return; |
| } |
| |
| |
| |
| /*-------------------------------------------------------------* |
| * Image accumulator arithmetic operations * |
| *-------------------------------------------------------------*/ |
| /*! |
| * finalAccumulateLow() |
| */ |
| 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) |
| { |
| l_int32 i, j; |
| l_int32 val; |
| l_uint32 *lines, *lined; |
| |
| switch (d) |
| { |
| case 8: |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val = lines[j] - offset; |
| val = L_MAX(0, val); |
| val = L_MIN(255, val); |
| SET_DATA_BYTE(lined, j, (l_uint8)val); |
| } |
| } |
| break; |
| case 16: |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val = lines[j] - offset; |
| val = L_MAX(0, val); |
| val = L_MIN(0xffff, val); |
| SET_DATA_TWO_BYTES(lined, j, (l_uint16)val); |
| } |
| } |
| break; |
| case 32: |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) |
| lined[j] = lines[j] - offset; |
| } |
| break; |
| } |
| return; |
| } |
| |
| |
| 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) |
| { |
| l_int32 i, j; |
| l_int32 val; |
| l_uint32 *lines, *lined; |
| |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| |
| for (j = 0; j < w; j++) { |
| val = lines[j] - offset; |
| if (val >= threshold) { |
| SET_DATA_BIT(lined, j); |
| } |
| } |
| } |
| } |
| |
| |
| /*! |
| * accumulateLow() |
| */ |
| 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) |
| { |
| l_int32 i, j; |
| l_uint32 *lines, *lined; |
| |
| switch (d) |
| { |
| case 1: |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| if (op == L_ARITH_ADD) { |
| for (j = 0; j < w; j++) |
| lined[j] += GET_DATA_BIT(lines, j); |
| } |
| else { /* op == L_ARITH_SUBTRACT */ |
| for (j = 0; j < w; j++) |
| lined[j] -= GET_DATA_BIT(lines, j); |
| } |
| } |
| break; |
| case 8: |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| if (op == L_ARITH_ADD) { |
| for (j = 0; j < w; j++) |
| lined[j] += GET_DATA_BYTE(lines, j); |
| } |
| else { /* op == L_ARITH_SUBTRACT */ |
| for (j = 0; j < w; j++) |
| lined[j] -= GET_DATA_BYTE(lines, j); |
| } |
| } |
| break; |
| case 16: |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| if (op == L_ARITH_ADD) { |
| for (j = 0; j < w; j++) |
| lined[j] += GET_DATA_TWO_BYTES(lines, j); |
| } |
| else { /* op == L_ARITH_SUBTRACT */ |
| for (j = 0; j < w; j++) |
| lined[j] -= GET_DATA_TWO_BYTES(lines, j); |
| } |
| } |
| break; |
| case 32: |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| if (op == L_ARITH_ADD) { |
| for (j = 0; j < w; j++) |
| lined[j] += lines[j]; |
| } |
| else { /* op == L_ARITH_SUBTRACT */ |
| for (j = 0; j < w; j++) |
| lined[j] -= lines[j]; |
| } |
| } |
| break; |
| } |
| return; |
| } |
| |
| |
| /*! |
| * multConstAccumulateLow() |
| */ |
| void |
| multConstAccumulateLow(l_uint32 *data, |
| l_int32 w, |
| l_int32 h, |
| l_int32 wpl, |
| l_float32 factor, |
| l_uint32 offset) |
| { |
| l_int32 i, j; |
| l_int32 val; |
| l_uint32 *line; |
| |
| for (i = 0; i < h; i++) { |
| line = data + i * wpl; |
| for (j = 0; j < w; j++) { |
| val = line[j] - offset; |
| val = (l_int32)(val * factor); |
| val += offset; |
| line[j] = (l_uint32)val; |
| } |
| } |
| return; |
| } |
| |
| |
| /*-----------------------------------------------------------------------* |
| * Absolute value of difference, component-wise * |
| *-----------------------------------------------------------------------*/ |
| /*! |
| * absDifferenceLow() |
| * |
| * Finds the absolute value of the difference of each pixel, |
| * for 8 and 16 bpp gray and for 32 bpp rgb. For 32 bpp, the |
| * differences are found for each of the RGB components |
| * separately, and the LSB component is ignored. |
| * The results are written into datad. |
| */ |
| 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) |
| { |
| l_int32 i, j, val1, val2, diff; |
| l_uint32 word1, word2; |
| l_uint32 *lines1, *lines2, *lined, *pdword; |
| |
| PROCNAME("absDifferenceLow"); |
| |
| switch (d) |
| { |
| case 8: |
| for (i = 0; i < h; i++) { |
| lines1 = datas1 + i * wpls; |
| lines2 = datas2 + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val1 = GET_DATA_BYTE(lines1, j); |
| val2 = GET_DATA_BYTE(lines2, j); |
| diff = L_ABS(val1 - val2); |
| SET_DATA_BYTE(lined, j, diff); |
| } |
| } |
| break; |
| case 16: |
| for (i = 0; i < h; i++) { |
| lines1 = datas1 + i * wpls; |
| lines2 = datas2 + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val1 = GET_DATA_TWO_BYTES(lines1, j); |
| val2 = GET_DATA_TWO_BYTES(lines2, j); |
| diff = L_ABS(val1 - val2); |
| SET_DATA_TWO_BYTES(lined, j, diff); |
| } |
| } |
| break; |
| case 32: |
| for (i = 0; i < h; i++) { |
| lines1 = datas1 + i * wpls; |
| lines2 = datas2 + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| word1 = lines1[j]; |
| word2 = lines2[j]; |
| pdword = lined + j; |
| val1 = GET_DATA_BYTE(&word1, COLOR_RED); |
| val2 = GET_DATA_BYTE(&word2, COLOR_RED); |
| diff = L_ABS(val1 - val2); |
| SET_DATA_BYTE(pdword, COLOR_RED, diff); |
| val1 = GET_DATA_BYTE(&word1, COLOR_GREEN); |
| val2 = GET_DATA_BYTE(&word2, COLOR_GREEN); |
| diff = L_ABS(val1 - val2); |
| SET_DATA_BYTE(pdword, COLOR_GREEN, diff); |
| val1 = GET_DATA_BYTE(&word1, COLOR_BLUE); |
| val2 = GET_DATA_BYTE(&word2, COLOR_BLUE); |
| diff = L_ABS(val1 - val2); |
| SET_DATA_BYTE(pdword, COLOR_BLUE, diff); |
| } |
| } |
| break; |
| default: |
| ERROR_VOID("source depth must be 8, 16 or 32 bpp", procName); |
| break; |
| } |
| |
| return; |
| } |
| |