summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorscuri <scuri>2009-10-01 02:56:38 +0000
committerscuri <scuri>2009-10-01 02:56:38 +0000
commit62783aee16f96fe5e513fb230b8efddaa02981df (patch)
tree9dc512b0c758025c5cddba9709420f1bf9058675
parent9a5e93213e08601a58725f44035ac622fb68e849 (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.html11
-rw-r--r--include/im_complex.h20
-rw-r--r--include/im_math_op.h15
-rw-r--r--include/im_process_loc.h29
-rw-r--r--include/im_process_pon.h20
-rw-r--r--src/im_process.def3
-rw-r--r--src/lua5/im_process.lua3
-rw-r--r--src/lua5/imlua_process.c56
-rw-r--r--src/process/im_arithmetic_bin.cpp98
-rw-r--r--src/process/im_arithmetic_un.cpp64
-rw-r--r--src/process/im_convolve.cpp190
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;
+}
+