@@ -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 | |||
@@ -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 \ | |||
@@ -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]) | |||
{ | |||
@@ -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 */ | |||
@@ -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 */ | |||
@@ -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) | |||
{ | |||
@@ -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 */ | |||
@@ -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; | |||
} | |||
@@ -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 */ | |||
@@ -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; | |||
@@ -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" /> | |||
@@ -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> | |||