From c33c45904b03ea2297435df0a2ab61971c806aa9 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Sun, 22 Jun 2014 09:20:43 +0000 Subject: [PATCH] image: brightness, contrast, threshold, invert, dilate, erode, sharpen. --- TODO | 4 - src/Makefile.am | 4 +- src/image/dither/ostromoukhov.cpp | 2 +- src/image/filter/autocontrast.cpp | 75 ------ src/image/filter/color.cpp | 383 +++++++++++------------------- src/image/filter/convolution.cpp | 16 ++ src/image/filter/dilate.cpp | 252 +++++++++----------- src/image/filter/sharpen.cpp | 128 ---------- src/image/tiles.cpp | 111 --------- src/lol/image/image.h | 10 +- src/lolcore.vcxproj | 3 +- src/lolcore.vcxproj.filters | 5 +- 12 files changed, 290 insertions(+), 703 deletions(-) delete mode 100644 src/image/filter/autocontrast.cpp delete mode 100644 src/image/filter/sharpen.cpp delete mode 100644 src/image/tiles.cpp diff --git a/TODO b/TODO index 75a0b8b4..f2d45bb4 100644 --- a/TODO +++ b/TODO @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 3f76fba5..1b907ff8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/image/dither/ostromoukhov.cpp b/src/image/dither/ostromoukhov.cpp index 970dfec5..4a3c8652 100644 --- a/src/image/dither/ostromoukhov.cpp +++ b/src/image/dither/ostromoukhov.cpp @@ -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]) { diff --git a/src/image/filter/autocontrast.cpp b/src/image/filter/autocontrast.cpp deleted file mode 100644 index e2fc3eac..00000000 --- a/src/image/filter/autocontrast.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// Lol Engine -// -// Copyright: (c) 2004-2014 Sam Hocevar -// 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(); - 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(); - 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 */ - diff --git a/src/image/filter/color.cpp b/src/image/filter/color.cpp index 989c21d4..60c23452 100644 --- a/src/image/filter/color.cpp +++ b/src/image/filter/color.cpp @@ -1,288 +1,191 @@ -/* - * libpipi Pathetic image processing interface library - * Copyright (c) 2004-2008 Sam Hocevar - * 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 +// 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 -#include -#include -#include - -#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(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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(); + for (int n = 0; n < count; ++n) + pixels[n] = 1.f - pixels[n]; + ret.Unlock(pixels); + } + else + { + vec4 *pixels = ret.Lock(); + 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(); + 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(); + 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 */ + diff --git a/src/image/filter/convolution.cpp b/src/image/filter/convolution.cpp index 1718ae02..2ef0b3ef 100644 --- a/src/image/filter/convolution.cpp +++ b/src/image/filter/convolution.cpp @@ -83,6 +83,22 @@ Image Image::Convolution(Array2D const &kernel) } } +Image Image::Sharpen(Array2D const &kernel) +{ + ivec2 ksize = kernel.GetSize(); + Array2D 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 static Image NonSepConv(Image &src, Array2D const &kernel) { diff --git a/src/image/filter/dilate.cpp b/src/image/filter/dilate.cpp index 9cd04e8a..64447551 100644 --- a/src/image/filter/dilate.cpp +++ b/src/image/filter/dilate.cpp @@ -1,170 +1,144 @@ -/* - * libpipi Pathetic image processing interface library - * Copyright (c) 2004-2008 Sam Hocevar - * 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 +// 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 -#include -#include -#include - -#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(); + float *dstp = ret.Lock(); + + 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(); + vec4 *dstp = ret.Lock(); + + 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(); + float *dstp = ret.Lock(); + + 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(); + vec4 *dstp = ret.Lock(); + + 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 */ + diff --git a/src/image/filter/sharpen.cpp b/src/image/filter/sharpen.cpp deleted file mode 100644 index 65184498..00000000 --- a/src/image/filter/sharpen.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * libpipi Pathetic image processing interface library - * Copyright (c) 2004-2008 Sam Hocevar - * 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 -#include -#include -#include -#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; -} - diff --git a/src/image/tiles.cpp b/src/image/tiles.cpp deleted file mode 100644 index 24eea793..00000000 --- a/src/image/tiles.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * libpipi Pathetic image processing interface library - * Copyright (c) 2004-2008 Sam Hocevar - * 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 -#include -#include - -#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 */ - diff --git a/src/lol/image/image.h b/src/lol/image/image.h index abab29cc..0af48fba 100644 --- a/src/lol/image/image.h +++ b/src/lol/image/image.h @@ -104,12 +104,20 @@ public: /* Image processing */ Image AutoContrast() const; + Image Brightness(float val) const; + Image Contrast(float val) const; Image Convolution(Array2D const &kernel); Image Crop(ibox2 box) const; + Image Dilate(); + Image Erode(); + Image Invert() const; Image Median(ivec2 radii) const; Image Median(Array2D const &kernel) const; - Image YUVToRGB() const; + Image Sharpen(Array2D const &kernel); + Image Threshold(float val) const; + Image Threshold(vec3 val) const; Image RGBToYUV() const; + Image YUVToRGB() const; /* Dithering */ Image DitherRandom() const; diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index a700e767..d20b7c35 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -149,8 +149,9 @@ - + + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index 9d199931..33f861b3 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -364,12 +364,15 @@ sys - + image\filter image\filter + + image\filter + image\filter