/*====================================================================* - 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; }