diff options
author | scuri <scuri> | 2009-10-01 02:56:38 +0000 |
---|---|---|
committer | scuri <scuri> | 2009-10-01 02:56:38 +0000 |
commit | 62783aee16f96fe5e513fb230b8efddaa02981df (patch) | |
tree | 9dc512b0c758025c5cddba9709420f1bf9058675 | |
parent | 9a5e93213e08601a58725f44035ac622fb68e849 (diff) |
New: functions imProcessUnsharp and imProcessSharp.
Changed: now imProcessUnArithmeticOp, imProcessArithmeticConstOp and imProcessArithmeticOp willl crop the result to 0-255 if destiny has data type byte.
Changed: removed IM_UN_INC operation from imProcessUnArithmeticOp. It was not an unary operation. Can simply be done in place by imProcessArithmeticOp and IM_BIN_ADD.
-rw-r--r-- | html/en/history.html | 11 | ||||
-rw-r--r-- | include/im_complex.h | 20 | ||||
-rw-r--r-- | include/im_math_op.h | 15 | ||||
-rw-r--r-- | include/im_process_loc.h | 29 | ||||
-rw-r--r-- | include/im_process_pon.h | 20 | ||||
-rw-r--r-- | src/im_process.def | 3 | ||||
-rw-r--r-- | src/lua5/im_process.lua | 3 | ||||
-rw-r--r-- | src/lua5/imlua_process.c | 56 | ||||
-rw-r--r-- | src/process/im_arithmetic_bin.cpp | 98 | ||||
-rw-r--r-- | src/process/im_arithmetic_un.cpp | 64 | ||||
-rw-r--r-- | src/process/im_convolve.cpp | 190 |
11 files changed, 420 insertions, 89 deletions
diff --git a/html/en/history.html b/html/en/history.html index afff43e..99da0f2 100644 --- a/html/en/history.html +++ b/html/en/history.html @@ -14,7 +14,9 @@ <h3 dir="ltr"> CVS (28/Set/2009)</h3> <ul> - <li><span style="color: #0000FF">New:</span> function <strong> + <li><span style="color: #0000FF">New:</span> functions <strong> + imProcessUnsharp</strong> and <strong>imProcessSharp</strong>.</li> + <li><span style="color: #0000FF">New:</span> function <strong> imImageGetOpenGLData</strong>.</li> <li><span style="color: #0000FF">New:</span> functions <strong> im.ConvertDataTypeNew</strong>, <strong>im.ConvertColorSpaceNew</strong> @@ -38,6 +40,13 @@ <li><span style="color: #008000">Changed: </span><strong>imProcessPrune</strong> renamed to <strong>imProcessRemoveByArea</strong>, and added a new parameter to select inside or outside the interval.</li> + <li><span style="color: #008000">Changed: </span>removed IM_UN_INC operation from <strong>imProcessUnArithmeticOp</strong>. + It was not an unary operation. Can simply be done in place by <strong> + imProcessArithmeticOp</strong> and IM_BIN_ADD. </li> + <li><span style="color: #008000">Changed: </span>now<strong> imProcessUnArithmeticOp</strong>, + <strong>imProcessArithmeticConstOp</strong> and <strong> + imProcessArithmeticOp</strong> willl crop the result to 0-255 if destiny + has data type byte.</li> <li><span style="color: #008000"><span style="color: #ff0000">Fixed:</span><span style="color: #000000"> PNG attribute TransparencyIndex. new PNG attribute TransparencyMap. TransparentColor renamed to diff --git a/include/im_complex.h b/include/im_complex.h index 2ac4d92..1328dd5 100644 --- a/include/im_complex.h +++ b/include/im_complex.h @@ -54,6 +54,26 @@ inline int operator <= (const imcfloat& C, const float& F) return ((F <= C.real) && (0 <= C.imag)); } +inline int operator < (const imcfloat& C1, const imcfloat& C2) +{ + return ((C1.real < C2.real) && (C1.imag < C2.imag)); +} + +inline int operator < (const imcfloat& C, const float& F) +{ + return ((F < C.real) && (0 < C.imag)); +} + +inline int operator > (const imcfloat& C1, const imcfloat& C2) +{ + return ((C1.real > C2.real) && (C1.imag > C2.imag)); +} + +inline int operator > (const imcfloat& C, const float& F) +{ + return ((F > C.real) && (0 > C.imag)); +} + inline imcfloat operator + (const imcfloat& C1, const imcfloat& C2) { return imcfloat(C1.real + C2.real, C1.imag + C2.imag); diff --git a/include/im_math_op.h b/include/im_math_op.h index f410c62..2a4794f 100644 --- a/include/im_math_op.h +++ b/include/im_math_op.h @@ -9,14 +9,12 @@ #include "im_complex.h" -//#define IM_NEARZERO 0.0000001f -//#define IM_NEARINF 10000000 /// Crop value to Byte limit template <class T> inline T crop_byte(const T& v) { - return v <= 0? 0: v <= 255? v: 255; + return v < 0? 0: v > 255? 255: v; } /// Generic Addition with 2 template types @@ -44,7 +42,6 @@ inline T1 mul_op(const T1& v1, const T2& v2) template <class T1, class T2> inline T1 div_op(const T1& v1, const T2& v2) { -// if (v2 == 0) return (T1)IM_NEARINF; return v1 / v2; } @@ -52,7 +49,6 @@ inline T1 div_op(const T1& v1, const T2& v2) template <class T> inline T inv_op(const T& v) { -// if (v == 0) return (T)IM_NEARINF; return 1/v; } @@ -60,7 +56,7 @@ inline T inv_op(const T& v) template <class T1, class T2> inline T1 diff_op(const T1& v1, const T2& v2) { - if (v1 <= v2) + if (v1 < v2) return v2 - v1; return v1 - v2; } @@ -69,7 +65,7 @@ inline T1 diff_op(const T1& v1, const T2& v2) template <class T1, class T2> inline T1 min_op(const T1& v1, const T2& v2) { - if (v1 <= v2) + if (v1 < v2) return v1; return v2; } @@ -78,7 +74,7 @@ inline T1 min_op(const T1& v1, const T2& v2) template <class T1, class T2> inline T1 max_op(const T1& v1, const T2& v2) { - if (v1 <= v2) + if (v1 < v2) return v2; return v1; } @@ -109,7 +105,7 @@ inline T1 pow_op(const T1& v1, const T2& v2) template <class T> inline T abs_op(const T& v) { - if (v <= 0) + if (v < 0) return -1*v; return v; } @@ -161,7 +157,6 @@ inline int log(const int& v) template <class T> inline T log_op(const T& v) { -// if (v <= 0) return (T)IM_NEARINF; return (T)log(v); } diff --git a/include/im_process_loc.h b/include/im_process_loc.h index 9c0531b..44e8281 100644 --- a/include/im_process_loc.h +++ b/include/im_process_loc.h @@ -569,6 +569,35 @@ int imGaussianStdDev2KernelSize(float stddev); * \ingroup convolve */ float imGaussianKernelSize2StdDev(int kernel_size); +/** Edge enhancement using Unsharp mask. stddev control the gaussian filter, + * amount controls how much the edges will enhance the image (0<amount<1), and + * threshold controls which edges will be considered, it compares to twice of the absolute size of the edge. + * Although very similar to \ref imProcessSharp, produces better results. + * + * \verbatim im.ProcessUnsharp(src_image: imImage, dst_image: imImage, stddev: number, amount: number, threshold: number) [in Lua 5] \endverbatim + * \verbatim im.ProcessUnsharpNew(image: imImage, stddev: number, amount: number, threshold: number) -> new_image: imImage [in Lua 5] \endverbatim + * \ingroup convolve */ +int imProcessUnsharp(const imImage* src_image, imImage* dst_image, float stddev, float amount, float threshold); + +/** Edge enhancement using Laplacian8 mask. + * amount controls how much the edges will enhance the image (0<amount<1), and + * threshold controls which edges will be considered, it compares to twice of the absolute size of the edge. + * + * \verbatim im.ProcessSharp(src_image: imImage, dst_image: imImage, amount: number, threshold: number) [in Lua 5] \endverbatim + * \verbatim im.ProcessSharpNew(image: imImage, amount: number, threshold: number) -> new_image: imImage [in Lua 5] \endverbatim + * \ingroup convolve */ +int imProcessSharp(const imImage* src_image, imImage* dst_image, float amount, float threshold); + +/** Edge enhancement using a given kernel. + * If kernel has all positive values, then the unsharp technique is used, else sharp is used. + * amount controls how much the edges will enhance the image (0<amount<1), and + * threshold controls which edges will be considered, it compares to twice of the absolute size of the edge. + * + * \verbatim im.ProcessSharp(src_image: imImage, dst_image: imImage, amount: number, threshold: number) [in Lua 5] \endverbatim + * \verbatim im.ProcessSharpNew(image: imImage, amount: number, threshold: number) -> new_image: imImage [in Lua 5] \endverbatim + * \ingroup convolve */ +int imProcessSharpKernel(const imImage* src_image, const imImage* kernel, imImage* dst_image, float amount, float threshold); + #if defined(__cplusplus) } diff --git a/include/im_process_pon.h b/include/im_process_pon.h index bf09a71..0611cc6 100644 --- a/include/im_process_pon.h +++ b/include/im_process_pon.h @@ -22,14 +22,13 @@ extern "C" { * See \ref im_process_pon.h * \ingroup process */ -/** Unary Arithmetic Operations. +/** Unary Arithmetic Operations. \n * Inverse and log may lead to math exceptions. * \ingroup arithm */ enum imUnaryOp { IM_UN_EQL, /**< equal = a */ IM_UN_ABS, /**< abssolute = |a| */ IM_UN_LESS, /**< less = -a */ - IM_UN_INC, /**< increment += a */ IM_UN_INV, /**< invert = 1/a (#) */ IM_UN_SQR, /**< square = a*a */ IM_UN_SQRT, /**< square root = a^(1/2) */ @@ -42,15 +41,22 @@ enum imUnaryOp { }; /** Apply an arithmetic unary operation. \n - * Can be done in place, images must match size, does not need to match type. + * Can be done in place, images must match size. \n + * Destiny image can be several types depending on source: \n + * \li byte -> byte, ushort, int, float + * \li ushort -> byte, ushort, int, float + * \li int -> byte, ushort, int, float + * \li float -> float + * \li complex -> complex + * If destiny is byte, then the result is cropped to 0-255. * * \verbatim im.ProcessUnArithmeticOp(src_image: imImage, dst_image: imImage, op: number) [in Lua 5] \endverbatim * \verbatim im.ProcessUnArithmeticOpNew(image: imImage, op: number) -> new_image: imImage [in Lua 5] \endverbatim * \ingroup arithm */ void imProcessUnArithmeticOp(const imImage* src_image, imImage* dst_image, int op); -/** Binary Arithmetic Operations. - * Inverse and log may lead to math exceptions. +/** Binary Arithmetic Operations. \n + * Divide may lead to math exceptions. * \ingroup arithm */ enum imBinaryOp { IM_BIN_ADD, /**< add = a+b */ @@ -72,6 +78,7 @@ enum imBinaryOp { * \li float -> float * \li complex -> complex * One exception is that you can combine complex with float resulting complex. + * If destiny is byte, then the result is cropped to 0-255. * * \verbatim im.ProcessArithmeticOp(src_image1: imImage, src_image2: imImage, dst_image: imImage, op: number) [in Lua 5] \endverbatim * \verbatim im.ProcessArithmeticOpNew(image1: imImage, image2: imImage, op: number) -> new_image: imImage [in Lua 5] \endverbatim @@ -88,6 +95,7 @@ void imProcessArithmeticOp(const imImage* src_image1, const imImage* src_image2, * \li float -> float * \li complex -> complex * The constant value is type casted to an apropriate type before the operation. + * If destiny is byte, then the result is cropped to 0-255. * * \verbatim im.ProcessArithmeticConstOp(src_image: imImage, src_const: number, dst_image: imImage, op: number) [in Lua 5] \endverbatim * \verbatim im.ProcessArithmeticConstOpNew(image: imImage, src_const: number, op: number) -> new_image: imImage [in Lua 5] \endverbatim @@ -523,7 +531,7 @@ enum imToneGamut { * Supports all data types except IM_CFLOAT. \n * The linear operation do a special convertion when min > 0 and max < 1, it forces min=0 and max=1. \n * IM_BYTE images have min=0 and max=255 always. \n - * Can be done in place. When there is no extra params use NULL. + * Can be done in place. When there is no extra params, can use NULL. * * \verbatim im.ProcessToneGamut(src_image: imImage, dst_image: imImage, op: number, param: table of number) [in Lua 5] \endverbatim * \verbatim im.ProcessToneGamutNew(src_image: imImage, op: number, param: table of number) -> new_image: imImage [in Lua 5] \endverbatim diff --git a/src/im_process.def b/src/im_process.def index fd3d5dd..07bba47 100644 --- a/src/im_process.def +++ b/src/im_process.def @@ -160,3 +160,6 @@ EXPORTS imProcessRotateRef imProcessInterlaceSplit imProcessBarlettConvolve + imProcessUnsharp + imProcessSharp + imProcessSharpKernel diff --git a/src/lua5/im_process.lua b/src/lua5/im_process.lua index eb9cae6..d74c6b1 100644 --- a/src/lua5/im_process.lua +++ b/src/lua5/im_process.lua @@ -243,6 +243,9 @@ OneSourceOneDest("ProcessZeroCrossing") OneSourceOneDest("ProcessCanny") OneSourceOneDest("ProcessUnArithmeticOp") TwoSourcesOneDest("ProcessArithmeticOp") +OneSourceOneDest("ProcessUnsharp") +OneSourceOneDest("ProcessSharp") +TwoSourcesOneDest("ProcessSharpKernel") function im.ProcessArithmeticConstOpNew (src_image, src_const, op) local dst_image = im.ImageCreateBased(src_image) diff --git a/src/lua5/imlua_process.c b/src/lua5/imlua_process.c index fa6dc89..863c1d6 100644 --- a/src/lua5/imlua_process.c +++ b/src/lua5/imlua_process.c @@ -2,7 +2,7 @@ * \brief IM Lua 5 Binding * * See Copyright Notice in im_lib.h - * $Id: imlua_process.c,v 1.7 2009/09/28 20:19:09 scuri Exp $ + * $Id: imlua_process.c,v 1.8 2009/10/01 02:56:58 scuri Exp $ */ #include <memory.h> @@ -1475,6 +1475,56 @@ static int imluaProcessCanny (lua_State *L) } /*****************************************************************************\ + im.ProcessUnsharp +\*****************************************************************************/ +static int imluaProcessUnsharp(lua_State *L) +{ + imImage *src_image = imlua_checkimage(L, 1); + imImage *dst_image = imlua_checkimage(L, 2); + float p1 = (float)luaL_checknumber(L, 3); + float p2 = (float)luaL_checknumber(L, 4); + float p3 = (float)luaL_checknumber(L, 5); + + imlua_match(L, src_image, dst_image); + + imProcessUnsharp(src_image, dst_image, p1, p2, p3); + return 0; +} + +/*****************************************************************************\ + im.ProcessSharp +\*****************************************************************************/ +static int imluaProcessSharp(lua_State *L) +{ + imImage *src_image = imlua_checkimage(L, 1); + imImage *dst_image = imlua_checkimage(L, 2); + float p1 = (float)luaL_checknumber(L, 3); + float p2 = (float)luaL_checknumber(L, 4); + + imlua_match(L, src_image, dst_image); + + imProcessSharp(src_image, dst_image, p1, p2); + return 0; +} + +/*****************************************************************************\ + im.ProcessSharpKernel +\*****************************************************************************/ +static int imluaProcessSharpKernel(lua_State *L) +{ + imImage *src_image = imlua_checkimage(L, 1); + imImage *kernel = imlua_checkimage(L, 2); + imImage *dst_image = imlua_checkimage(L, 3); + float p1 = (float)luaL_checknumber(L, 4); + float p2 = (float)luaL_checknumber(L, 5); + + imlua_match(L, src_image, dst_image); + + imProcessSharpKernel(src_image, kernel, dst_image, p1, p2); + return 0; +} + +/*****************************************************************************\ im.GaussianStdDev2Repetitions \*****************************************************************************/ static int imluaGaussianKernelSize2StdDev(lua_State *L) @@ -2927,6 +2977,9 @@ static const luaL_reg improcess_lib[] = { {"ProcessSplineEdgeConvolve", imluaProcessSplineEdgeConvolve}, {"ProcessZeroCrossing", imluaProcessZeroCrossing}, {"ProcessCanny", imluaProcessCanny}, + {"ProcessUnsharp", imluaProcessUnsharp}, + {"ProcessSharp", imluaProcessSharp}, + {"ProcessSharpKernel", imluaProcessSharpKernel}, {"GaussianKernelSize2StdDev", imluaGaussianKernelSize2StdDev}, {"GaussianStdDev2KernelSize", imluaGaussianStdDev2KernelSize}, @@ -3013,7 +3066,6 @@ static const imlua_constant im_process_constants[] = { { "UN_EQL", IM_UN_EQL, NULL }, { "UN_ABS", IM_UN_ABS, NULL }, { "UN_LESS", IM_UN_LESS, NULL }, - { "UN_INC", IM_UN_INC, NULL }, { "UN_INV", IM_UN_INV, NULL }, { "UN_SQR", IM_UN_SQR, NULL }, { "UN_SQRT", IM_UN_SQRT, NULL }, diff --git a/src/process/im_arithmetic_bin.cpp b/src/process/im_arithmetic_bin.cpp index 74fe010..494b6c0 100644 --- a/src/process/im_arithmetic_bin.cpp +++ b/src/process/im_arithmetic_bin.cpp @@ -2,7 +2,7 @@ * \brief Binary Arithmetic Operations * * See Copyright Notice in im_lib.h - * $Id: im_arithmetic_bin.cpp,v 1.1 2008/10/17 06:16:33 scuri Exp $ + * $Id: im_arithmetic_bin.cpp,v 1.2 2009/10/01 02:56:58 scuri Exp $ */ @@ -61,6 +61,47 @@ static void DoBinaryOp(T1 *map1, T2 *map2, T3 *map, int count, int op) } } +static void DoBinaryOpByte(imbyte *map1, imbyte *map2, imbyte *map, int count, int op) +{ + int i; + + switch(op) + { + case IM_BIN_ADD: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(add_op((int)map1[i], (int)map2[i])); + break; + case IM_BIN_SUB: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(sub_op((int)map1[i], (int)map2[i])); + break; + case IM_BIN_MUL: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(mul_op((int)map1[i], (int)map2[i])); + break; + case IM_BIN_DIV: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(div_op((int)map1[i], (int)map2[i])); + break; + case IM_BIN_DIFF: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(diff_op((int)map1[i], (int)map2[i])); + break; + case IM_BIN_MIN: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(min_op((int)map1[i], (int)map2[i])); + break; + case IM_BIN_MAX: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(max_op((int)map1[i], (int)map2[i])); + break; + case IM_BIN_POW: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(pow_op((int)map1[i], (int)map2[i])); + break; + } +} + static void DoBinaryOpCpxReal(imcfloat *map1, float *map2, imcfloat *map, int count, int op) { int i; @@ -118,7 +159,7 @@ void imProcessArithmeticOp(const imImage* src_image1, const imImage* src_image2, else if (dst_image->data_type == IM_INT) DoBinaryOp((imbyte*)src_image1->data[i], (imbyte*)src_image2->data[i], (int*)dst_image->data[i], count, op); else - DoBinaryOp((imbyte*)src_image1->data[i], (imbyte*)src_image2->data[i], (imbyte*)dst_image->data[i], count, op); + DoBinaryOpByte((imbyte*)src_image1->data[i], (imbyte*)src_image2->data[i], (imbyte*)dst_image->data[i], count, op); break; case IM_USHORT: if (dst_image->data_type == IM_FLOAT) @@ -304,6 +345,48 @@ static void DoBinaryConstOp(T1 *map1, T2 value, T3 *map, int count, int op) } } +template <class T1> +static void DoBinaryConstOpByte(T1 *map1, int value, imbyte *map, int count, int op) +{ + int i; + + switch(op) + { + case IM_BIN_ADD: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(add_op((int)map1[i], value)); + break; + case IM_BIN_SUB: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(sub_op((int)map1[i], value)); + break; + case IM_BIN_MUL: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(mul_op((int)map1[i], value)); + break; + case IM_BIN_DIV: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(div_op((int)map1[i], value)); + break; + case IM_BIN_DIFF: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(diff_op((int)map1[i], value)); + break; + case IM_BIN_MIN: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(min_op((int)map1[i], value)); + break; + case IM_BIN_MAX: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(max_op((int)map1[i], value)); + break; + case IM_BIN_POW: + for (i = 0; i < count; i++) + map[i] = (imbyte)crop_byte(pow_op((int)map1[i], value)); + break; + } +} + void imProcessArithmeticConstOp(const imImage* src_image1, float value, imImage* dst_image, int op) { int count = src_image1->count; @@ -320,7 +403,7 @@ void imProcessArithmeticConstOp(const imImage* src_image1, float value, imImage* else if (dst_image->data_type == IM_INT) DoBinaryConstOp((imbyte*)src_image1->data[i], (int)value, (int*)dst_image->data[i], count, op); else - DoBinaryConstOp((imbyte*)src_image1->data[i], (imushort)value, (imbyte*)dst_image->data[i], count, op); + DoBinaryConstOpByte((imbyte*)src_image1->data[i], (int)value, (imbyte*)dst_image->data[i], count, op); break; case IM_USHORT: if (dst_image->data_type == IM_FLOAT) @@ -328,7 +411,7 @@ void imProcessArithmeticConstOp(const imImage* src_image1, float value, imImage* else if (dst_image->data_type == IM_INT) DoBinaryConstOp((imushort*)src_image1->data[i], (int)value, (int*)dst_image->data[i], count, op); else if (dst_image->data_type == IM_BYTE) - DoBinaryConstOp((imushort*)src_image1->data[i], (imushort)value, (imbyte*)dst_image->data[i], count, op); + DoBinaryConstOpByte((imushort*)src_image1->data[i], (int)value, (imbyte*)dst_image->data[i], count, op); else DoBinaryConstOp((imushort*)src_image1->data[i], (imushort)value, (imushort*)dst_image->data[i], count, op); break; @@ -338,7 +421,7 @@ void imProcessArithmeticConstOp(const imImage* src_image1, float value, imImage* else if (dst_image->data_type == IM_USHORT) DoBinaryConstOp((int*)src_image1->data[i], (int)value, (imushort*)dst_image->data[i], count, op); else if (dst_image->data_type == IM_BYTE) - DoBinaryConstOp((int*)src_image1->data[i], (int)value, (imbyte*)dst_image->data[i], count, op); + DoBinaryConstOpByte((int*)src_image1->data[i], (int)value, (imbyte*)dst_image->data[i], count, op); else DoBinaryConstOp((int*)src_image1->data[i], (int)value, (int*)dst_image->data[i], count, op); break; @@ -367,7 +450,8 @@ void imProcessMultipleMean(const imImage** src_image_list, int src_image_count, for(int i = 0; i < src_image_count; i++) { const imImage *image = src_image_list[i]; - imProcessUnArithmeticOp(image, acum_image, IM_UN_INC); + imProcessArithmeticOp(image, acum_image, acum_image, IM_BIN_ADD); /* acum_image += image */ + } imProcessArithmeticConstOp(acum_image, float(src_image_count), dst_image, IM_BIN_DIV); @@ -393,7 +477,7 @@ void imProcessMultipleStdDev(const imImage** src_image_list, int src_image_count imProcessUnArithmeticOp(aux_image, aux_image, IM_UN_SQR); // dst_image += aux_image - imProcessUnArithmeticOp(aux_image, dst_image, IM_UN_INC); + imProcessArithmeticOp(aux_image, dst_image, dst_image, IM_BIN_ADD); } // dst_image = dst_image / src_image_count; diff --git a/src/process/im_arithmetic_un.cpp b/src/process/im_arithmetic_un.cpp index 59e384c..e4dba8a 100644 --- a/src/process/im_arithmetic_un.cpp +++ b/src/process/im_arithmetic_un.cpp @@ -2,7 +2,7 @@ * \brief Unary Arithmetic Operations * * See Copyright Notice in im_lib.h - * $Id: im_arithmetic_un.cpp,v 1.1 2008/10/17 06:16:33 scuri Exp $ + * $Id: im_arithmetic_un.cpp,v 1.2 2009/10/01 02:56:58 scuri Exp $ */ @@ -71,10 +71,6 @@ static void DoUnaryOp(T1 *map, T2 *new_map, int count, int op) for (i = 0; i < count; i++) new_map[i] = (T2)map[i]; break; - case IM_UN_INC: - for (i = 0; i < count; i++) - new_map[i] = (T2)(new_map[i] + map[i]); - break; case IM_UN_LESS: for (i = 0; i < count; i++) new_map[i] = less_op((T2)map[i]); @@ -85,7 +81,7 @@ static void DoUnaryOp(T1 *map, T2 *new_map, int count, int op) break; case IM_UN_SQRT: for (i = 0; i < count; i++) - new_map[i] = (T2)sqrt_op(map[i]); + new_map[i] = sqrt_op((T2)map[i]); break; case IM_UN_LOG: for (i = 0; i < count; i++) @@ -114,6 +110,56 @@ static void DoUnaryOp(T1 *map, T2 *new_map, int count, int op) } } +template <class T1> +static void DoUnaryOpByte(T1 *map, imbyte *new_map, int count, int op) +{ + int i; + + switch(op) + { + case IM_UN_ABS: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(abs_op((int)map[i])); + break; + case IM_UN_INV: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(inv_op((int)map[i])); /* will always be 0 */ + break; + case IM_UN_EQL: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte((int)map[i]); + break; + case IM_UN_LESS: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(less_op((int)map[i])); + break; + case IM_UN_SQR: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(sqr_op((int)map[i])); + break; + case IM_UN_SQRT: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(sqrt_op((int)map[i])); + break; + case IM_UN_LOG: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(log_op((int)map[i])); + break; + case IM_UN_SIN: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(sin_op((int)map[i])); + break; + case IM_UN_COS: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(cos_op((int)map[i])); + break; + case IM_UN_EXP: + for (i = 0; i < count; i++) + new_map[i] = (imbyte)crop_byte(exp_op((int)map[i])); + break; + } +} + void imProcessUnArithmeticOp(const imImage* src_image, imImage* dst_image, int op) { int total_count = src_image->count * src_image->depth; @@ -128,11 +174,11 @@ void imProcessUnArithmeticOp(const imImage* src_image, imImage* dst_image, int o else if (dst_image->data_type == IM_USHORT) DoUnaryOp((imbyte*)src_image->data[0], (imushort*)dst_image->data[0], total_count, op); else - DoUnaryOp((imbyte*)src_image->data[0], (imbyte*)dst_image->data[0], total_count, op); + DoUnaryOpByte((imbyte*)src_image->data[0], (imbyte*)dst_image->data[0], total_count, op); break; case IM_USHORT: if (dst_image->data_type == IM_BYTE) - DoUnaryOp((imushort*)src_image->data[0], (imbyte*)dst_image->data[0], total_count, op); + DoUnaryOpByte((imushort*)src_image->data[0], (imbyte*)dst_image->data[0], total_count, op); else if (dst_image->data_type == IM_INT) DoUnaryOp((imushort*)src_image->data[0], (int*)dst_image->data[0], total_count, op); else if (dst_image->data_type == IM_FLOAT) @@ -142,7 +188,7 @@ void imProcessUnArithmeticOp(const imImage* src_image, imImage* dst_image, int o break; case IM_INT: if (dst_image->data_type == IM_BYTE) - DoUnaryOp((int*)src_image->data[0], (imbyte*)dst_image->data[0], total_count, op); + DoUnaryOpByte((int*)src_image->data[0], (imbyte*)dst_image->data[0], total_count, op); else if (dst_image->data_type == IM_USHORT) DoUnaryOp((int*)src_image->data[0], (imushort*)dst_image->data[0], total_count, op); else if (dst_image->data_type == IM_FLOAT) diff --git a/src/process/im_convolve.cpp b/src/process/im_convolve.cpp index bca2dcd..a88a25c 100644 --- a/src/process/im_convolve.cpp +++ b/src/process/im_convolve.cpp @@ -2,7 +2,7 @@ * \brief Convolution Operations * * See Copyright Notice in im_lib.h - * $Id: im_convolve.cpp,v 1.1 2008/10/17 06:16:33 scuri Exp $ + * $Id: im_convolve.cpp,v 1.2 2009/10/01 02:56:58 scuri Exp $ */ @@ -1426,59 +1426,6 @@ int imProcessDiffOfGaussianConvolve(const imImage* src_image, imImage* dst_image return 1; } -#ifdef _TEST_CODE_ -int imProcessDiffOfGaussianConvolveTEST(const imImage* src_image, imImage* dst_image, float stddev1, float stddev2) -{ - int kernel_size1 = imGaussianStdDev2KernelSize(stddev1); - int kernel_size2 = imGaussianStdDev2KernelSize(stddev2); - int size = kernel_size1; - if (kernel_size1 < kernel_size2) size = kernel_size2; - - imImage* kernel1 = imImageCreate(size, size, IM_GRAY, IM_FLOAT); - imImage* kernel2 = imImageCreate(size, size, IM_GRAY, IM_FLOAT); - if (!kernel1 || !kernel2) - { - if (kernel1) imImageDestroy(kernel1); - if (kernel2) imImageDestroy(kernel2); - return 0; - } - - imImageSetAttribute(kernel1, "Description", IM_BYTE, -1, (void*)"Gaussian"); - imImageSetAttribute(kernel2, "Description", IM_BYTE, -1, (void*)"Gaussian"); - - imProcessRenderGaussian(kernel1, stddev1); - imProcessRenderGaussian(kernel2, stddev2); - - // ERROR: kernel 1 should be multiplied by a factor to improve the difference. - - imProcessArithmeticOp(kernel1, kernel2, kernel1, IM_BIN_SUB); - imImageSetAttribute(kernel1, "Description", IM_BYTE, -1, (void*)"Difference of Gaussian"); - - int ret = 0; - if (src_image->data_type == IM_BYTE || src_image->data_type == IM_USHORT) - { - imImage* aux_image = imImageClone(dst_image); - if (!aux_image) - { - imImageDestroy(kernel1); - imImageDestroy(kernel2); - return 0; - } - - imProcessUnArithmeticOp(src_image, aux_image, IM_UN_EQL); // Convert to IM_INT - ret = imProcessConvolve(aux_image, dst_image, kernel1); - imImageDestroy(aux_image); - } - else - ret = imProcessConvolve(src_image, dst_image, kernel1); - - imImageDestroy(kernel1); - imImageDestroy(kernel2); - - return ret; -} -#endif - int imProcessMeanConvolve(const imImage* src_image, imImage* dst_image, int ks) { int counter = imCounterBegin("Mean Convolve"); @@ -1510,3 +1457,138 @@ int imProcessMeanConvolve(const imImage* src_image, imImage* dst_image, int ks) return ret; } + +template <class T1, class T2> +static void DoSharpOp(T1 *src_map, T1 *dst_map, int count, float amount, T2 threshold, int gauss) +{ + int i; + T1 min, max; + + int size_of = sizeof(imbyte); + if (sizeof(T1) == size_of) + { + min = 0; + max = 255; + } + else + { + imMinMax(src_map, count, min, max); + + if (min == max) + { + max = min + 1; + + if (min != 0) + min = min - 1; + } + } + + for (i = 0; i < count; i++) + { + T2 diff; + + if (gauss) + diff = 20*(src_map[i] - dst_map[i]); /* dst_map contains a gaussian filter of the source image, must compensate for small edge values */ + else + diff = dst_map[i]; /* dst_map contains a laplacian filter of the source image */ + + if (threshold && abs_op(2*diff) < threshold) + diff = 0; + + T2 value = (T2)(src_map[i] + amount*diff); + if (value < min) + value = min; + else if (value > max) + value = max; + + dst_map[i] = (T1)value; + } +} + +static void doSharp(const imImage* src_image, imImage* dst_image, float amount, float threshold, int gauss) +{ + int count = src_image->count; + + for (int i = 0; i < src_image->depth; i++) + { + switch(src_image->data_type) + { + case IM_BYTE: + DoSharpOp((imbyte*)src_image->data[i], (imbyte*)dst_image->data[i], count, amount, (int)threshold, gauss); + break; + case IM_USHORT: + DoSharpOp((imushort*)src_image->data[i], (imushort*)dst_image->data[i], count, amount, (int)threshold, gauss); + break; + case IM_INT: + DoSharpOp((int*)src_image->data[i], (int*)dst_image->data[i], count, amount, (int)threshold, gauss); + break; + case IM_FLOAT: + DoSharpOp((float*)src_image->data[i], (float*)dst_image->data[i], count, amount, (float)threshold, gauss); + break; + } + } +} + +int imProcessUnsharp(const imImage* src_image, imImage* dst_image, float stddev, float amount, float threshold) +{ + int kernel_size = imGaussianStdDev2KernelSize(stddev); + + imImage* kernel = imImageCreate(kernel_size, kernel_size, IM_GRAY, IM_FLOAT); + if (!kernel) + return 0; + + imImageSetAttribute(kernel, "Description", IM_BYTE, -1, (void*)"Unsharp"); + imProcessRenderGaussian(kernel, stddev); + + int ret = imProcessConvolveSep(src_image, dst_image, kernel); + doSharp(src_image, dst_image, amount, threshold, 1); + + imImageDestroy(kernel); + + return ret; +} + +int imProcessSharp(const imImage* src_image, imImage* dst_image, float amount, float threshold) +{ + imImage* kernel = imKernelLaplacian8(); + if (!kernel) + return 0; + + int ret = imProcessConvolve(src_image, dst_image, kernel); + doSharp(src_image, dst_image, amount, threshold, 0); + + imImageDestroy(kernel); + + return ret; +} + +static int iProcessCheckKernelType(const imImage* kernel) +{ + if (kernel->data_type == IM_INT) + { + int* kernel_data = (int*)kernel->data[0]; + for (int i = 0; i < kernel->count; i++) + { + if (kernel_data[i] < 0) /* if there are negative values, assume kernel is an edge detector */ + return 0; + } + } + else if (kernel->data_type == IM_FLOAT) + { + float* kernel_data = (float*)kernel->data[0]; + for (int i = 0; i < kernel->count; i++) + { + if (kernel_data[i] < 0) /* if there are negative values, assume kernel is an edge detector */ + return 0; + } + } + return 1; /* default is kernel is a smooth filter */ +} + +int imProcessSharpKernel(const imImage* src_image, const imImage* kernel, imImage* dst_image, float amount, float threshold) +{ + int ret = imProcessConvolve(src_image, dst_image, kernel); + doSharp(src_image, dst_image, amount, threshold, iProcessCheckKernelType(kernel)); + return ret; +} + |