Browse Source

image: brightness, contrast, threshold, invert, dilate, erode, sharpen.

undefined
Sam Hocevar 10 years ago
parent
commit
c33c45904b
12 changed files with 290 additions and 703 deletions
  1. +0
    -4
      TODO
  2. +2
    -2
      src/Makefile.am
  3. +1
    -1
      src/image/dither/ostromoukhov.cpp
  4. +0
    -75
      src/image/filter/autocontrast.cpp
  5. +143
    -240
      src/image/filter/color.cpp
  6. +16
    -0
      src/image/filter/convolution.cpp
  7. +113
    -139
      src/image/filter/dilate.cpp
  8. +0
    -128
      src/image/filter/sharpen.cpp
  9. +0
    -111
      src/image/tiles.cpp
  10. +9
    -1
      src/lol/image/image.h
  11. +2
    -1
      src/lolcore.vcxproj
  12. +4
    -1
      src/lolcore.vcxproj.filters

+ 0
- 4
TODO View File

@@ -34,10 +34,7 @@ Image:
· context.cpp
· dither/dbs.cpp
· filter/blur.cpp
· filter/color.cpp
· filter/dilate.cpp
· filter/rotate.cpp
· filter/sharpen.cpp
· filter/transform.cpp
· filter/wave.cpp
· paint/bezier.cpp
@@ -52,5 +49,4 @@ Image:
· resample/bicubic.cpp
· resample/bresenham.cpp
· sequence.cpp
· tiles.cpp


+ 2
- 2
src/Makefile.am View File

@@ -119,8 +119,8 @@ liblolcore_sources = \
image/color/cie1931.cpp image/color/color.cpp \
image/dither/random.cpp image/dither/ediff.cpp \
image/dither/ostromoukhov.cpp image/dither/ordered.cpp \
image/filter/autocontrast.cpp image/filter/convolution.cpp \
image/filter/median.cpp image/filter/yuv.cpp \
image/filter/convolution.cpp image/filter/color.cpp \
image/filter/dilate.cpp image/filter/median.cpp image/filter/yuv.cpp \
image/render/noise.cpp \
\
loldebug.h \


+ 1
- 1
src/image/dither/ostromoukhov.cpp View File

@@ -57,7 +57,7 @@ static inline vec3 GetDiffusion(float v)
if (v < 0.f)
v = 0.f;

for (int i = 1; i < sizeof(table) / sizeof(table[0]); ++i)
for (unsigned int i = 1; i < sizeof(table) / sizeof(table[0]); ++i)
{
if (v <= table[i][0])
{


+ 0
- 75
src/image/filter/autocontrast.cpp View File

@@ -1,75 +0,0 @@
//
// Lol Engine
//
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
//

#if defined HAVE_CONFIG_H
# include "config.h"
#endif

#include "core.h"

/*
* Autocontrast functions
* TODO: the current approach is naive; we should use the histogram in order
* to decide how to change the contrast.
*/

namespace lol
{

Image Image::AutoContrast() const
{
Image ret = *this;

float min_val = 1.f, max_val = 0.f;
int count = GetSize().x * GetSize().y;

if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
{
float *pixels = ret.Lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n)
{
min_val = lol::min(min_val, pixels[n]);
max_val = lol::max(max_val, pixels[n]);
}

float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f;
for (int n = 0; n < count; ++n)
pixels[n] = (pixels[n] - min_val) * t;

ret.Unlock(pixels);
}
else
{
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n)
{
min_val = lol::min(min_val, pixels[n].r);
min_val = lol::min(min_val, pixels[n].g);
min_val = lol::min(min_val, pixels[n].b);
max_val = lol::max(max_val, pixels[n].r);
max_val = lol::max(max_val, pixels[n].g);
max_val = lol::max(max_val, pixels[n].b);
}

float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f;
for (int n = 0; n < count; ++n)
pixels[n] = vec4((pixels[n].r - min_val) * t,
(pixels[n].g - min_val) * t,
(pixels[n].b - min_val) * t,
pixels[n].a);;

ret.Unlock(pixels);
}

return ret;
}

} /* namespace lol */


+ 143
- 240
src/image/filter/color.cpp View File

@@ -1,288 +1,191 @@
/*
* libpipi Pathetic image processing interface library
* Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
//
// Lol Engine
//
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
//

#if defined HAVE_CONFIG_H
# include "config.h"
#endif

#include "core.h"

/*
* color.c: colour manipulation functions
* Colour manipulation functions
*/

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "pipi.h"
#include "pipi-internals.h"

pipi_image_t *pipi_brightness(pipi_image_t *src, double val)
namespace lol
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
int x, y, w, h, gray;

w = src->w;
h = src->h;

gray = (src->last_modified == PIPI_PIXELS_Y_F32);

srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
srcdata = (float *)srcp->pixels;

dst = pipi_new(w, h);
dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
dstdata = (float *)dstp->pixels;
Image Image::Brightness(float val) const
{
Image ret = *this;
int count = GetSize().x * GetSize().y;

if(val >= 0.0)
if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
{
for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(gray)
{
double p = srcdata[y * w + x];
dstdata[y * w + x] = p < 1. - val ? p + val : 1.;
}
else
{
double p;
int d = 4 * (y * w + x);

p = srcdata[d];
dstdata[d] = p < 1. - val ? p + val : 1.;
p = srcdata[d + 1];
dstdata[d + 1] = p < 1. - val ? p + val : 1.;
p = srcdata[d + 2];
dstdata[d + 2] = p < 1. - val ? p + val : 1.;
p = srcdata[d + 3];
dstdata[d + 3] = p;
}
}
}
float *pixels = ret.Lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = lol::clamp(pixels[n] + val, 0.f, 1.f);
ret.Unlock(pixels);
}
else
{
for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(gray)
{
double p = srcdata[y * w + x];
dstdata[y * w + x] = p > -val ? p + val : 0.;
}
else
{
double p;
int d = 4 * (y * w + x);

p = srcdata[d];
dstdata[d] = p > -val ? p + val : 0.;
p = srcdata[d + 1];
dstdata[d + 1] = p > -val ? p + val : 0.;
p = srcdata[d + 2];
dstdata[d + 2] = p > -val ? p + val : 0.;
p = srcdata[d + 3];
dstdata[d + 3] = p;
}
}
}
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = vec4(lol::clamp(pixels[n].rgb + vec3(val), 0.f, 1.f),
pixels[n].a);
ret.Unlock(pixels);
}

return dst;
return ret;
}

pipi_image_t *pipi_contrast(pipi_image_t *src, double val)
Image Image::Contrast(float val) const
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
int x, y, w, h, gray;
Image ret = *this;
int count = GetSize().x * GetSize().y;

w = src->w;
h = src->h;

gray = (src->last_modified == PIPI_PIXELS_Y_F32);

srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
srcdata = (float *)srcp->pixels;

dst = pipi_new(w, h);
dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
dstdata = (float *)dstp->pixels;

if(val >= 0.0)
if (val >= 0.f)
{
if(val > 0.99999)
val = 0.99999;

val = 1. / (1. - val);

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(gray)
{
double p = (srcdata[y * w + x] - 0.5) * val + 0.5;
dstdata[y * w + x] = p < 0. ? 0. : p > 1. ? 1. : p;
}
else
{
double p;
int d = 4 * (y * w + x);
if (val > 0.99999f)
val = 0.99999f;

p = (srcdata[d] - 0.5) * val + 0.5;
dstdata[d] = p < 0. ? 0. : p > 1. ? 1. : p;
p = (srcdata[d + 1] - 0.5) * val + 0.5;
dstdata[d + 1] = p < 0. ? 0. : p > 1. ? 1. : p;
p = (srcdata[d + 2] - 0.5) * val + 0.5;
dstdata[d + 2] = p < 0. ? 0. : p > 1. ? 1. : p;
p = srcdata[d + 3];
dstdata[d + 3] = p;
}
}
}
val = 1.f / (1.f - val);
}
else
{
if(val < -1.)
val = -1.;

val = 1. + val;

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(gray)
{
double p = srcdata[y * w + x];
dstdata[y * w + x] = (p - 0.5) * val + 0.5;
}
else
{
double p;
int d = 4 * (y * w + x);
val = lol::clamp(1.f + val, 0.f, 1.f);
}

p = srcdata[d];
dstdata[d] = (p - 0.5) * val + 0.5;
p = srcdata[d + 1];
dstdata[d + 1] = (p - 0.5) * val + 0.5;
p = srcdata[d + 2];
dstdata[d + 2] = (p - 0.5) * val + 0.5;
p = srcdata[d + 3];
dstdata[d + 3] = p;
}
}
}
if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
{
float add = -0.5f * val + 0.5f;
float *pixels = ret.Lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = lol::clamp(pixels[n] * val + add, 0.f, 1.f);
ret.Unlock(pixels);
}
else
{
vec3 add = vec3(-0.5f * val + 0.5f);
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = vec4(lol::clamp(pixels[n].rgb * val + add, 0.f, 1.f),
pixels[n].a);
ret.Unlock(pixels);
}

return dst;
return ret;
}

pipi_image_t *pipi_invert(pipi_image_t *src)
/*
* TODO: the current approach is naive; we should use the histogram in order
* to decide how to change the contrast.
*/
Image Image::AutoContrast() const
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
int x, y, w, h, gray;

w = src->w;
h = src->h;
Image ret = *this;

gray = (src->last_modified == PIPI_PIXELS_Y_F32);
float min_val = 1.f, max_val = 0.f;
int count = GetSize().x * GetSize().y;

srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
srcdata = (float *)srcp->pixels;
if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
{
float *pixels = ret.Lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n)
{
min_val = lol::min(min_val, pixels[n]);
max_val = lol::max(max_val, pixels[n]);
}

dst = pipi_new(w, h);
dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
dstdata = (float *)dstp->pixels;
float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f;
for (int n = 0; n < count; ++n)
pixels[n] = (pixels[n] - min_val) * t;

for(y = 0; y < h; y++)
ret.Unlock(pixels);
}
else
{
for(x = 0; x < w; x++)
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n)
{
if(gray)
{
dstdata[y * w + x] = 1. - srcdata[y * w + x];
}
else
{
int d = 4 * (y * w + x);

dstdata[d] = 1. - srcdata[d];
dstdata[d + 1] = 1. - srcdata[d + 1];
dstdata[d + 2] = 1. - srcdata[d + 2];
dstdata[d + 3] = 1. - srcdata[d + 3];
}
min_val = lol::min(min_val, pixels[n].r);
min_val = lol::min(min_val, pixels[n].g);
min_val = lol::min(min_val, pixels[n].b);
max_val = lol::max(max_val, pixels[n].r);
max_val = lol::max(max_val, pixels[n].g);
max_val = lol::max(max_val, pixels[n].b);
}

float t = max_val > min_val ? 1.f / (max_val - min_val) : 1.f;
for (int n = 0; n < count; ++n)
pixels[n] = vec4((pixels[n].r - min_val) * t,
(pixels[n].g - min_val) * t,
(pixels[n].b - min_val) * t,
pixels[n].a);;

ret.Unlock(pixels);
}

return dst;
return ret;
}

pipi_image_t *pipi_threshold(pipi_image_t *src, double val)
Image Image::Invert() const
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
int x, y, w, h, gray;

w = src->w;
h = src->h;
Image ret = *this;
int count = GetSize().x * GetSize().y;

gray = (src->last_modified == PIPI_PIXELS_Y_F32);
if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
{
float *pixels = ret.Lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = 1.f - pixels[n];
ret.Unlock(pixels);
}
else
{
vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = vec4(vec3(1.f) -pixels[n].rgb, pixels[n].a);
ret.Unlock(pixels);
}

srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
srcdata = (float *)srcp->pixels;
return ret;
}

dst = pipi_new(w, h);
dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
dstdata = (float *)dstp->pixels;
Image Image::Threshold(float val) const
{
Image ret = *this;
int count = GetSize().x * GetSize().y;

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
if(gray)
{
dstdata[y * w + x] = srcdata[y * w + x] < val ? 0. : 1.;
}
else
{
int d = 4 * (y * w + x);
float *pixels = ret.Lock<PixelFormat::Y_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = pixels[n] > val ? 1.f : 0.f;
ret.Unlock(pixels);

dstdata[d] = srcdata[d] < val ? 0. : 1.;
dstdata[d + 1] = srcdata[d + 1] < val ? 0. : 1.;
dstdata[d + 2] = srcdata[d + 2] < val ? 0. : 1.;
dstdata[d + 3] = srcdata[d + 3] < val ? 0. : 1.;
}
}
}
return ret;
}

return dst;
Image Image::Threshold(vec3 val) const
{
Image ret = *this;
int count = GetSize().x * GetSize().y;

vec4 *pixels = ret.Lock<PixelFormat::RGBA_F32>();
for (int n = 0; n < count; ++n)
pixels[n] = vec4(pixels[n].r > val.r ? 1.f : 0.f,
pixels[n].g > val.g ? 1.f : 0.f,
pixels[n].b > val.b ? 1.f : 0.f,
pixels[n].a);
ret.Unlock(pixels);

return ret;
}

} /* namespace lol */


+ 16
- 0
src/image/filter/convolution.cpp View File

@@ -83,6 +83,22 @@ Image Image::Convolution(Array2D<float> const &kernel)
}
}

Image Image::Sharpen(Array2D<float> const &kernel)
{
ivec2 ksize = kernel.GetSize();
Array2D<float> newkernel(ksize);

for (int dy = 0; dy < ksize.y; ++dy)
for (int dx = 0; dx < ksize.x; ++dx)
{
newkernel[dx][dy] = - kernel[dx][dy];
if (dx == ksize.x / 2 && dy == ksize.y / 2)
newkernel[dx][dy] += 2.f;
}

return Convolution(newkernel);
}

template<PixelFormat FORMAT, int WRAP_X, int WRAP_Y>
static Image NonSepConv(Image &src, Array2D<float> const &kernel)
{


+ 113
- 139
src/image/filter/dilate.cpp View File

@@ -1,170 +1,144 @@
/*
* libpipi Pathetic image processing interface library
* Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
//
// Lol Engine
//
// Copyright: (c) 2004-2014 Sam Hocevar <sam@hocevar.net>
// This program is free software; you can redistribute it and/or
// modify it under the terms of the Do What The Fuck You Want To
// Public License, Version 2, as published by Sam Hocevar. See
// http://www.wtfpl.net/ for more details.
//

#if defined HAVE_CONFIG_H
# include "config.h"
#endif

#include "core.h"

/*
* dilate.c: dilate and erode functions
* Dilate and erode functions
*/

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "pipi.h"
#include "pipi-internals.h"

/* FIXME: these functions are almost the same, try to merge them
* somewhat efficiently. */
/* TODO: - dilate by k (Manhattan distance)
* - dilate by r (euclidian distance, with non-integer r) */
pipi_image_t *pipi_dilate(pipi_image_t *src)
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
int x, y, w, h, i, gray;

w = src->w;
h = src->h;

gray = (src->last_modified == PIPI_PIXELS_Y_F32);

srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
srcdata = (float *)srcp->pixels;
namespace lol
{

dst = pipi_new(w, h);
dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
dstdata = (float *)dstp->pixels;
Image Image::Dilate()
{
ivec2 const size = GetSize();
Image ret(size);

for(y = 0; y < h; y++)
if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
{
for(x = 0; x < w; x++)
{
double t;
int x2, y2, x3, y3;

y2 = y - 1;
if(y2 < 0) y2 = h - 1;
y3 = y + 1;
if(y3 >= h) y3 = 0;

x2 = x - 1;
if(x2 < 0) x2 = w - 1;
x3 = x + 1;
if(x3 >= w) x3 = 0;

if(gray)
float const *srcp = Lock<PixelFormat::Y_F32>();
float *dstp = ret.Lock<PixelFormat::Y_F32>();

for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
{
t = srcdata[y * w + x];
if(srcdata[y2 * w + x] > t) t = srcdata[y2 * w + x];
if(srcdata[y3 * w + x] > t) t = srcdata[y3 * w + x];
if(srcdata[y * w + x2] > t) t = srcdata[y * w + x2];
if(srcdata[y * w + x3] > t) t = srcdata[y * w + x3];
dstdata[y * w + x] = t;
int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);

float t = srcp[y * size.x + x];
t = lol::max(t, srcp[y * size.x + x2]);
t = lol::max(t, srcp[y * size.x + x3]);
t = lol::max(t, srcp[y2 * size.x + x]);
t = lol::max(t, srcp[y3 * size.x + x]);
dstp[y * size.x + x] = t;
}
else

Unlock(srcp);
ret.Unlock(dstp);
}
else
{
vec4 const *srcp = Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>();

for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
{
for(i = 0; i < 4; i++)
{
t = srcdata[4 * (y * w + x) + i];
if(srcdata[4 * (y2 * w + x) + i] > t)
t = srcdata[4 * (y2 * w + x) + i];
if(srcdata[4 * (y3 * w + x) + i] > t)
t = srcdata[4 * (y3 * w + x) + i];
if(srcdata[4 * (y * w + x2) + i] > t)
t = srcdata[4 * (y * w + x2) + i];
if(srcdata[4 * (y * w + x3) + i] > t)
t = srcdata[4 * (y * w + x3) + i];
dstdata[4 * (y * w + x) + i] = t;
}
int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);

vec3 t = srcp[y * size.x + x].rgb;
t = lol::max(t, srcp[y * size.x + x2].rgb);
t = lol::max(t, srcp[y * size.x + x3].rgb);
t = lol::max(t, srcp[y2 * size.x + x].rgb);
t = lol::max(t, srcp[y3 * size.x + x].rgb);
dstp[y * size.x + x] = vec4(t, srcp[y * size.x + x].a);
}
}

Unlock(srcp);
ret.Unlock(dstp);
}

return dst;
return ret;
}

pipi_image_t *pipi_erode(pipi_image_t *src)
Image Image::Erode()
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
int x, y, w, h, i, gray;

w = src->w;
h = src->h;

gray = (src->last_modified == PIPI_PIXELS_Y_F32);
ivec2 const size = GetSize();
Image ret(size);

srcp = gray ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
srcdata = (float *)srcp->pixels;

dst = pipi_new(w, h);
dstp = gray ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32)
: pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
dstdata = (float *)dstp->pixels;

for(y = 0; y < h; y++)
if (GetFormat() == PixelFormat::Y_8 || GetFormat() == PixelFormat::Y_F32)
{
for(x = 0; x < w; x++)
{
double t;
int x2, y2, x3, y3;

y2 = y - 1;
if(y2 < 0) y2 = h - 1;
y3 = y + 1;
if(y3 >= h) y3 = 0;

x2 = x - 1;
if(x2 < 0) x2 = w - 1;
x3 = x + 1;
if(x3 >= w) x3 = 0;

if(gray)
float const *srcp = Lock<PixelFormat::Y_F32>();
float *dstp = ret.Lock<PixelFormat::Y_F32>();

for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
{
t = srcdata[y * w + x];
if(srcdata[y2 * w + x] < t) t = srcdata[y2 * w + x];
if(srcdata[y3 * w + x] < t) t = srcdata[y3 * w + x];
if(srcdata[y * w + x2] < t) t = srcdata[y * w + x2];
if(srcdata[y * w + x3] < t) t = srcdata[y * w + x3];
dstdata[y * w + x] = t;
int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);

float t = srcp[y * size.x + x];
t = lol::max(t, srcp[y * size.x + x2]);
t = lol::max(t, srcp[y * size.x + x3]);
t = lol::max(t, srcp[y2 * size.x + x]);
t = lol::max(t, srcp[y3 * size.x + x]);
dstp[y * size.x + x] = t;
}
else

Unlock(srcp);
ret.Unlock(dstp);
}
else
{
vec4 const *srcp = Lock<PixelFormat::RGBA_F32>();
vec4 *dstp = ret.Lock<PixelFormat::RGBA_F32>();

for (int y = 0; y < size.y; ++y)
for (int x = 0; x < size.x; ++x)
{
for(i = 0; i < 4; i++)
{
t = srcdata[4 * (y * w + x) + i];
if(srcdata[4 * (y2 * w + x) + i] < t)
t = srcdata[4 * (y2 * w + x) + i];
if(srcdata[4 * (y3 * w + x) + i] < t)
t = srcdata[4 * (y3 * w + x) + i];
if(srcdata[4 * (y * w + x2) + i] < t)
t = srcdata[4 * (y * w + x2) + i];
if(srcdata[4 * (y * w + x3) + i] < t)
t = srcdata[4 * (y * w + x3) + i];
dstdata[4 * (y * w + x) + i] = t;
}
int y2 = lol::max(y - 1, 0);
int x2 = lol::max(x - 1, 0);
int y3 = lol::min(y + 1, size.y - 1);
int x3 = lol::min(x + 1, size.x - 1);

vec3 t = srcp[y * size.x + x].rgb;
t = lol::min(t, srcp[y * size.x + x2].rgb);
t = lol::min(t, srcp[y * size.x + x3].rgb);
t = lol::min(t, srcp[y2 * size.x + x].rgb);
t = lol::min(t, srcp[y3 * size.x + x].rgb);
dstp[y * size.x + x] = vec4(t, srcp[y * size.x + x].a);
}
}

Unlock(srcp);
ret.Unlock(dstp);
}

return dst;
return ret;
}

} /* namespace lol */


+ 0
- 128
src/image/filter/sharpen.cpp View File

@@ -1,128 +0,0 @@
/*
* libpipi Pathetic image processing interface library
* Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

/*
* sharpen.c: sharpen functions
*/

#include "config.h"
#include "common.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif

#include "pipi.h"
#include "pipi-internals.h"

pipi_image_t *pipi_gaussian_sharpen(pipi_image_t *src, float radius)
{
pipi_image_t *dst;
pipi_pixels_t *srcp, *dstp;
float *srcdata, *dstdata;
double *kernel, *buffer;
double K, L;
int x, y, i, w, h, kr, kw;

w = src->w;
h = src->h;

srcp = pipi_get_pixels(src, PIPI_PIXELS_RGBA_F);
srcdata = (float *)srcp->pixels;

dst = pipi_new(w, h);
dstp = pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F);
dstdata = (float *)dstp->pixels;

kr = (int)(3. * radius + 0.99999);
kw = 2 * kr + 1;
K = 1. / (sqrt(2. * M_PI) * radius);
L = -1. / (2. * radius * radius);

kernel = malloc(kw * sizeof(double));
for(i = -kr; i <= kr; i++)
kernel[i + kr] = exp(L * i * i) * K;

buffer = malloc(w * h * 4 * sizeof(double));

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
double R = 0., G = 0., B = 0., t = 0.;
int x2, off = 4 * (y * w + x);

for(i = -kr; i <= kr; i++)
{
double f = kernel[i + kr];

x2 = x + i;
if(x2 < 0) x2 = 0;
else if(x2 >= w) x2 = w - 1;

R += f * srcdata[(y * w + x2) * 4];
G += f * srcdata[(y * w + x2) * 4 + 1];
B += f * srcdata[(y * w + x2) * 4 + 2];
t += f;
}

buffer[off] = R / t;
buffer[off + 1] = G / t;
buffer[off + 2] = B / t;
}
}

for(y = 0; y < h; y++)
{
for(x = 0; x < w; x++)
{
double R = 0., G = 0., B = 0., t = 0.;
int y2, off = 4 * (y * w + x);

for(i = -kr; i <= kr; i++)
{
double f = kernel[i + kr];

y2 = y + i;
if(y2 < 0) y2 = 0;
else if(y2 >= h) y2 = h - 1;

R += f * buffer[(y2 * w + x) * 4];
G += f * buffer[(y2 * w + x) * 4 + 1];
B += f * buffer[(y2 * w + x) * 4 + 2];
t += f;
}

dstdata[off] = 2 * srcdata[off] - R / t;
if(dstdata[off] < 0.0) dstdata[off] = 0.0;
if(dstdata[off] > 1.0) dstdata[off] = 1.0;
dstdata[off + 1] = 2 * srcdata[off + 1 ] - G / t;
if(dstdata[off + 1] < 0.0) dstdata[off + 1] = 0.0;
if(dstdata[off + 1] > 1.0) dstdata[off + 1] = 1.0;
dstdata[off + 2] = 2 * srcdata[off + 2 ] - B / t;
if(dstdata[off + 2] < 0.0) dstdata[off + 2] = 0.0;
if(dstdata[off + 2] > 1.0) dstdata[off + 2] = 1.0;
}
}

free(buffer);
free(kernel);

return dst;
}


+ 0
- 111
src/image/tiles.cpp View File

@@ -1,111 +0,0 @@
/*
* libpipi Pathetic image processing interface library
* Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
* All Rights Reserved
*
* $Id$
*
* This library is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/

/*
* tiles.c: the tiles system
*/

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "pipi.h"
#include "pipi-internals.h"

#ifdef USE_TILES
pipi_tile_t *pipi_get_tile(pipi_image_t *img, int x, int y, int zoom,
pipi_format_t fmt, int plane)
{
pipi_tile_t * ret;
int i;

/* If the tile already exists, return it. */
for(i = 0; i < img->ntiles; i++)
{
if(img->tiles[i]->x == x && img->tiles[i]->y == y
&& img->tiles[i]->fmt == fmt
&& img->tiles[i]->zoom == zoom
&& img->tiles[i]->plane == plane)
{
img->tiles[i]->refcount++;
return img->tiles[i];
}
}

/* Create a tile. When the image provides a tile creation function,
* we should use it. */
ret = pipi_create_tile(fmt, plane);
ret->x = x;
ret->y = y;
ret->refcount = 1;

/* Insert tile and return it. */
img->ntiles++;
img->tiles = realloc(img->tiles, img->ntiles * sizeof(pipi_tile_t *));
img->tiles[img->ntiles - 1] = ret;

return ret;
}

void pipi_release_tile(pipi_image_t *img, pipi_tile_t *tile)
{
int i;

for(i = 0; i < img->ntiles; i++)
{
if(img->tiles[i] == tile)
{
img->tiles[i]->refcount--;
if(img->tiles[i]->refcount <= 0)
{
free(img->tiles[i]);
img->tiles[i] = img->tiles[img->ntiles - 1];
img->ntiles--;
}
return;
}
}
}

pipi_tile_t *pipi_create_tile(pipi_format_t fmt, int plane)
{
pipi_tile_t * ret;
size_t bytes;

switch(fmt)
{
case PIPI_PIXELS_RGBA_U8:
case PIPI_PIXELS_BGR_U8:
bytes = sizeof(uint8_t) * TILE_SIZE * TILE_SIZE;
break;
case PIPI_PIXELS_RGBA_F32:
case PIPI_PIXELS_Y_F32:
bytes = sizeof(float) * TILE_SIZE * TILE_SIZE;
break;
default:
bytes = 0;
break;
}

ret = malloc(sizeof(pipi_tile_t) + bytes);
ret->fmt = fmt;
ret->plane = plane;
ret->data.u8 = ret->align.u8;

return ret;
}
#endif /* USE_TILES */


+ 9
- 1
src/lol/image/image.h View File

@@ -104,12 +104,20 @@ public:

/* Image processing */
Image AutoContrast() const;
Image Brightness(float val) const;
Image Contrast(float val) const;
Image Convolution(Array2D<float> const &kernel);
Image Crop(ibox2 box) const;
Image Dilate();
Image Erode();
Image Invert() const;
Image Median(ivec2 radii) const;
Image Median(Array2D<float> const &kernel) const;
Image YUVToRGB() const;
Image Sharpen(Array2D<float> const &kernel);
Image Threshold(float val) const;
Image Threshold(vec3 val) const;
Image RGBToYUV() const;
Image YUVToRGB() const;

/* Dithering */
Image DitherRandom() const;


+ 2
- 1
src/lolcore.vcxproj View File

@@ -149,8 +149,9 @@
<ClCompile Include="image\codec\zed-palette-image.cpp" />
<ClCompile Include="image\color\cie1931.cpp" />
<ClCompile Include="image\color\color.cpp" />
<ClCompile Include="image\filter\autocontrast.cpp" />
<ClCompile Include="image\filter\color.cpp" />
<ClCompile Include="image\filter\convolution.cpp" />
<ClCompile Include="image\filter\dilate.cpp" />
<ClCompile Include="image\filter\median.cpp" />
<ClCompile Include="image\filter\yuv.cpp" />
<ClCompile Include="image\dither\ediff.cpp" />


+ 4
- 1
src/lolcore.vcxproj.filters View File

@@ -364,12 +364,15 @@
<ClCompile Include="sys\thread.cpp">
<Filter>sys</Filter>
</ClCompile>
<ClCompile Include="image\filter\autocontrast.cpp">
<ClCompile Include="image\filter\color.cpp">
<Filter>image\filter</Filter>
</ClCompile>
<ClCompile Include="image\filter\convolution.cpp">
<Filter>image\filter</Filter>
</ClCompile>
<ClCompile Include="image\filter\dilate.cpp">
<Filter>image\filter</Filter>
</ClCompile>
<ClCompile Include="image\filter\median.cpp">
<Filter>image\filter</Filter>
</ClCompile>


Loading…
Cancel
Save